<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<?xml-stylesheet type="text/xsl" href="/rss.xsl"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Andrey Listopadov</title>
    <link>https://andreyor.st/tags/fennel/</link>
    <image>
      <title>Andrey Listopadov</title>
      <link>https://andreyor.st/tags/fennel/</link>
      <url>https://andreyor.st/tags/fennel/favicon-64.png</url>
    </image>
    <description>Posts tagged 'fennel' by Andrey Listopadov</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en-us</language>
    <copyright>Andrey Listopadov 2020-2026 - This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License</copyright>
    <lastBuildDate>Mon, 29 Jun 2026 00:29:00 +0300</lastBuildDate>
    <atom:link href="https://andreyor.st/tags/fennel/feed.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Clojure on Fennel part four: Parsing (again)</title>
      <link>https://andreyor.st/posts/2026-06-29-clojure-on-fennel-part-four-parsing-again/</link>
      <guid>https://andreyor.st/posts/2026-06-29-clojure-on-fennel-part-four-parsing-again/</guid>
      <description>&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://andreyor.st/posts/2026-04-07-clojure-on-fennel-part-one-persistent-data-structures/&#34;&gt;part one: persistent data structures&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://andreyor.st/posts/2026-04-15-clojure-on-fennel-part-two-immutablefnl-optimizations/&#34;&gt;part two: immutable.fnl optimizations&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://andreyor.st/posts/2026-04-27-clojure-on-fennel-part-three-parsing/&#34;&gt;part three: parsing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;part four: parsing (again)&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;Other than that, the parsing is complete, and we can look at the compiler part of the ClojureFnl project.
But that&amp;rsquo;s gonna be in the next post.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Sike!&lt;/p&gt;
&lt;p&gt;Wasn&amp;rsquo;t my intention to fake out like this again, but while working on the compiler, I had an important realization that led me to redesign the parser completely.
And it&amp;rsquo;s a bit of a shame, because I already had a decent part of the compiler working, being able to run the REPL and do various cool things with it.
But, better sooner than later, I guess.&lt;/p&gt;
&lt;p&gt;I had a good amount of the post about the compiler already written too, but now I&amp;rsquo;ll have to discard all of that.
So instead, I decided to talk about the new parser by explaining why the old one failed me.
And to do so, I&amp;rsquo;ll give you a brief look on how the compiler currently works with parsed code.&lt;/p&gt;
&lt;h2 id=&#34;old-parser-and-compiler&#34;&gt;Old parser and compiler&lt;/h2&gt;
&lt;p&gt;So, in the previous post, we&amp;rsquo;ve reached a point where the parser can read code into a tagged tree.
I spent a fair amount of time discussing how I wanted this specifically, and now it feels like I&amp;rsquo;m backpedalling, but tagged tree is not the way forward.
Here&amp;rsquo;s the idea.&lt;/p&gt;
&lt;p&gt;Currently, we&amp;rsquo;re reading this expression &lt;code&gt;(+ 1 2)&lt;/code&gt; into:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:code&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:list&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:symbol&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;+&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:whitespace&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:number&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;1&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:whitespace&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:number&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;2&amp;#34;&lt;/span&gt;]]]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The compiler then walks this tree, taking the first value of each node to decide what to do.
First, it sees &lt;code&gt;:code&lt;/code&gt; - that&amp;rsquo;s just an entry point, containing multiple top-level expressions.
Next, it sees &lt;code&gt;:list&lt;/code&gt; and dispatches to a function dedicated to compiling lists.&lt;/p&gt;
&lt;p&gt;This function checks the first element of the list, sees that it is a &lt;code&gt;:symbol&lt;/code&gt;, and checks whether this symbol is somehow special.
While &lt;code&gt;+&lt;/code&gt; doesn&amp;rsquo;t look that special, it is to the compiler, because Clojure&amp;rsquo;s &lt;code&gt;+&lt;/code&gt; and Fennel&amp;rsquo;s &lt;code&gt;+&lt;/code&gt; are not the same thing.
In Clojure, &lt;code&gt;+&lt;/code&gt; is a function, in Fennel, it is a special.&lt;/p&gt;
&lt;p&gt;So the compiler replaces &lt;code&gt;+&lt;/code&gt; with &lt;code&gt;clojure_core_ns.add&lt;/code&gt;, and then proceeds over the rest of the forms in the list, recursively calling itself over each.
In the end, we get this, written into a string builder:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure_core_ns.add&lt;/span&gt; 1 2)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This is a somewhat simplified explanation, because I&amp;rsquo;m omitting scope resolution, symbol shadowing, and other such things that the compiler currently tracks.
For actual specials, like Clojure&amp;rsquo;s &lt;code&gt;let*&lt;/code&gt;, the story is a bit different too.
The compiler has a dedicated &lt;code&gt;compile-special&lt;/code&gt; function for all Clojure specials provided by &lt;code&gt;cljlib&lt;/code&gt; as Fennel macros.
And that&amp;rsquo;s where things started to go haywire.&lt;/p&gt;
&lt;p&gt;Look at this code:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;def &lt;/span&gt;^&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:private&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;foo&lt;/span&gt; 42)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It&amp;rsquo;s read like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:list&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:symbol&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;def&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:whitespace&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:metadata&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:metadata-entry&lt;/span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:keyword&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;:private&amp;#34;&lt;/span&gt;]]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:whitespace&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:symbol&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;foo&amp;#34;&lt;/span&gt;]]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:whitespace&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:number&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;42&amp;#34;&lt;/span&gt;]]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Here&amp;rsquo;s a problem - the parser reads metadata &lt;code&gt;^:private&lt;/code&gt;, and metadata in Clojure is attached to symbols, so the grammar I use reads the next value after the metadata and wraps it into a single node:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:metadata&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:metadata-entry&lt;/span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:keyword&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;:private&amp;#34;&lt;/span&gt;]]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:whitespace&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:symbol&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;foo&amp;#34;&lt;/span&gt;]]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The compiler, while compiling this list, sees &lt;code&gt;def&lt;/code&gt; as the first symbol and enters &lt;code&gt;compile-special.def&lt;/code&gt;.
But &lt;code&gt;def&lt;/code&gt; expects a symbol to bind the value to, while here we have a different node type, called &lt;code&gt;:metadata&lt;/code&gt;.
So my compiler had to account for all cases where metadata can appear - and it wasn&amp;rsquo;t easy to do.&lt;/p&gt;
&lt;p&gt;I tried to side-step this by always expecting metadata, because it can appear almost anywhere, and discarding it, because Fennel&amp;rsquo;s concept of metadata is a bit different.
In which I mostly succeeded.
But this wasn&amp;rsquo;t the only problematic thing to support.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s another example, now from &lt;a href=&#34;https://github.com/borkdude/edamame/blob/cd392b2246acced63099ae605f7580942a9cd462/src/edamame/impl/parser.cljc#L92&#34; target=&#34;_blank&#34;&gt;Edamame&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn- &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-token&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Read in a single logical token from the reader&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ^&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;String&lt;/span&gt; [#&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;?&lt;/span&gt;(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:clj&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:cljs&lt;/span&gt; ^&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;not-native&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:cljr&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_kind&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;initch&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;loop &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sb&lt;/span&gt; #&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;?&lt;/span&gt;(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:clj&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;StringBuilder.&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:cljs&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;StringBuffer.&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:cljr&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;StringBuilder.&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ch&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;initch&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;whitespace?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ch&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;macro-terminating?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ch&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;nil? &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ch&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;do &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;when &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ch&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;r/unread&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ch&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;str &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sb&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;recur&lt;/span&gt; #&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;?&lt;/span&gt;(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:clj&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;.append&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sb&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ch&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:cljs&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;.append&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sb&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ch&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:cljr&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;.Append&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sb&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;str &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ch&lt;/span&gt;))) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;r/read-char&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It reads into this tagged tree:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:list&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:symbol&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;defn-&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:whitespace&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:symbol&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;read-token&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:whitespace&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\n  &amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:string&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\&amp;#34;Read in a single logical token from the reader\&amp;#34;&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:whitespace&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\n  &amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:metadata&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:metadata-entry&lt;/span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:symbol&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;String&amp;#34;&lt;/span&gt;]]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:whitespace&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:vector&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:conditional&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:list&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:keyword&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;:clj&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:whitespace&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:symbol&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;rdr&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:whitespace&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:keyword&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;:cljs&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:whitespace&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:metadata&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:metadata-entry&lt;/span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:symbol&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;not-native&amp;#34;&lt;/span&gt;]]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:whitespace&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:symbol&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;rdr&amp;#34;&lt;/span&gt;]]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:whitespace&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:keyword&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;:cljr&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:whitespace&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:symbol&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;rdr&amp;#34;&lt;/span&gt;]]]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:whitespace&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:symbol&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;_kind&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:whitespace&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:symbol&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;initch&amp;#34;&lt;/span&gt;]]]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:whitespace&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\n  &amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:list&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:symbol&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;loop&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:whitespace&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:vector&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:symbol&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;sb&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:whitespace&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:conditional&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:list&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:keyword&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;:clj&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:whitespace&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:list&lt;/span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:symbol&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;StringBuilder.&amp;#34;&lt;/span&gt;]]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:whitespace&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\n               &amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:keyword&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;:cljs&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:whitespace&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:list&lt;/span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:symbol&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;StringBuffer.&amp;#34;&lt;/span&gt;]]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:whitespace&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\n               &amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:keyword&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;:cljr&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:whitespace&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:list&lt;/span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:symbol&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;StringBuilder.&amp;#34;&lt;/span&gt;]]]]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:whitespace&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\n         &amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:symbol&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;ch&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:whitespace&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:symbol&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;initch&amp;#34;&lt;/span&gt;]]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:whitespace&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\n    &amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:list&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:symbol&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;if&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:whitespace&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:list&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:symbol&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;or&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:whitespace&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:list&lt;/span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:symbol&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;whitespace?&amp;#34;&lt;/span&gt;] [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:whitespace&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;] [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:symbol&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;ch&amp;#34;&lt;/span&gt;]]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:whitespace&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\n            &amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:list&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:symbol&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;macro-terminating?&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:whitespace&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:symbol&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;ch&amp;#34;&lt;/span&gt;]]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:whitespace&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\n            &amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:list&lt;/span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:symbol&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;nil?&amp;#34;&lt;/span&gt;] [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:whitespace&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;] [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:symbol&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;ch&amp;#34;&lt;/span&gt;]]]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:whitespace&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\n      &amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:list&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:symbol&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;do&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:whitespace&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:list&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:symbol&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;when&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:whitespace&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:symbol&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;ch&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:whitespace&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\n            &amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:list&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:symbol&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;r/unread&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:whitespace&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:symbol&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;rdr&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:whitespace&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:symbol&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;ch&amp;#34;&lt;/span&gt;]]]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:whitespace&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\n          &amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:list&lt;/span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:symbol&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;str&amp;#34;&lt;/span&gt;] [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:whitespace&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;] [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:symbol&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;sb&amp;#34;&lt;/span&gt;]]]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:whitespace&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\n      &amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:list&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:symbol&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;recur&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:whitespace&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:conditional&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:list&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:keyword&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;:clj&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:whitespace&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:list&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:symbol&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;.append&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:whitespace&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:symbol&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;sb&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:whitespace&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:symbol&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;ch&amp;#34;&lt;/span&gt;]]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:whitespace&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:keyword&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;:cljs&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:whitespace&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:list&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:symbol&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;.append&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:whitespace&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:symbol&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;sb&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:whitespace&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:symbol&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;ch&amp;#34;&lt;/span&gt;]]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:whitespace&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:keyword&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;:cljr&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:whitespace&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:list&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:symbol&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;.Append&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:whitespace&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:symbol&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;sb&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:whitespace&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:list&lt;/span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:symbol&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;str&amp;#34;&lt;/span&gt;] [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:whitespace&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;] [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:symbol&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;ch&amp;#34;&lt;/span&gt;]]]]]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:whitespace&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:list&lt;/span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:symbol&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;r/read-char&amp;#34;&lt;/span&gt;] [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:whitespace&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;] [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:symbol&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;rdr&amp;#34;&lt;/span&gt;]]]]]]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Yes, it&amp;rsquo;s abysmal, but bear with me.
I had to work with this, after all, thinking that this is a blessing.&lt;/p&gt;
&lt;p&gt;The compiler sees &lt;code&gt;defn-&lt;/code&gt; and enters the &lt;code&gt;compile-special.defn-&lt;/code&gt; function.
Defn expects a function name, then a vector for its arguments.
Here, instead of the vector, we have &lt;code&gt;metadata&lt;/code&gt; node again.
This is fine, since I just mentioned above that I managed to sidestep this problem.&lt;/p&gt;
&lt;p&gt;Since this is an arglist, we need to compile it in a special way, adding its symbols to the function scope, etc.
However, instead of arguments, we see the &lt;code&gt;conditional&lt;/code&gt; node:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:vector&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:conditional&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:list&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:keyword&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;:clj&amp;#34;&lt;/span&gt;] [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:whitespace&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;] [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:symbol&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;rdr&amp;#34;&lt;/span&gt;] [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:whitespace&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:keyword&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;:cljs&amp;#34;&lt;/span&gt;] [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:whitespace&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;] [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:metadata&lt;/span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:metadata-entry&lt;/span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:symbol&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;not-native&amp;#34;&lt;/span&gt;]] [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:whitespace&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;] [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:symbol&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;rdr&amp;#34;&lt;/span&gt;]] [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:whitespace&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:keyword&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;:cljr&amp;#34;&lt;/span&gt;] [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:whitespace&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;] [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:symbol&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;rdr&amp;#34;&lt;/span&gt;]]]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:whitespace&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:symbol&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;_kind&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:whitespace&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:symbol&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;initch&amp;#34;&lt;/span&gt;]]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I didn&amp;rsquo;t think it was allowed in Clojure to use conditional reading inside forms like this.
But apparently it&amp;rsquo;s OK, and my compiler failed to deal with it.&lt;/p&gt;
&lt;p&gt;So now, any node can not only be a &lt;code&gt;metadata&lt;/code&gt; node, but also a &lt;code&gt;conditional&lt;/code&gt; node.
This complicates things, but at this point I&amp;rsquo;m still thinking that I can persevere.&lt;/p&gt;
&lt;p&gt;So I did.
I added support for almost all specials provided by &lt;code&gt;cljlib&lt;/code&gt;.
The main thing that was left to do were macros.
And then it hit me:&lt;/p&gt;
&lt;p&gt;I can&amp;rsquo;t do macros like that!&lt;/p&gt;
&lt;p&gt;Why?
Why, of course, because macros don&amp;rsquo;t emit tagged trees that my compiler understands.
They emit code!&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s a simple macro:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defmacro &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;unless&lt;/span&gt; [&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;test &lt;/span&gt;&amp;amp; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;body&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  `(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;when &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;not &lt;/span&gt;~&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;test&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     ~@&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;body&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We can parse it:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:list&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:symbol&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;defmacro&amp;#34;&lt;/span&gt;] [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:whitespace&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;] [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:symbol&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;unless&amp;#34;&lt;/span&gt;] [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:whitespace&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:vector&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:symbol&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;test&amp;#34;&lt;/span&gt;] [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:whitespace&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;] [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:symbol&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;amp;&amp;#34;&lt;/span&gt;] [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:whitespace&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;] [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:symbol&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;body&amp;#34;&lt;/span&gt;]]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:whitespace&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:backtick&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:list&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:symbol&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;when&amp;#34;&lt;/span&gt;] [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:whitespace&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:list&lt;/span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:symbol&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;not&amp;#34;&lt;/span&gt;] [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:whitespace&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;] [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:unquote&lt;/span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:symbol&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;test&amp;#34;&lt;/span&gt;]]]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:whitespace&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;] [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:unquote-splicing&lt;/span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:symbol&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;body&amp;#34;&lt;/span&gt;]]]]]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We can probably even compile it to something that we could then call during the compiler step.
However, what will &lt;code&gt;(unless true (println 42))&lt;/code&gt; thing return?&lt;/p&gt;
&lt;p&gt;&lt;code&gt;(when (not true) (println 42))&lt;/code&gt;, of course.
It&amp;rsquo;s a Lisp macro, what else did you expect?&lt;/p&gt;
&lt;p&gt;But what does the compiler expect?&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:list&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:symbol&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;when&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:whitespace&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:list&lt;/span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:symbol&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;not&amp;#34;&lt;/span&gt;] [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:whitespace&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;] [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:symbol&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;true&amp;#34;&lt;/span&gt;]]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:whitespace&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:list&lt;/span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:symbol&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;println&amp;#34;&lt;/span&gt;] [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:whitespace&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;] [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:number&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;42&amp;#34;&lt;/span&gt;]]]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Oh, it wants this.&lt;/p&gt;
&lt;p&gt;I have to convert macro&amp;rsquo;s output into a string, parse it, and feed it into the compiler if I want macros to work at all.
And that&amp;rsquo;s BAD.
If only I realized this sooner!&lt;/p&gt;
&lt;p&gt;This was the final nail in the coffin of the tagged tree approach for my project.
I knew I had to rewrite the parser to emit actual data structures that I&amp;rsquo;ll be able to emit from macros as well, and compile them.&lt;/p&gt;
&lt;h2 id=&#34;new-reader&#34;&gt;New &lt;del&gt;parser&lt;/del&gt; reader&lt;/h2&gt;
&lt;p&gt;So I decided that I need a proper lisp reader that will produce data structures:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; Welcome to Fennel Proto REPL 0.6.4-dev&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; Fennel version: 1.7.0-dev&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; Lua version: PUC Lua 5.5&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; Work directory: ~/Projects/fennel/ClojureFnl/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;reader&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:impl.reader&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;reader.read-string&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;(def ^:private foo 42)&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;foo&lt;/span&gt; 42)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;{&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;meta&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;second&lt;/span&gt;} (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:clojure.core&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;meta&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;second&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;reader.read-string&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;(def ^:private foo 42)&amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:private&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;true&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As can be seen, the new &lt;code&gt;reader&lt;/code&gt; module provides the &lt;code&gt;read-string&lt;/code&gt; function that produces data structures.
Notably, there are no longer any metadata nodes - metadata is assigned to the symbol &lt;code&gt;foo&lt;/code&gt; in this case.&lt;/p&gt;
&lt;p&gt;Same goes for the reader conditionals:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;reader.read-string&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;[0 #?(:clj 1 :cljfnl 2) #?@(:clj [2 3] :cljfnl [3 4]) 5]&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[0 2 3 4 5]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;These are now correctly spliced at read time.&lt;/p&gt;
&lt;p&gt;This also solved macro problems for the most part:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;reader.read-string&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;`(+ ~x ~@y ~z)&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure.core/seq&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure.core/concat&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure.core/list&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;quote &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure.core/+&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure.core/list&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure.core/list&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;z&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And it matches what Clojure itself does:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Clojure&lt;/span&gt; 1.12&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;.5&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user=&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-string&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;`(+ ~x ~@y ~z)&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure.core/seq&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure.core/concat&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure.core/list&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;quote &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure.core/+&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure.core/list&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure.core/list&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;z&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Due to this change, the compiler doesn&amp;rsquo;t have to know about syntax quote (&lt;code&gt;`&lt;/code&gt;) at all, and thus macros will correctly return these kinds of lists.&lt;/p&gt;
&lt;p&gt;So, now we can read Clojure code into data structures.
Previously, the parser returned &lt;code&gt;[:code A B ...]&lt;/code&gt; kind of result, where &lt;code&gt;A&lt;/code&gt;, &lt;code&gt;B&lt;/code&gt;, and the rest are all top-level forms.
New reader also does this, but returns them as a list:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;reader.read-string-all&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;1 \&amp;#34;str\&amp;#34; :keyword ::namespaced #:map{:key :val}&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;str&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:keyword&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:user/namespaced&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:map/key&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:val&lt;/span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;However, there&amp;rsquo;s a problem.&lt;/p&gt;
&lt;p&gt;Consider the &lt;code&gt;::namespaced&lt;/code&gt; keyword.
Both my reader and Clojure read it as &lt;code&gt;:user/namespaced&lt;/code&gt;, but this is because the default namespace in the REPL is &lt;code&gt;user&lt;/code&gt;.
For my parser, it&amp;rsquo;s mostly an arbitrary choice because it doesn&amp;rsquo;t know anything about runtime.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Clojure&lt;/span&gt; 1.12&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;.5&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user=&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-string&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;::x&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:user/x&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user=&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;ns &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;foo&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;foo=&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-string&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;::x&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:foo/x&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And when compiling a file, the file might have an &lt;code&gt;ns&lt;/code&gt; declaration, or even multiple of them:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;ns &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;foo&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;println &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;::x&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;ns &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bar&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;println &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;::x&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If we were to run this code, we would see &lt;code&gt;:foo/x&lt;/code&gt; then &lt;code&gt;:bar/x&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;My parser currently reads all input, meaning it transforms all top-level forms from text to data.
However, this also means that it doesn&amp;rsquo;t understand anything about namespaces.&lt;/p&gt;
&lt;p&gt;Previously, this was fine because the compiler handled this - the tagged tree didn&amp;rsquo;t resolve anything.
Currently, however, we need to construct namespaced keys, and we need to know the namespace.
But it&amp;rsquo;s not possible unless we parse the input expression by expression, instead of all at once.&lt;/p&gt;
&lt;p&gt;Hence, I had to update the grammar so it could parse expression by expression.
This way, I could read source code form by form, and compile each form separately.
And if the compiler encounters an &lt;code&gt;ns&lt;/code&gt; declaration, it could update some state, so the reader would know how to read namespaced keywords, and other things that may include namespaces.&lt;/p&gt;
&lt;p&gt;But we still need to pass this state to the reader.
And my reader is based on a PEG grammar.&lt;/p&gt;
&lt;p&gt;Luckily for me, the &lt;code&gt;lpeg&lt;/code&gt; library I use has a &lt;code&gt;Carg&lt;/code&gt; function that can pass additional arguments into the PEG parser.
This way I can write my transformation function &lt;code&gt;T&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;T&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tag&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;patt&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;/ &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;* &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Ct&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;* &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Cc&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tag&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;patt&lt;/span&gt;)) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Carg&lt;/span&gt; 1))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;node&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;state&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;node&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; ----8&amp;lt;----&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:macro-keyword&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bo&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-macro-keyword&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bo&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;state&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:conditional&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-conditional&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;state&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:conditional-splicing&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;conditional-splicing&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;state&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; ----8&amp;lt;----&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This state can be passed anew after reading each expression, or mutated in place - either way, the reader now knows how to access state.
The reader itself is still stateless.&lt;/p&gt;
&lt;p&gt;The reader now supports all Clojure syntax and produces data structures:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; Clojure                                          ;; Fennel&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;1                                                   &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; 1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;0.5                                                 &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; 0.5&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;1&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;e10&lt;/span&gt;                                                &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; 10000000000.0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;1&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;/2&lt;/span&gt;                                                 &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; 1/2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;1&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;N&lt;/span&gt;                                                  &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; 1N&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;1.33333333333333333333333333333333&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;M&lt;/span&gt;                 &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; 1.33333333333333333333333333333333M&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;xFF&lt;/span&gt;                                                &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; 255&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;017                                                 &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; 15&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;16&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rFF&lt;/span&gt;                                               &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; 255&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;\c&lt;/span&gt;                                                  &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; &amp;#34;c&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;string&amp;#34;&lt;/span&gt;                                            &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; &amp;#34;string&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;\u&lt;/span&gt;0041                                              &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; &amp;#34;A&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;\o&lt;/span&gt;101                                               &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; &amp;#34;A&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:keyword&lt;/span&gt;                                            &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; :keyword&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:namespaced/keyword&lt;/span&gt;                                 &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; :namespaced/keyword&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;::auto-keyword&lt;/span&gt;                                      &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; :user/auto-keyword&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;symbol &lt;/span&gt;                                             &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; symbol&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;namespaced/symbol&lt;/span&gt;                                   &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; namespaced/symbol&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;var&lt;/span&gt;                                               &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; (var var)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;quoted-symbol&lt;/span&gt;                                      &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; (quote quoted-symbol)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;list&lt;/span&gt;)                                              &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; (list)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vector&lt;/span&gt;]                                            &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; [vector]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;hash&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;map&lt;/span&gt;}                                          &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; {hash map}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:namespaced&lt;/span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:map&lt;/span&gt; 42}                               &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; {:namespaced/map 42}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#&lt;span style=&#34;&#34;&gt;::&lt;/span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:auto&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:namespaced&lt;/span&gt;}                              &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; {:user/auto :namespaced}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#{&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;hash&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;set&lt;/span&gt;}                                         &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; #{set hash}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;regexp&amp;#34;&lt;/span&gt;                                           &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; &amp;#34;regexp&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dereferencing&lt;/span&gt;                                      &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; (clojure.core/deref dereferencing)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;%1&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;%2&lt;/span&gt;)                                          &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; (fn* [p__0__ p__1__] (+ p__0__ p__1__))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;^&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:meta&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;                                         &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; data&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_discard&lt;/span&gt;                                           &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[#&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;?&lt;/span&gt;(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:cljfnl&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;reader&amp;#34;&lt;/span&gt;) #&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;?&lt;/span&gt;@(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:cljfnl&lt;/span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:conditionals&lt;/span&gt;])] &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; [&amp;#34;reader&amp;#34; :conditionals]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;                                                 &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;true&lt;/span&gt;                                                &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;false&lt;/span&gt;                                               &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; false&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;##&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;NaN&lt;/span&gt;                                               &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; .nan&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;##&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Inf&lt;/span&gt;                                               &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; .inf&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;inst&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;2022&amp;#34;&lt;/span&gt;                                        &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; #inst &amp;#34;2022-01-01T00:00:00.000-00:00&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;uuid&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;c6e8050a-789b-4305-b518-8f0f7c31da7a&amp;#34;&lt;/span&gt;        &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; #uuid &amp;#34;c6e8050a-789b-4305-b518-8f0f7c31da7a&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Note about data structures: even though we&amp;rsquo;re working in Fennel, the produced maps, vectors and lists are custom data structures that are implemented in the &lt;code&gt;cljlib&lt;/code&gt; library.
These are implementations of persistent data structures I&amp;rsquo;ve talked about in &lt;a href=&#34;https://andreyor.st/posts/2026-04-15-clojure-on-fennel-part-two-immutablefnl-optimizations/&#34;&gt;part 2&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&#34;further-work&#34;&gt;Further work&lt;/h2&gt;
&lt;p&gt;With that, I can work on the compiler, now for real.
It&amp;rsquo;s a shame that I basically have to do all the work on the compiler again from scratch, because the underlying data has changed so much, but this simplifies a lot of things, so I&amp;rsquo;m OK with that.&lt;/p&gt;
&lt;p&gt;One thing that the reader still doesn&amp;rsquo;t support yet is read-time evaluation with &lt;code&gt;#=expr&lt;/code&gt;.
This requires a working compiler, and I&amp;rsquo;ll have to first implement it, then integrate it back into the reader.&lt;/p&gt;
&lt;p&gt;Another thing I was thinking about was to drop the LPEG parser altogether.
Maybe, when I have the compiler working and have support for all Clojure runtime semantics in place, I&amp;rsquo;ll make a fork of the Edamame parser and replace the current reader with it, adding support for ClojureFnl via reader conditionals.
This will remove a C library dependency, which is a good thing for distribution.
I still have another C library for arbitrary-precision numbers, but it can be worked around.&lt;/p&gt;
&lt;p&gt;But, lesson learned - when implementing a lisp, even if it is just a transpiler, don&amp;rsquo;t try to cut corners, and make a proper reader.&lt;/p&gt;
&lt;p&gt;Next post, &lt;strong&gt;for sure&lt;/strong&gt;, will be about the compiler!&lt;/p&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: Clojure on Fennel part four: Parsing (again)&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Mon, 29 Jun 2026 00:29:00 +0300</pubDate>
    </item><item>
      <title>Better slopes in AABB collision systems</title>
      <link>https://andreyor.st/posts/2026-06-17-better-slopes-in-aabb-collision-systems/</link>
      <guid>https://andreyor.st/posts/2026-06-17-better-slopes-in-aabb-collision-systems/</guid>
      <description>&lt;p&gt;Earlier this year I &lt;a href=&#34;https://andreyor.st/posts/2026-01-09-slopes-in-aabb-collision-systems/&#34;&gt;published a guide&lt;/a&gt; on how to implement slopes in AABB collision resolution using &lt;a href=&#34;https://github.com/kikito/bump.lua&#34; target=&#34;_blank&#34;&gt;bump.lua&lt;/a&gt;.
The resulting system worked, but was a bit hard to use in-game and had a few issues, so I wouldn&amp;rsquo;t consider it a viable solution.&lt;/p&gt;
&lt;p&gt;The main issue with the old approach was the use of the &lt;code&gt;cross&lt;/code&gt; collision response.
It allowed the object to move through the slope as if it wasn&amp;rsquo;t there at all, and then the update loop corrected the &lt;code&gt;y&lt;/code&gt; position after the fact.
This alone makes writing code the game a lot more complicated than it needs to be:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;player-collision-filter&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;obj&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;not= &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;obj.slope&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:cross&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:slide&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;grounded?&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;obj&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;collisions&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;l&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;world&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:check&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;obj&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;obj.x&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;obj.y&lt;/span&gt; 1) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;player-collision-filter&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;and &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;or &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;faccumulate&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;l&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:until&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;col&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;collisions&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 (&lt;span style=&#34;font-weight:bold&#34;&gt;when &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;col.other.slope&lt;/span&gt; &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; &amp;lt;- eeeeeh...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   (&lt;span style=&#34;font-weight:bold&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;obj.y&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;col.other.slope&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;obj&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             (&lt;span style=&#34;font-weight:bold&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;obj.y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;collisions&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;update&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;player&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;main&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; ---8&amp;lt;---&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;collisions&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;l&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;world&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:move&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;player&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;player.x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;player.x-vel&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;player.y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;player.y-vel&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;player-collision-filter&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;doto &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;player&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;tset &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;tset &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;for &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;l&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;collision&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;collisions&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;other&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;collision.other&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold&#34;&gt;when &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;other.slope&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;case&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;other.slope&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;player&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y*&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;when &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;&amp;gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;player.y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y*&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;world&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:update&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;player&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;player.x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y*&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;player.w&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;player.h&lt;/span&gt;) &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; &amp;lt;- yikes!&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 (&lt;span style=&#34;font-weight:bold&#34;&gt;doto &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;player&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   (&lt;span style=&#34;font-weight:bold&#34;&gt;tset &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y*&lt;/span&gt;)))))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; ---8&amp;lt;---&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I had to resort to calling the &lt;code&gt;world:update&lt;/code&gt; method, which, as &lt;a href=&#34;https://github.com/kikito/bump.lua#changing-the-position-and-dimensions-of-items-in-the-world&#34; target=&#34;_blank&#34;&gt;described in the bump&amp;rsquo;s docs&lt;/a&gt;, is used to update object&amp;rsquo;s position in the world without checking collisions.
This made slopes really awkward to use and work with.
And while I suspected that this was a wrong approach, I decided to go with it anyway, because at the time I didn&amp;rsquo;t knew better.&lt;/p&gt;
&lt;p&gt;Then, while &lt;a href=&#34;https://andreyor.st/posts/2026-05-24-spring-lisp-game-jam-2026/&#34;&gt;working&lt;/a&gt; on the &lt;a href=&#34;https://tic80.com/play?cart=4708&#34; target=&#34;_blank&#34;&gt;game&lt;/a&gt; for the &lt;a href=&#34;https://itch.io/jam/spring-lisp-game-jam-2026&#34; target=&#34;_blank&#34;&gt;Spring Lisp Game Jam&lt;/a&gt; I again needed a custom collision handling that is not supported by &lt;code&gt;bump.lua&lt;/code&gt; directly, but a bit simpler this time around.
It&amp;rsquo;s a common thing in games, where you can pass through the block from one side, but not from the other.
Like clouds usually behave in platformers - you can cross them from below, but still land on them:&lt;/p&gt;
&lt;figure&gt;
&lt;p&gt;&lt;video autoplay loop muted&gt;&lt;source src=&#34;https://andreyor.st/2026-06-17-better-slopes-in-aabb-collision-systems/cloud-platform.mp4&#34; type=&#34;video/mp4&#34;&gt;
Your browser does not support the video tag.&lt;/video&gt;&lt;/p&gt;
&lt;figcaption&gt;
  &lt;p&gt;A cloud platform in the game Rayman (1995)&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;However, &lt;code&gt;bump.lua&lt;/code&gt; by default only supports the following type of collisions: &lt;code&gt;slide&lt;/code&gt;, &lt;code&gt;cross&lt;/code&gt;, &lt;code&gt;touch&lt;/code&gt;, and &lt;code&gt;bounce&lt;/code&gt;:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2026-06-17-better-slopes-in-aabb-collision-systems/collision-responses.png&#34;
         alt=&#34;Figure 1: Response types from bump.lua documentation&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 1: &lt;/span&gt;Response types from bump.lua &lt;a href=&#34;https://github.com/kikito/bump.lua#collision-resolution&#34; target=&#34;_blank&#34;&gt;documentation&lt;/a&gt;&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Solving this using the &lt;code&gt;cross&lt;/code&gt; handler seemed wrong, and after a bit of searching I learned that in &lt;code&gt;bump.lua&lt;/code&gt; you can define your own collision response functions.
So I defined my own collision response called &lt;code&gt;slide-cross&lt;/code&gt; (because the main intention was to be able to go through from the sides with the &lt;code&gt;slide&lt;/code&gt; response but cross over it from below):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;slide-cross&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;world&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;col&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;w&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;h&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;goal-x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;goal-y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;filter&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;goal-x&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;goal-x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;var &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;goal-y&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;goal-y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;&amp;lt;= &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;h&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;col.otherRect.y&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tch&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;col.touch&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;move&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;col.move&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;font-weight:bold&#34;&gt;when &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;or &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;not= &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;move.x&lt;/span&gt; 0) (&lt;span style=&#34;font-weight:bold&#34;&gt;not= &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;move.y&lt;/span&gt; 0))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;font-weight:bold&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;goal-y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tch.y&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;font-weight:bold&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;col.slide&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;goal-x&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;goal-y&lt;/span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cols&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;len&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;world&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:project&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;col.item&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tch.x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tch.y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;w&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;h&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;goal-x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;goal-y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;filter&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;font-weight:bold&#34;&gt;values &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;goal-x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;goal-y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cols&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;len&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cols&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;len&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;world&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:project&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;col.item&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;w&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;h&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;goal-x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;goal-y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;filter&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;font-weight:bold&#34;&gt;values &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;goal-x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;goal-y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cols&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;len&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;world&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:addResponse&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:slide-cross&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;slide-cross&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With such colliders in place, I could replicate cloud platform behavior:&lt;/p&gt;
&lt;p&gt;&lt;video autoplay loop muted&gt;&lt;source src=&#34;https://andreyor.st/2026-06-17-better-slopes-in-aabb-collision-systems/bump-cloud.mp4&#34; type=&#34;video/mp4&#34;&gt;
Your browser does not support the video tag.&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;I didn&amp;rsquo;t use clouds themselves in the actual game - instead, this collider was assigned to specific blocks I wanted to be able to run past, acting more as background structures you can still jump on, i.e. pedestals, but the idea of making a custom collider got me thinking.
If I can make a custom collision response function, why not try to do it for slopes too?&lt;/p&gt;
&lt;p&gt;So that&amp;rsquo;s what I did.
But before that, I had to redo slopes a bit.&lt;/p&gt;
&lt;h2 id=&#34;slopes-in-bump-dot-lua&#34;&gt;Slopes in &lt;code&gt;bump.lua&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;First, let&amp;rsquo;s start with how slopes are defined:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;make-slope&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x0&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y0&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x1&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y1&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;slope-type&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nx&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ny&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;slope-normal&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x0&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y0&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x1&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y1&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;slope-type&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:slope&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;slope-type&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:surface&lt;/span&gt; #(&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y0&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;/ &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;* &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;- &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y1&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y0&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold&#34;&gt;- &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clamp&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x0&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;$&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x1&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x0&lt;/span&gt;)) (&lt;span style=&#34;font-weight:bold&#34;&gt;- &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x1&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x0&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nx&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ny&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:h&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;m/max&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y0&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y1&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:w&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;m/max&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x0&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x1&lt;/span&gt;)}))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;For example, to define a slope at coordinates &lt;code&gt;x,y&lt;/code&gt; that is &lt;code&gt;16px&lt;/code&gt; long and &lt;code&gt;8px&lt;/code&gt; tall (&lt;img class=&#34;pixelart invertable&#34; src=&#34;https://andreyor.st/2026-06-17-better-slopes-in-aabb-collision-systems/slope1.png&#34;&gt;&lt;/img&gt;), we can call &lt;code&gt;make-slope&lt;/code&gt; like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;make-slope&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt; 0 8 16 0 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:floor&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;A 45° &lt;code&gt;8x8&lt;/code&gt; slope (&lt;img class=&#34;pixelart invertable&#34; src=&#34;https://andreyor.st/2026-06-17-better-slopes-in-aabb-collision-systems/slope-45.png&#34;&gt;&lt;/img&gt;) can be defined as follows:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;make-slope&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt; 0 8 8 0 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:floor&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;These slopes get taller from left to right, if we want a slope that goes lower from left to right (&lt;img class=&#34;pixelart invertable&#34; src=&#34;https://andreyor.st/2026-06-17-better-slopes-in-aabb-collision-systems/slope2.png&#34;&gt;&lt;/img&gt;), we swap the coordinates:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;make-slope&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt; 0 0 16 8 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:floor&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This function returns an object representing the slope.
Of course, we&amp;rsquo;re not limited to defining &lt;code&gt;16x8&lt;/code&gt; and &lt;code&gt;8x8&lt;/code&gt; slopes - these are just the most logical choices for a platformer in TIC-80.
We can define steeper slopes like &lt;code&gt;8x16&lt;/code&gt;, or use an arbitrary size altogether.
As long as it can be clearly represented by the underlying spritework given resolution constraints you work in.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;make-slope&lt;/code&gt; constructor computes the slope&amp;rsquo;s normal vector:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;slope-normal&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x0&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y0&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x1&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y1&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;slope-type&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dx&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;- &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x1&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x0&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dy&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;- &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y1&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y0&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;len&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;m/sqrt&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;* &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dx&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dx&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold&#34;&gt;* &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dy&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dy&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nx&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;/ &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;- &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dy&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;len&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ny&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;/ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dx&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;len&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;or &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;and &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;slope-type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:floor&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold&#34;&gt;&amp;gt; &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ny&lt;/span&gt; 0))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;font-weight:bold&#34;&gt;and &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;slope-type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:ceiling&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold&#34;&gt;&amp;lt; &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ny&lt;/span&gt; 0)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold&#34;&gt;values &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;- &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nx&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold&#34;&gt;- &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ny&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold&#34;&gt;values &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nx&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ny&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It will be used in our response function to implement bouncing off the slope surface correctly - one of the things I fell short while making the previous version.&lt;/p&gt;
&lt;h2 id=&#34;slope-response-function-for-bump-dot-lua&#34;&gt;Slope response function for &lt;code&gt;bump.lua&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;Now we can define the response function itself:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;slope-response&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;world&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;col&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;w&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;h&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;goal-x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;goal-y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;filter&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;goal-x&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;goal-x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;surface&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:slope&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;slope-type&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nx&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ny&lt;/span&gt;} &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;col.other&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ox&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;oy&lt;/span&gt;} &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;col.otherRect&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;touch-y&lt;/span&gt;} &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;col.touch&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;var &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;goal-y&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;goal-y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;slope-type&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:floor&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;surf-y&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;m/min&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;oy&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;surface&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;- &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;goal-x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ox&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                 (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;oy&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;surface&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;- &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;goal-x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;w&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ox&lt;/span&gt;))))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;&amp;gt; &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;goal-y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;h&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;surf-y&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;&amp;gt; &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;col.normal.y&lt;/span&gt; 0)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                       (&lt;span style=&#34;font-weight:bold&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;goal-y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;touch-y&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                       (&lt;span style=&#34;font-weight:bold&#34;&gt;set &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;goal-y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;col.normal.x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;col.normal.y&lt;/span&gt;] [(&lt;span style=&#34;font-weight:bold&#34;&gt;- &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;surf-y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;h&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nx&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ny&lt;/span&gt;]))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   (&lt;span style=&#34;font-weight:bold&#34;&gt;set &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;col.normal.x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;col.normal.y&lt;/span&gt;] [0 0])))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:ceiling&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;surf-y&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;m/max&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;oy&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;surface&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;- &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;goal-x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ox&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                   (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;oy&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;surface&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;- &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;goal-x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;w&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ox&lt;/span&gt;))))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;&amp;lt; &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;goal-y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;surf-y&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                     (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;&amp;lt; &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;col.normal.y&lt;/span&gt; 0)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                         (&lt;span style=&#34;font-weight:bold&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;goal-y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;touch-y&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                         (&lt;span style=&#34;font-weight:bold&#34;&gt;set &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;goal-y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;col.normal.x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;col.normal.y&lt;/span&gt;] [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;surf-y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nx&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ny&lt;/span&gt;]))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                     (&lt;span style=&#34;font-weight:bold&#34;&gt;set &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;col.normal.x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;col.normal.y&lt;/span&gt;] [0 0])))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;error &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;unknown slope type: &amp;#34;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;tostring &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;col.slide&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;goal-x&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;goal-y&lt;/span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cols&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;len&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;world&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:project&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;col.item&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;w&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;h&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;goal-x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;goal-y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;filter&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;values &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;goal-x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;goal-y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cols&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;len&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It has two &lt;code&gt;case&lt;/code&gt; branches - one that I&amp;rsquo;ve omitted in the above explanation of &lt;code&gt;make-slope&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;slope-type&lt;/code&gt; argument, set to &lt;code&gt;floor&lt;/code&gt; in those examples, determines if a slope is a ground one or a one on the ceiling.
Another thing that wasn&amp;rsquo;t supported in the old method.&lt;/p&gt;
&lt;p&gt;This response function works as follows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It gets &lt;code&gt;goal-x&lt;/code&gt; and &lt;code&gt;goal-y&lt;/code&gt;, as well as other usual parameters, and the collision object.&lt;/li&gt;
&lt;li&gt;The slope is always in &lt;code&gt;col.other&lt;/code&gt;, because slope itself never collides with anything (they&amp;rsquo;re never passed to &lt;code&gt;world:move&lt;/code&gt; calls).&lt;/li&gt;
&lt;li&gt;We get the slope&amp;rsquo;s rectangle to adjust our object&amp;rsquo;s position across the slope&amp;rsquo;s width.&lt;/li&gt;
&lt;li&gt;Then we check &lt;code&gt;slope-type&lt;/code&gt;
&lt;ul&gt;
&lt;li&gt;For floor slopes we get the &lt;code&gt;min&lt;/code&gt; of the &lt;code&gt;y&lt;/code&gt; coordinate of the slope &lt;code&gt;y&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Then we check if the &lt;code&gt;goal-y&lt;/code&gt; received by the collision response function is below the slope&amp;rsquo;s surface.&lt;/li&gt;
&lt;li&gt;If so, and the normal vector points up, meaning the collision comes from above the slope, we set the &lt;code&gt;goal-y&lt;/code&gt; and normal vector.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;For ceiling slopes, the logic is the same, only some signs and checks are inverted.&lt;/li&gt;
&lt;li&gt;If approached from the other side of the slope, i.e. from below - the collision acts like a regular AABB, so the slope forms a right triangle.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Handling &lt;code&gt;goal-y&lt;/code&gt; and normal vector inside the response function provides much cleaner slopes:&lt;/p&gt;
&lt;figure&gt;
&lt;p&gt;&lt;video autoplay loop muted&gt;&lt;source src=&#34;https://andreyor.st/2026-06-17-better-slopes-in-aabb-collision-systems/aabb-slopes.mp4&#34; type=&#34;video/mp4&#34;&gt;
Your browser does not support the video tag.&lt;/video&gt;&lt;/p&gt;
&lt;figcaption&gt;
  &lt;p&gt;Note: it may seem that balls float over the slopes without touching, but that&#39;s only a visual quirk because ball&#39;s collider is still a 8x8 square - it touches the slope wiht a corner, but the sprite makes it look that it&#39;s floating.  A more precise collider for the ball is needed, but it&#39;s out of the scope of this post.&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;The old implementation couldn&amp;rsquo;t achieve such smooth gliding over the slope&amp;rsquo;s surface.
Balls get stuck on adjacent slopes, and incorrect normals prevent balls from rolling off smoothly:&lt;/p&gt;
&lt;figure&gt;
&lt;p&gt;&lt;video autoplay loop muted&gt;&lt;source src=&#34;https://andreyor.st/2026-06-17-better-slopes-in-aabb-collision-systems/old-slopes-jagged.mp4&#34; type=&#34;video/mp4&#34;&gt;
Your browser does not support the video tag.&lt;/video&gt;&lt;/p&gt;
&lt;figcaption&gt;
  &lt;p&gt;Note: in this clip the ball seems to touch the slope properly, but again, it&#39;s just a visual thing - in reality the slope is a little below the sprite&#39;s visual representation of it.&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Now, when slopes are defined better, we can integrate them into a mock-up platformer to test them in a game environment:&lt;/p&gt;
&lt;p&gt;&lt;video autoplay loop muted&gt;&lt;source src=&#34;https://andreyor.st/2026-06-17-better-slopes-in-aabb-collision-systems/game-slopes.mp4&#34; type=&#34;video/mp4&#34;&gt;
Your browser does not support the video tag.&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;I don&amp;rsquo;t use normal vectors here, since in a platformer the jump usually goes up, regardless of the terrain, but depending on the player&amp;rsquo;s state one could use normals as well, given that we have them in the collision info.&lt;/p&gt;
&lt;p&gt;The old implementation of slopes had problems, that can be seen here:&lt;/p&gt;
&lt;p&gt;&lt;video autoplay loop muted&gt;&lt;source src=&#34;https://andreyor.st/2026-06-17-better-slopes-in-aabb-collision-systems/old-slopes.mp4&#34; type=&#34;video/mp4&#34;&gt;
Your browser does not support the video tag.&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;Notice that when transitioning from slope to solid ground, the player transitions to the falling state for one frame.
This was because we had to handle slope collisions outside of the collider itself, in the update loop - we couldn&amp;rsquo;t cross slopes unless they&amp;rsquo;re a tiny bit higher than the ground next to it.
This problem is now eliminated by handling slopes during bump&amp;rsquo;s collision resolution step.&lt;/p&gt;
&lt;p&gt;But we don&amp;rsquo;t have to stop there - what we have now is basically an extension to normal &lt;abbr title=&#34;Axis-Aligned Bounding-Box&#34;&gt;AABB&lt;/abbr&gt; with custom height functions that are bound by bounding boxes.
So we can create any kind of slopes, like ramps - we just need a proper height function.
However, we did a small optimisation that prevents us from doing it right now - we pre-computed slope normals.
If we use a height function whose normal vector changes along the &lt;code&gt;x&lt;/code&gt; coordinate, we need to handle that in the &lt;code&gt;slope-response&lt;/code&gt; function:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-diff&#34; data-lang=&#34;diff&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (fn slope-response [world col x y w h goal-x goal-y filter]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span                                  &gt;   (let [goal-x (or goal-x x)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span style=&#34;background-color:#efcbcf;&#34;&gt;-        {: surface :slope slope-type : nx : ny} col.other
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span style=&#34;background-color:#bbeabb&#34;&gt;+        {: surface :slope slope-type} col.other
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span                                  &gt;         {:x ox :y oy} col.otherRect
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span style=&#34;background-color:#efcbcf;&#34;&gt;-        {:y touch-y} col.touch]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span style=&#34;background-color:#bbeabb&#34;&gt;+        cx (- (+ goal-x (/ w 2)) ox)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span style=&#34;background-color:#bbeabb&#34;&gt;+        (nx ny) (slope-normal (- cx 1) (surface (- cx 1))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span style=&#34;background-color:#bbeabb&#34;&gt;+                              (+ cx 1) (surface (+ cx 1)) slope-type)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span                                  &gt;     (var goal-y (or goal-y y))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span                                  &gt;     (case slope-type
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span                                  &gt;       :floor (let [surf-y (m/min (+ oy (surface (- goal-x ox)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span                                  &gt;                                  (+ oy (surface (- (+ goal-x w) ox))))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span                                  &gt;                (if (&amp;gt; (+ goal-y h) surf-y)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span style=&#34;background-color:#efcbcf;&#34;&gt;-                   (if (&amp;gt; col.normal.y 0)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span style=&#34;background-color:#efcbcf;&#34;&gt;-                       (set goal-y touch-y)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span style=&#34;background-color:#efcbcf;&#34;&gt;-                       (set [goal-y col.normal.x col.normal.y] [(- surf-y h) nx ny]))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span style=&#34;background-color:#bbeabb&#34;&gt;+                   (set [goal-y col.normal.x col.normal.y] [(- surf-y h) nx ny])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span                                  &gt;                    (set [col.normal.x col.normal.y] [0 0])))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span                                  &gt;       :ceiling (let [surf-y (m/max (+ oy (surface (- goal-x ox)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span                                  &gt;                                    (+ oy (surface (- (+ goal-x w) ox))))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span                                  &gt;                  (if (&amp;lt; goal-y surf-y)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span style=&#34;background-color:#efcbcf;&#34;&gt;-                     (if (&amp;lt; col.normal.y 0)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span style=&#34;background-color:#efcbcf;&#34;&gt;-                         (set goal-y touch-y)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span style=&#34;background-color:#efcbcf;&#34;&gt;-                         (set [goal-y col.normal.x col.normal.y] [surf-y nx ny]))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span style=&#34;background-color:#bbeabb&#34;&gt;+                     (set [goal-y col.normal.x col.normal.y] [surf-y nx ny])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span                                  &gt;                      (set [col.normal.x col.normal.y] [0 0])))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span                                  &gt;       _ (error (.. &#34;unknown slope type: &#34; (tostring _))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span                                  &gt;     (set col.slide {:x goal-x :y goal-y})
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;With that in place, we can even make dynamic slopes, like a moving sine wave, and objects will correctly respond:&lt;/p&gt;
&lt;p&gt;&lt;video autoplay loop muted&gt;&lt;source src=&#34;https://andreyor.st/2026-06-17-better-slopes-in-aabb-collision-systems/sine-slopes.mp4&#34; type=&#34;video/mp4&#34;&gt;
Your browser does not support the video tag.&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;For my purposes, I don&amp;rsquo;t need this kind of flexibility yet, but it&amp;rsquo;s nice to be able to do it still.
I could see this being used in a game like Sonic, where you have loops, which are circles.
Defining four slopes for each circle quadrant (two bottom ones as &lt;code&gt;floor&lt;/code&gt; slopes and upper ones as &lt;code&gt;ceiling&lt;/code&gt; slopes), and handling how to enter and exit them by marking some of them inactive via the &lt;code&gt;cross&lt;/code&gt; collision response.
Handling normals in this case would prove handy, as Sonic jumps perpendicular to the normal at the current position on the slope.&lt;/p&gt;
&lt;p&gt;&lt;video autoplay loop muted&gt;&lt;source src=&#34;https://andreyor.st/2026-06-17-better-slopes-in-aabb-collision-systems/sonic.mp4&#34; type=&#34;video/mp4&#34;&gt;
Your browser does not support the video tag.&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;However, we lost one additional feature our original &lt;code&gt;slope-response&lt;/code&gt; had: these slopes don&amp;rsquo;t have solid opposite side.
Triangular floor slopes prevented objects from entering the slope from beneath, only from the sides and from above the slope.
Sine-wave slope will teleport objects to the slope side if an object entered inside - it&amp;rsquo;s a correctness measure, because of a more complicated geometry.&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s not a bad thing on its own, since slopes are usually surrounded by other types of ground anyway, but still a thing to consider.&lt;/p&gt;
&lt;p&gt;With that, I have almost perfect slopes for &lt;code&gt;bump.lua&lt;/code&gt;, and I can use it in systems where I can&amp;rsquo;t access more sophisticated collision detection systems like &lt;a href=&#34;https://box2d.org/&#34; target=&#34;_blank&#34;&gt;Box2D&lt;/a&gt;.
There are still things to be aware of, though.
First, because bump&amp;rsquo;s collision resolution does a single pass, we can&amp;rsquo;t handle cases well where a ball touches the slope, another wall, and another ball.
Second, the order of collisions can give different outcomes - if a ball lands exactly in the middle of two slopes, the outcome is determined by which slope &lt;code&gt;bump.lua&lt;/code&gt; will check first.
So it&amp;rsquo;s good for simple cases, but not a proper slope collision simulation, like one found in non-AABB systems.&lt;/p&gt;
&lt;p&gt;On that note, I think I&amp;rsquo;m satisfied with what I have, and I&amp;rsquo;ll try to use this in my next game projects!
And, as always, the &lt;a href=&#34;https://tic80.com/play?cart=4730&#34; target=&#34;_blank&#34;&gt;you can try this online here&lt;/a&gt;, and a downloadable version of a cart is provided below:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2026-06-17-better-slopes-in-aabb-collision-systems/aabb-slopes.png&#34;/&gt;
&lt;/figure&gt;

&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: Better slopes in AABB collision systems&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Wed, 17 Jun 2026 19:14:00 +0300</pubDate>
    </item><item>
      <title>Spring Lisp Game Jam 2026</title>
      <link>https://andreyor.st/posts/2026-05-24-spring-lisp-game-jam-2026/</link>
      <guid>https://andreyor.st/posts/2026-05-24-spring-lisp-game-jam-2026/</guid>
      <description>&lt;p&gt;This year I decided to participate in the &lt;a href=&#34;https://itch.io/jam/spring-lisp-game-jam-2026&#34; target=&#34;_blank&#34;&gt;Spring Lisp Game Jam&lt;/a&gt;.
It&amp;rsquo;s an annual event, where you have to make a game in any kind of lisp in a limited time, usually a week.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve been putting this away for several years, because every time the jam started I wasn&amp;rsquo;t ready to spend time on it, because of work or other duties I had at the time.
This year, however, I decided to take a vacation, and give it my all.
Life, of course, had other plans, but I managed to persevere.&lt;/p&gt;
&lt;p&gt;This game jam doesn&amp;rsquo;t have a particular theme, which is good, as I always wanted to make a particular kind of a game - a movement-oriented platformer.
I really enjoyed games like Metroid Fusion and Metroid Dread, which, to my taste, have great platforming, especially in Dread, so I wanted to make something akin to it.
On paper, this idea seemed doable.
In practice, well, you&amp;rsquo;ll see.&lt;/p&gt;
&lt;p&gt;I decided to make &amp;ldquo;speed&amp;rdquo; the main thing of my game, thinking that the core idea will be to maintain speed, and complete room-based obstacle courses.
My engine of choice was again &lt;a href=&#34;https://tic80.com/&#34; target=&#34;_blank&#34;&gt;TIC-80&lt;/a&gt; as I had some experience with it already, and it&amp;rsquo;s the most frictionless environment I know for making small games.
That&amp;rsquo;s debatable, of course, given TIC&amp;rsquo;s restrictions of resolution of 240x136 pixels and a 16-color-only palette.
But I like restrictions, they breed creativity, as we all know.&lt;/p&gt;
&lt;p&gt;This is more of a postmortem post, as I&amp;rsquo;m writing this after finishing the game - I simply had no capacity of writing this during the development.
So information below is more of how I remember this, and of notes I made along the way.&lt;/p&gt;
&lt;h2 id=&#34;day-1&#34;&gt;Day 1&lt;/h2&gt;
&lt;p&gt;First things first, I chose TIC-80, and it supports programming in lisp out of the box.
The language in question is Fennel, which is a nice lisp that compiles to Lua.
I needed a few things though.&lt;/p&gt;
&lt;p&gt;TIC doesn&amp;rsquo;t have any built-in functionality besides the essential things for drawing on the screen and reading user&amp;rsquo;s input.
My game needs to deal with collisions, and while other game engines, like LOVE, include a library for that, TIC is certainly not.&lt;/p&gt;
&lt;p&gt;A popular library for this is &lt;a href=&#34;https://github.com/kikito/bump.lua&#34; target=&#34;_blank&#34;&gt;bump.lua&lt;/a&gt;, however, TIC doesn&amp;rsquo;t allow filesystem interactions, so the library must be bundled inside the cart.
However, this is a Lua library, and I&amp;rsquo;m making a game in Fennel.&lt;/p&gt;
&lt;p&gt;Fennel has a way of inlining dependencies via the &lt;code&gt;--require-as-include&lt;/code&gt; option that could be used, however, it only works when compiling Fennel code to Lua.
And I&amp;rsquo;m not sure if this will pass for the game jam.
Plus, Fennel doesn&amp;rsquo;t compile comments, so I couldn&amp;rsquo;t just write the game cart in Fennel and then compile it to Lua, I&amp;rsquo;d need to translate all of the cart metadata by hand.&lt;/p&gt;
&lt;p&gt;Luckily, a few years ago I made a port of bump.lua to Fennel for cases like this.
I used it in the &lt;a href=&#34;https://gitlab.com/andreyorst/game1/-/blob/main/cart.fnl&#34; target=&#34;_blank&#34;&gt;other game&lt;/a&gt; I was making at the time.
You can read my old dev-log &lt;a href=&#34;https://andreyor.st/tags/game1&#34;&gt;here&lt;/a&gt;.
Anyhow, I needed to make an actual game, not just mess with libraries, so I &lt;a href=&#34;https://lospec.com/palette-list/urbex-16&#34; target=&#34;_blank&#34;&gt;picked a palette&lt;/a&gt; and began working.&lt;/p&gt;
&lt;p&gt;First day was all about player controller.
I needed a solid foundation to build the game around, and none of my previous player controllers were adequate for this.
They were too stiff.&lt;/p&gt;
&lt;p&gt;At the end of the day I ended up with this:&lt;/p&gt;
&lt;p&gt;&lt;video autoplay loop muted&gt;&lt;source src=&#34;https://andreyor.st/2026-05-24-spring-lisp-game-jam-2026/day-1.mp4&#34; type=&#34;video/mp4&#34;&gt;
Your browser does not support the video tag.&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;This is a bit more than just a player controller - I have a camera system, level editor, placeholder graphics, and powerups already coded.&lt;/p&gt;
&lt;p&gt;This is my camera system:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;camera&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:x&lt;/span&gt; 96
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:y&lt;/span&gt; 40
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:update&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self&lt;/span&gt; {&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt;}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;font-weight:bold&#34;&gt;doto &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;font-weight:bold&#34;&gt;tset &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:x&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;* &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;// &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; 240) 240))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;font-weight:bold&#34;&gt;tset &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:y&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;* &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;// &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt; 136) 136))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:draw&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[{&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt;} &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;remap&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;map&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;// &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; 8) (&lt;span style=&#34;font-weight:bold&#34;&gt;// &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt; 8) (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;// &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; 8) 31) (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;// &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt; 8) 18) 0 0 0 1 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;remap&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:translate&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cam-x&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cam-y&lt;/span&gt;} &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;font-weight:bold&#34;&gt;values &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;- &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cam-x&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold&#34;&gt;- &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cam-y&lt;/span&gt;)))})
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It&amp;rsquo;s a simple object that has three main methods.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;update&lt;/code&gt; method is responsible for camera positioning.
It is called on each frame, and it simply clamps the &lt;code&gt;x, y&lt;/code&gt; position into the one full screen range.
Thus, this is not a free camera, it is locked to the current screen.&lt;/p&gt;
&lt;p&gt;I had dynamic cameras in the past, and while I like them, for this game I wanted something different.
Essentially, my vision was that each screen will be an obstacle course, although even at this point I already knew this would be a bit problematic.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;draw&lt;/code&gt; method simply draws the current visible range of tiles via the &lt;code&gt;map&lt;/code&gt; command.
I have a &lt;code&gt;remap&lt;/code&gt; callback ready in case I&amp;rsquo;ll need to change some tiles dynamically.&lt;/p&gt;
&lt;p&gt;The final method &lt;code&gt;translate&lt;/code&gt; is an interesting one.
When I draw anything, like the player, or interactable objects, I need to do so in the camera space.
So I call &lt;code&gt;(camera:translate obj.x obj.y)&lt;/code&gt; to get screen-space coordinates.
In other words, object&amp;rsquo;s coordinates may be &lt;code&gt;1337,420&lt;/code&gt;, but in camera space they as well may be &lt;code&gt;42,27&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The camera draws the level from the map editor built into TIC, but we need to load it into the game to interact with it properly.
So we need a system to do that.&lt;/p&gt;
&lt;p&gt;The level editor is another thing I reused from the last game I made with TIC.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;objects&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  {1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:player&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   17 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:speed-up&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   33 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:jump-up&lt;/span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;macro &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;id&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  `(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mget&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;// &lt;/span&gt;&lt;span style=&#34;&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; 8) (&lt;span style=&#34;font-weight:bold&#34;&gt;// &lt;/span&gt;&lt;span style=&#34;&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt; 8)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;obj?&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;objects&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;id&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;solid?&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fget&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;id&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt;) 0))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;load-map-to-world&lt;/span&gt; []
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;for &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; 0 (&lt;span style=&#34;font-weight:bold&#34;&gt;* &lt;/span&gt;240 8) 8]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;for &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt; 0 (&lt;span style=&#34;font-weight:bold&#34;&gt;* &lt;/span&gt;136 8) 8]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;case&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;obj?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:player&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;do &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mset&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;// &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; 8) (&lt;span style=&#34;font-weight:bold&#34;&gt;// &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt; 8) 0)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    (&lt;span style=&#34;font-weight:bold&#34;&gt;doto &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;player&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                      (&lt;span style=&#34;font-weight:bold&#34;&gt;tset &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                      (&lt;span style=&#34;font-weight:bold&#34;&gt;tset &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                      (&lt;span style=&#34;font-weight:bold&#34;&gt;tset &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:spawn-x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                      (&lt;span style=&#34;font-weight:bold&#34;&gt;tset &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:spawn-y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    (&lt;span style=&#34;font-weight:bold&#34;&gt;doto &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;camera&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                      (&lt;span style=&#34;font-weight:bold&#34;&gt;tset &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:x&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;* &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; 8))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                      (&lt;span style=&#34;font-weight:bold&#34;&gt;tset &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:y&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;* &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt; 8)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;world&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:add&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;player&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;player.x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;player.y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;player.w&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;player.h&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:speed-up&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;obj&lt;/span&gt; {&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:h&lt;/span&gt; 8 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:w&lt;/span&gt; 8 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:cross&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:handle&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;target&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                             (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;world&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:remove&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                             (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mset&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;// &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self.x&lt;/span&gt; 8) (&lt;span style=&#34;font-weight:bold&#34;&gt;// &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self.y&lt;/span&gt; 8) 0)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                             (&lt;span style=&#34;font-weight:bold&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;target.max-xvel&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;target.max-xvel&lt;/span&gt; 1)))}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;world&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:add&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;obj&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;obj.x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;obj.y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;obj.w&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;obj.h&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:jump-up&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;obj&lt;/span&gt; {&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:h&lt;/span&gt; 8 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:w&lt;/span&gt; 8 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:cross&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:handle&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;target&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;world&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:remove&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mset&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;// &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self.x&lt;/span&gt; 8) (&lt;span style=&#34;font-weight:bold&#34;&gt;// &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self.y&lt;/span&gt; 8) 0)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                     (&lt;span style=&#34;font-weight:bold&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;target.jump-vel&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;- &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;target.jump-vel&lt;/span&gt; 2)))}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;world&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:add&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;obj&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;obj.x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;obj.y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;obj.w&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;obj.h&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;solid?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;obj&lt;/span&gt; {&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:h&lt;/span&gt; 8 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:w&lt;/span&gt; 8}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;world&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:add&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;obj&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;obj.x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;obj.y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;obj.w&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;obj.h&lt;/span&gt;)))))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It&amp;rsquo;s a simple loop that goes over each map tile, and decides if it is a thing that we need to register in bump&amp;rsquo;s &lt;code&gt;world&lt;/code&gt;.
To decide that I use a combination of tile ids and flags.
It&amp;rsquo;s called at the start of the game, and loads the map once.&lt;/p&gt;
&lt;p&gt;Finally, the most convoluted part was the player controller:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;player.update&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_transition-target&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;grounded?&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;grounded?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;collision-filter&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;wall-bound?&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;wall-bound?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;collision-filter&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;echoes&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:update&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;when &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bonk?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;collision-filter&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self.yvel&lt;/span&gt; 0))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;grounded?&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self.yvel&lt;/span&gt; 0)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;apply-gravity&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;wall-bound?&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;and &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;btn&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;right&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;grounded?&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;not &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;wall-bound?&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold&#34;&gt;doto &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;font-weight:bold&#34;&gt;tset &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:flip&lt;/span&gt; 1)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;font-weight:bold&#34;&gt;tset &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:xvel&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lerp&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self.xvel&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;wall-bound?&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;/ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self.max-xvel&lt;/span&gt; 5) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self.max-xvel&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;grounded?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;acc&lt;/span&gt; 0.01))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold&#34;&gt;and &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;btn&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;left&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;grounded?&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;not &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;wall-bound?&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold&#34;&gt;doto &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;font-weight:bold&#34;&gt;tset &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:flip&lt;/span&gt; -1)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;font-weight:bold&#34;&gt;tset &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:xvel&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lerp&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self.xvel&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;wall-bound?&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;/ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self.max-xvel&lt;/span&gt; -5) (&lt;span style=&#34;font-weight:bold&#34;&gt;- &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self.max-xvel&lt;/span&gt;)) (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;grounded?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;acc&lt;/span&gt; 0.01))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;grounded?&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;wall-bound?&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;font-weight:bold&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self.xvel&lt;/span&gt; 0)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              (&lt;span style=&#34;font-weight:bold&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self.xvel&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;snap-to-zero&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;round&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lerp&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self.xvel&lt;/span&gt; 0 0.1)))))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;when &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;or &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;btnp&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;A&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;btnp&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;B&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;btnp&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;X&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;btnp&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Y&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;grounded?&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;font-weight:bold&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self.yvel&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self.jump-vel&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;wall-bound?&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;font-weight:bold&#34;&gt;doto &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;font-weight:bold&#34;&gt;tset &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:flip&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;- &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self.flip&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;font-weight:bold&#34;&gt;tset &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:xvel&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self.xvel&lt;/span&gt; 0)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            (&lt;span style=&#34;font-weight:bold&#34;&gt;* &lt;/span&gt;3 (&lt;span style=&#34;font-weight:bold&#34;&gt;- &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;wall-bound?&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            (&lt;span style=&#34;font-weight:bold&#34;&gt;- &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self.xvel&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;font-weight:bold&#34;&gt;tset &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:yvel&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;* &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self.jump-vel&lt;/span&gt; 0.75)))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cols&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;len&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;world&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:move&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self.x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self.xvel&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self.y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self.yvel&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;collision-filter&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;for &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;len&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[{&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;other&lt;/span&gt;} (&lt;span style=&#34;font-weight:bold&#34;&gt;. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cols&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;other.handle&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;other&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:handle&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self.x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self.y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This is again a method in the &lt;code&gt;player&lt;/code&gt; object, which holds some state, like coordinates and other attributes of the player, like max speed.
It&amp;rsquo;s fairly simple right now, but it&amp;rsquo;ll get worse in the future days.&lt;/p&gt;
&lt;p&gt;One of the things you may have noticed was a trail effect, when the player reaches a certain speed.
I wanted it in the game, inspired by Super Metroid&amp;rsquo;s speed booster effect.
However, my small brain couldn&amp;rsquo;t figure out how to do it properly, so I simply used linear interpolation so each echo lags behind the player object just enough, and used time offsets to delay their animations.
Later, I realized that I can do it simply by storing last player position every few frames and drawing the echo this way, but I had no time to fix it.&lt;/p&gt;
&lt;p&gt;The animation system is another thing I needed to make myself, as TIC doesn&amp;rsquo;t have anything like that.
There&amp;rsquo;s a popular library for doing that, called &lt;a href=&#34;https://github.com/kikito/anim8&#34; target=&#34;_blank&#34;&gt;anim8&lt;/a&gt;, by the same author of bump.lua.
I didn&amp;rsquo;t use it, as I had to learn it, and wasn&amp;rsquo;t sure if it&amp;rsquo;s compatible with TIC at all.&lt;/p&gt;
&lt;p&gt;So my animation system is as follows:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;draw-anim&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;flip?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;speed&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;when &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;= &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;% &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;speed&lt;/span&gt;) 0)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self.frame&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;% &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self.frame&lt;/span&gt; 1) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self.frames&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;spr&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self.start&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;* &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self.frame&lt;/span&gt; 2)) (&lt;span style=&#34;font-weight:bold&#34;&gt;- &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; 4) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt; 0 1 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;flip?&lt;/span&gt; 0 2 2))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;run-anim&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:start&lt;/span&gt; 258
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:end&lt;/span&gt; 268
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:frames&lt;/span&gt; 6
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:frame&lt;/span&gt; 0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:draw&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;draw-anim&lt;/span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;jump-anim&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:start&lt;/span&gt; 288
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:end&lt;/span&gt; 302
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:frames&lt;/span&gt; 8
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:frame&lt;/span&gt; 0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:draw&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;draw-anim&lt;/span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; etc&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In the &lt;code&gt;player.draw&lt;/code&gt; method I call this depending on the player&amp;rsquo;s state:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;player.draw&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;camera&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:translate&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self.x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self.y&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;flip?&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;&amp;lt; &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self.flip&lt;/span&gt; 0) 1 0)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;echoes&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:draw&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;&amp;lt;= &lt;/span&gt;0 (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;m/abs&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self.xvel&lt;/span&gt;) 0.01)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;not= &lt;/span&gt;0 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self.yvel&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;slow-jump-anim&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:draw&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;flip?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;player&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;idle-anim&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:draw&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;flip?&lt;/span&gt; 60))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold&#34;&gt;not &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;grounded?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;case&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;wall-bound?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;player&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          1 (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;spr&lt;/span&gt; 256 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt; 0 1 1 0 1 2)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          -1 (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;spr&lt;/span&gt; 256 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt; 0 1 0 0 1 2)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;&amp;gt; &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;m/abs&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self.xvel&lt;/span&gt;) 3)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;jump-anim&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:draw&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;flip?&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;m/floor&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lerp&lt;/span&gt; 10 1 (&lt;span style=&#34;font-weight:bold&#34;&gt;/ &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;m/abs&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self.xvel&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;m/abs&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self.max-xvel&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;slow-jump-anim&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:draw&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;flip?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;player&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;run-anim&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:draw&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;flip?&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;m/floor&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lerp&lt;/span&gt; 10 3 (&lt;span style=&#34;font-weight:bold&#34;&gt;/ &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;m/abs&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self.xvel&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;m/abs&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self.max-xvel&lt;/span&gt;))))))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As you can see, I don&amp;rsquo;t yet have a state machine or anything like it in my player object, which I fixed in later days.
However, this was enough to make the animations you&amp;rsquo;ve seen in the video.&lt;/p&gt;
&lt;p&gt;Animation speed is determined by the &lt;code&gt;speed&lt;/code&gt; parameter, which is named incorrectly, as it is more of an update interval in frames.
I use linear interpolation to play animations faster when player&amp;rsquo;s speed increases, interpolating from &lt;code&gt;10&lt;/code&gt; tics to &lt;code&gt;1&lt;/code&gt; tic.
Each frame is &lt;code&gt;60&lt;/code&gt; tics.&lt;/p&gt;
&lt;h2 id=&#34;day-2&#34;&gt;Day 2&lt;/h2&gt;
&lt;p&gt;Second day I focused on improving animations, as currently they look very janky.&lt;/p&gt;
&lt;p&gt;I have Aseprite installed, so I picked up my drawing tablet and sat down working on the run animation.
Or I would have done that if Wacom wasn&amp;rsquo;t a piece of crap.&lt;/p&gt;
&lt;p&gt;I had to install drivers, but not just any drivers - the newest drivers are incompatible with my rather old tablet.
They are quite big size-wise, and with slow internet it was a pain, since I blindly downloaded the latest driver, and was met with a message, that I should upgrade my device.
Luckily, the official web page still has a working driver for my OS and tablet combination, but I was afraid for a second that I would have to resort to using my phone.
Not that it is a problem, but I wanted to try Aseprite for this project.&lt;/p&gt;
&lt;p&gt;The result is as follows:&lt;/p&gt;
&lt;p&gt;&lt;video autoplay loop muted&gt;&lt;source src=&#34;https://andreyor.st/2026-05-24-spring-lisp-game-jam-2026/day-2.mp4&#34; type=&#34;video/mp4&#34;&gt;
Your browser does not support the video tag.&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;I also added sliding animation, and spikes, as no platformer is complete without spikes, am I right or am I right?&lt;/p&gt;
&lt;p&gt;Jumping also has two states now - a slow jump, and a fast jump, each with their own animation.
For slow jumps the player sprite is mostly static, changing only when the vertical velocity goes from negative to positive.
When a certain amount of speed is reached, however, the jump changes into a Salto Mortale mode, where the player spins frantically, like Samus Aran.
Did I mention that Metroid was a huge inspiration for me this time around?&lt;/p&gt;
&lt;p&gt;In addition to sliding, I added wall slide, which is not only a visual aid, but also slows you down when falling a bit.&lt;/p&gt;
&lt;h2 id=&#34;day-3&#34;&gt;Day 3&lt;/h2&gt;
&lt;p&gt;I felt satisfied with my player controller so far, so I started working on the level itself.
This includes decorations, and level design in general.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s what I got by the end of day three:&lt;/p&gt;
&lt;p&gt;&lt;video autoplay loop muted&gt;&lt;source src=&#34;https://andreyor.st/2026-05-24-spring-lisp-game-jam-2026/day-3.mp4&#34; type=&#34;video/mp4&#34;&gt;
Your browser does not support the video tag.&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;I designed a few tiles for the ground and walls, as well as variants for different biomes:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2026-05-24-spring-lisp-game-jam-2026/day-3-tiles.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;It&amp;rsquo;s hard to show the whole map in TIC, so here&amp;rsquo;s a screenshot from the built-in overview:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2026-05-24-spring-lisp-game-jam-2026/day-3-map.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;Aesthetics for this game were inspired by the palette I&amp;rsquo;ve chosen, and by the game Animal Well, which I&amp;rsquo;ve played recently.
Or at least I wanted to think that way, as I liked the artstyle, and limited resolution of that game.&lt;/p&gt;
&lt;h2 id=&#34;days-4-7&#34;&gt;Days 4-7&lt;/h2&gt;
&lt;p&gt;The rest of the days I&amp;rsquo;ve been working on the level design.
I even started to plan out the level on a piece of paper, like so:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2026-05-24-spring-lisp-game-jam-2026/plan.jpg&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;Here&amp;rsquo;s map progress by day:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2026-05-24-spring-lisp-game-jam-2026/day-4.png&#34;
         alt=&#34;Figure 1: Day 4&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 1: &lt;/span&gt;Day 4&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2026-05-24-spring-lisp-game-jam-2026/day-4-2.png&#34;
         alt=&#34;Figure 2: Day 4, again&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 2: &lt;/span&gt;Day 4, again&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2026-05-24-spring-lisp-game-jam-2026/day-5.png&#34;
         alt=&#34;Figure 3: Day 5&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 3: &lt;/span&gt;Day 5&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2026-05-24-spring-lisp-game-jam-2026/day-6.png&#34;
         alt=&#34;Figure 4: Day 6&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 4: &lt;/span&gt;Day 6&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;At some point I completed the paper plan:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2026-05-24-spring-lisp-game-jam-2026/full-plan.jpg&#34;/&gt;
&lt;/figure&gt;

&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2026-05-24-spring-lisp-game-jam-2026/day-7.png&#34;
         alt=&#34;Figure 5: Day 7&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 5: &lt;/span&gt;Day 7&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2026-05-24-spring-lisp-game-jam-2026/day-8.png&#34;
         alt=&#34;Figure 6: Day 8&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 6: &lt;/span&gt;Day 8&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;I was ready to start working on the last bit of the map, when I realized that I made a mistake.
My plan contained an extra row on top, when in reality I had just two more.&lt;/p&gt;
&lt;p&gt;This meant that I had to trim down the last section, as I couldn&amp;rsquo;t really throw anything from the middle section, and it wouldn&amp;rsquo;t make sense to make the top section penetrate down.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2026-05-24-spring-lisp-game-jam-2026/day-9.png&#34;
         alt=&#34;Figure 7: Day 9&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 7: &lt;/span&gt;Day 9&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Still, I had the full map complete by day nine, out of ten days available for the jam.
A bit of a close call, but I could release this game any time, as it is essentially complete now.&lt;/p&gt;
&lt;p&gt;During these days I also made a main menu screen, and the end screen.
The end screen feels a bit barebones, but I had no time to do anything more with it, as I still had to do the most difficult part - sounds and music.&lt;/p&gt;
&lt;h2 id=&#34;sfx&#34;&gt;SFX&lt;/h2&gt;
&lt;p&gt;Sound effects weren&amp;rsquo;t as hard, when it comes to the player itself.
I&amp;rsquo;m using simple effects for steps, jumps, and slides based on white noise that TIC provides.
Timing them to animation frames is easy enough, as I can call &lt;code&gt;sfx&lt;/code&gt; from the animation pipeline itself.&lt;/p&gt;
&lt;p&gt;Because of that, things like steps are actually in sync with the animation, which I like.
However, in the browser the sound may lag, I don&amp;rsquo;t really know why, but it did for all my previous games.
Maybe it also depends on the browser.&lt;/p&gt;
&lt;h2 id=&#34;day-10-music&#34;&gt;Day 10 - Music&lt;/h2&gt;
&lt;p&gt;As I usually do, I left the hardest part to the last day.
If I fail at it, I won&amp;rsquo;t include it in the game, and release it as is - it&amp;rsquo;s still a complete game.
But, if I succeed, the game will be a bit better.&lt;/p&gt;
&lt;p&gt;Music composition is not of my top skills, I&amp;rsquo;d say I&amp;rsquo;m pretty bad at it.
There are few reasons for that, first and foremost being it&amp;rsquo;s so clunky to do that on a computer.
If I had a MIDI keyboard, or an iPad with GarageBand, I think I would spend more time doing that.&lt;/p&gt;
&lt;p&gt;So I reached out to &lt;a href=&#34;https://whoisthatdf.bandcamp.com/&#34; target=&#34;_blank&#34;&gt;a friend&lt;/a&gt; with whom we did a &lt;a href=&#34;https://www.youtube.com/watch?v=y9Mt3EJ6d4k&#34; target=&#34;_blank&#34;&gt;collaboration&lt;/a&gt; before, and asked them to help me out.
They were kind enough to provide me with an original piece, which I had to port to TIC with the best of my ability.&lt;/p&gt;
&lt;p&gt;TIC&amp;rsquo;s music tracker is a bit weird, and very limiting for someone who&amp;rsquo;s not versatile enough with trackers in general.&lt;/p&gt;
&lt;p&gt;Adapting the song was quite a challenge for me.
First of all, the song was written in non-tracker software, as MIDI.
Having a piano-roll view of it helped with adapting, but some of the effects that were used were hard to recreate, so I did my best.&lt;/p&gt;
&lt;p&gt;For example, delay.
I had to create a wave that modulated its volume to act like its two notes repeating after a short delay.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2026-05-24-spring-lisp-game-jam-2026/sfx.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;Then there were drums.
I need to mention that I&amp;rsquo;m limited by three channels out of four available.
One channel is reserved for in-game sound effects, like steps, jumps, powerups, etc.
This leaves me with three channels for music.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2026-05-24-spring-lisp-game-jam-2026/tracker.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;I used the first channel for the lead melody, second one for the bass, and the third one for the drum beat.
Drums proved that it&amp;rsquo;s not really feasible to do them in one channel.
You can&amp;rsquo;t overlay two samples, like in a modern MIDI editor.
So you have to choose between kick and snare.
Or snare and cymbal.
Or kick and cymbal.
You get the idea.&lt;/p&gt;
&lt;h2 id=&#34;the-game&#34;&gt;The game&lt;/h2&gt;
&lt;p&gt;Anyway, this concludes this dev log, and the game is now available on &lt;a href=&#34;https://andreyorst.itch.io/speed&#34; target=&#34;_blank&#34;&gt;itch.io&lt;/a&gt;.
If you like it, consider voting for it on the &lt;a href=&#34;https://itch.io/jam/spring-lisp-game-jam-2026/rate/4606269&#34; target=&#34;_blank&#34;&gt;jam&amp;rsquo;s page&lt;/a&gt;.
And if you wish to download it, here&amp;rsquo;s the cart:&lt;/p&gt;
&lt;figure class=&#34;pixelart&#34;&gt;&lt;img src=&#34;https://andreyor.st/2026-05-24-spring-lisp-game-jam-2026/speed.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;I can complete this game in about 10 minutes, but I think it&amp;rsquo;ll take a fair bit more time for players unfamiliar with it.
After all, I spent a lot of time playing this game during development, and I know it pretty well.&lt;/p&gt;
&lt;p&gt;I know that some levels in this game are probably very janky.
Many jumps are probably not as obvious as they should have been, or unnecessarily hard.
I&amp;rsquo;ve had no time to get this game play-tested by other people, so that&amp;rsquo;s that.
Still, I fixed the most annoying places that drove even me nuts.
And overall, I&amp;rsquo;m satisfied with what I made.&lt;/p&gt;
&lt;p&gt;I hope you like this game, but don&amp;rsquo;t forget to check other submissions too!
If you&amp;rsquo;re a fellow participant, I wish you luck, and let&amp;rsquo;s see who&amp;rsquo;s gonna be the winner!
And if not, I encourage you to try it next year.
It&amp;rsquo;s fun :)&lt;/p&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: Spring Lisp Game Jam 2026&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Sun, 24 May 2026 08:08:00 +0300</pubDate>
    </item><item>
      <title>Clojure on Fennel part three: parsing</title>
      <link>https://andreyor.st/posts/2026-04-27-clojure-on-fennel-part-three-parsing/</link>
      <guid>https://andreyor.st/posts/2026-04-27-clojure-on-fennel-part-three-parsing/</guid>
      <description>&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://andreyor.st/posts/2026-04-07-clojure-on-fennel-part-one-persistent-data-structures/&#34;&gt;part one: persistent data structures&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://andreyor.st/posts/2026-04-15-clojure-on-fennel-part-two-immutablefnl-optimizations/&#34;&gt;part two: immutable.fnl optimizations&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;part three: parsing&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://andreyor.st/posts/2026-06-29-clojure-on-fennel-part-four-parsing-again/&#34;&gt;part four: parsing (again)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The two previous posts were not related to the compiler itself, but were kicked off by the start of the compiler development.
I&amp;rsquo;d say this project was the reason that I made proper immutable data structures for Fennel and Lua.
But now we&amp;rsquo;re finally going to talk about the compiler itself!
And we&amp;rsquo;ll start with the parsing stage - transforming Clojure code into something that can be operated on by the compiler.&lt;/p&gt;
&lt;h2 id=&#34;manual-single-pass-parser-and-compiler&#34;&gt;Manual single-pass parser and compiler&lt;/h2&gt;
&lt;p&gt;When I started this project, as I usually do, I underestimated the complexity at hand.
My first attempt was a single-pass compiler that accepted a stream of characters of Clojure code and re-compiled it on the fly.&lt;/p&gt;
&lt;p&gt;My idea was to write a simple recursive-descent parser that, when accepting a character would decide how to translate it to Fennel, assuming my &lt;a href=&#34;https://gitlab.com/andreyorst/fennel-cljlib&#34; target=&#34;_blank&#34;&gt;fennel-cljlib&lt;/a&gt; library handled most of the semantics.
So, for example, when encountering &lt;code&gt;[&lt;/code&gt; it would translate it to &lt;code&gt;(cljlib.vector&lt;/code&gt; and thus &lt;code&gt;[1 2 3]&lt;/code&gt; would descend to &lt;code&gt;compile-vector&lt;/code&gt; and expand to &lt;code&gt;(cljlib.vector 1 2 3)&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The idea is simple, and at first I thought that it would suffice, but then I remembered that there are a lot of other things in Clojure that I have to consider.
For example &lt;code&gt;#_&lt;/code&gt; - the ignore form syntax, and &lt;code&gt;^foo&lt;/code&gt; - the metadata syntax.
This complicated things a lot, so I added initial support for them and moved on - because I decided that this will be a bootstrap compiler for a proper Clojure parser.&lt;/p&gt;
&lt;h2 id=&#34;clojure-parsers&#34;&gt;Clojure parsers&lt;/h2&gt;
&lt;p&gt;After some time I &lt;a href=&#34;https://gitlab.com/andreyorst/clojurefnl/-/commit/b42b79f7b77f7f1489c3a0667bf9301a0d5ccb10&#34; target=&#34;_blank&#34;&gt;had a compiler&lt;/a&gt; that could compile most of the arbitrary code I threw at it.
Of course, it was not exactly to the Clojure spec, but it worked and I was going to replace it anyway.
So I started looking at available Clojure parsers written in Clojure.&lt;/p&gt;
&lt;h3 id=&#34;edamame&#34;&gt;Edamame&lt;/h3&gt;
&lt;p&gt;I started with &lt;a href=&#34;https://github.com/borkdude/edamame&#34; target=&#34;_blank&#34;&gt;Edamame&lt;/a&gt;.
The choice was based on the fact that the &lt;a href=&#34;https://github.com/squint-cljs/squint&#34; target=&#34;_blank&#34;&gt;Squint&lt;/a&gt; project uses it and my project is similar to Squint, or so I thought.
This parser is also used in &lt;a href=&#34;https://github.com/babashka/sci&#34; target=&#34;_blank&#34;&gt;SCI&lt;/a&gt; - a Clojure interpreter, so it seemed like a good fit.&lt;/p&gt;
&lt;p&gt;The first thing I did was &lt;a href=&#34;https://gitlab.com/andreyorst/clojurefnl/-/commit/da15660171e8b2411679d5aa5a90ef7020eb5b84&#34; target=&#34;_blank&#34;&gt;make sure that Edamame at least compiles&lt;/a&gt; with my bootstrap compiler.
The fact that it compiles doesn&amp;rsquo;t mean that it works - it just translated everything into Fennel, with bits of cljlib here and there.
So the next step was to make it work.&lt;/p&gt;
&lt;p&gt;But then I had a realization that I don&amp;rsquo;t need to do that at all - I could just parse Edamame with Edamame, and write a compiler against its output!
Meaning, I could use Edamame&amp;rsquo;s parser directly until my compiler is complete enough to compile Edamame.
And since my idea was to replace bootstrap compiler in the end anyway, I decided that it doesn&amp;rsquo;t make much sense to make it work enough to fully compile Edamame into a runnable Fennel code.
So I used Edamame to parse Edamame, and got back&amp;hellip;&lt;/p&gt;
&lt;p&gt;&amp;hellip; the same Edamame source.&lt;/p&gt;
&lt;p&gt;Imagine my face when I realized that Edamame doesn&amp;rsquo;t produce an abstract syntax tree with all information, but instead it just produces Clojure data structures, such as lists, vectors, and other stuff.
And all of the information about the source code sits inside metadata of these data structures, not in the output.
Yes, it does transform some Clojure forms into lists, like &lt;code&gt;@foo&lt;/code&gt; is transformed into &lt;code&gt;(deref foo)&lt;/code&gt;, but that&amp;rsquo;s still nothing to me, because Fennel has no list data type and its support for metadata is nowhere near compatibility with Clojure.&lt;/p&gt;
&lt;p&gt;I get it, I should have read the readme with more attention, and don&amp;rsquo;t make assumptions based on wild guesses, so it&amp;rsquo;s fine.
Still, I wasn&amp;rsquo;t dropping the idea to use an existing Clojure parser, and the bootstrap compiler combo.
I just need a different parser.&lt;/p&gt;
&lt;h3 id=&#34;rewrite-clj&#34;&gt;Rewrite-clj&lt;/h3&gt;
&lt;p&gt;Next one I looked at was &lt;a href=&#34;https://github.com/clj-commons/rewrite-clj&#34; target=&#34;_blank&#34;&gt;rewrite-clj&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This library does return a tree of objects.
It&amp;rsquo;s still a list, but at least it contains nodes that can be translated into Fennel objects.
However, it still had a few problems.&lt;/p&gt;
&lt;p&gt;First, its source code is much bigger than that of Edamame.
Its API is more complicated, and it expects the use of Zippers, which I don&amp;rsquo;t yet have in cljlib.
I didn&amp;rsquo;t want such a big parser for my compiler, given that it&amp;rsquo;s job is quite simple - produce an AST that I will always walk in full.&lt;/p&gt;
&lt;p&gt;Second, it&amp;rsquo;s still producing some Clojure data structures that I can&amp;rsquo;t cleanly map to Fennel, so it would mean that the compiler itself would depend on cljlib.
And I didn&amp;rsquo;t want that.&lt;/p&gt;
&lt;p&gt;Luckily for me, their user guide mentioned another parser.&lt;/p&gt;
&lt;h3 id=&#34;parcera&#34;&gt;Parcera&lt;/h3&gt;
&lt;p&gt;Finally, &lt;a href=&#34;https://github.com/carocad/parcera&#34; target=&#34;_blank&#34;&gt;parcera&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Looking at the readme, I finally saw what I wanted to see:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;ns &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;example.core&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:require&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parcera.core&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:as&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parcera&lt;/span&gt;]))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;;parse clojure code from a string&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parcera/ast&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;str &lt;/span&gt;&amp;#39;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;ns &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parcera.core&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                     (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:require&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure.data&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:as&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                               [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure.string&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:as&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;str&lt;/span&gt;]))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; =&amp;gt; returns a data structure with the result from the parser&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:code&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:list&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:symbol&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;ns&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:whitespace&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:symbol&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;parcera.core&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:whitespace&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:list&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:keyword&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;:require&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:whitespace&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:vector&lt;/span&gt; (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:symbol&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;clojure.data&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:whitespace&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:keyword&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;:as&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:whitespace&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:symbol&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;data&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:whitespace&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:vector&lt;/span&gt; (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:symbol&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;clojure.string&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:whitespace&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:keyword&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;:as&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:whitespace&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:symbol&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;str&amp;#34;&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Tagged tree.
Yes, it&amp;rsquo;s still a list, but at least this can be easily mapped to Fennel sequential tables.
So I opened the code and&amp;hellip;&lt;/p&gt;
&lt;p&gt;&amp;hellip;there&amp;rsquo;s nothing there!
Turns out, this project uses an ANTLR grammar for parsing Clojure.&lt;/p&gt;
&lt;p&gt;At this point I was quite frustrated with the fact that there&amp;rsquo;s no single Clojure parser that could provide something similar to what parcera provides, but written in pure Clojure.
Or at least in Java, which I could hand-translate as a last resort.
Yes, there&amp;rsquo;s a Clojure parser inside the Clojure project itself, written in Java, but my goal was to recompile an existing parser written in Clojure.&lt;/p&gt;
&lt;h2 id=&#34;grammar-based-parser&#34;&gt;Grammar-based parser&lt;/h2&gt;
&lt;p&gt;After a bit of consideration, I decided that a grammar-based approach is not that bad of an idea after all.
I couldn&amp;rsquo;t use the ANTLR grammar directly, but at least I had it, and it seemed complete enough.&lt;/p&gt;
&lt;p&gt;In Lua there&amp;rsquo;s a great library called &lt;a href=&#34;https://www.inf.puc-rio.br/~roberto/lpeg/&#34; target=&#34;_blank&#34;&gt;LPeg&lt;/a&gt; that can generate parsers at runtime from a PEG grammar, and I wanted to try it out for quite some time.
But to do that I needed a PEG grammar for Clojure.
ANTLR and PEG are quite different, but it&amp;rsquo;s not impossible to translate one grammar into another.&lt;/p&gt;
&lt;p&gt;So that&amp;rsquo;s what I did:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Clojure PEG Grammar
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Adapted from https://github.com/carocad/parcera (ANTLR4 grammar v0.11.6)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Key differences:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# - Unlike ANTLR, PEG choices are ordered (/).
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#   More specific alternatives need to come first.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# - No separate lexer phase.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#   All rules operate on characters directly.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# - ANTLR fragment rules are prefixed with &amp;#39;_&amp;#39;.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# - ANTLR&amp;#39;s SENTINEL (catch-all for invalid tokens) has no direct PEG equivalent.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#   The parser will silently fail on invalid input.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Parser rules
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;code        &amp;lt;- input* !.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;input       &amp;lt;- ignore / form
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ignore      &amp;lt;- whitespace / comment / discard
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;form        &amp;lt;- literal / collection / reader_macro
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# sets and namespaced maps are under dispatch (they start with #)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;collection  &amp;lt;- list / vector / map
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;list        &amp;lt;- &amp;#39;(&amp;#39; input* &amp;#39;)&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;vector      &amp;lt;- &amp;#39;[&amp;#39; input* &amp;#39;]&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;map         &amp;lt;- &amp;#39;{&amp;#39; input* &amp;#39;}&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# macro_keyword before keyword (&amp;#39;::&amp;#39; is longer than &amp;#39;:&amp;#39;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;literal     &amp;lt;- macro_keyword / keyword / string / number / character / symbol
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;keyword       &amp;lt;- KEYWORD
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;macro_keyword &amp;lt;- MACRO_KEYWORD
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;string        &amp;lt;- STRING
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# ordering: most-specific prefix first; LONG last (least specific)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;number        &amp;lt;- HEXADECIMAL / OCTAL / RADIX / DOUBLE / RATIO / LONG
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# NAMED_CHAR first (longest); UNICODE before UNICODE_CHAR (more specific)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;character     &amp;lt;- NAMED_CHAR / OCTAL_CHAR / UNICODE / UNICODE_CHAR
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;symbol        &amp;lt;- SYMBOL
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# unquote_splicing before unquote (&amp;#39;~@&amp;#39; vs &amp;#39;~&amp;#39;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;reader_macro &amp;lt;- unquote_splicing
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              / unquote
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              / metadata
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              / backtick
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              / quote
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              / dispatch
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              / deref
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;metadata &amp;lt;- ((metadata_entry / deprecated_metadata_entry) ignore*)+
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            ( symbol
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            / collection
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            / set
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            / namespaced_map
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            / tag
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            / fn
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            / unquote_splicing
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            / unquote
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            / conditional_splicing
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            / conditional
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            / deref
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            / quote
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            / backtick
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            / var_quote
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            )
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;metadata_entry            &amp;lt;- &amp;#39;^&amp;#39; ignore* (map / symbol / string / keyword / macro_keyword / conditional)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# #^ is deprecated syntax for metadata
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;deprecated_metadata_entry &amp;lt;- &amp;#39;#^&amp;#39; ignore* (map / symbol / string / keyword / macro_keyword / conditional)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;backtick          &amp;lt;- &amp;#39;`&amp;#39; ignore* form
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;quote             &amp;lt;- &amp;#34;&amp;#39;&amp;#34; ignore* form
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# negative lookahead prevents &amp;#39;~&amp;#39; from matching when &amp;#39;~@&amp;#39; follows
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;unquote           &amp;lt;- &amp;#39;~&amp;#39; !&amp;#39;@&amp;#39; ignore* form
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;unquote_splicing  &amp;lt;- &amp;#39;~@&amp;#39; ignore* form
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;deref             &amp;lt;- &amp;#39;@&amp;#39; ignore* form
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# conditional_splicing before conditional (&amp;#39;#?@&amp;#39; vs &amp;#39;#?&amp;#39;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# tag last (most general: &amp;#39;#&amp;#39; + symbol)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;dispatch &amp;lt;- conditional_splicing
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          / conditional
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          / set
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          / namespaced_map
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          / fn
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          / regex
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          / var_quote
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          / symbolic
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          / eval
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          / tag
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# no whitespace allowed between &amp;#39;#&amp;#39; and the delimiter
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;fn                    &amp;lt;- &amp;#39;#&amp;#39; list
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;regex                 &amp;lt;- &amp;#39;#&amp;#39; STRING
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;set                   &amp;lt;- &amp;#39;#{&amp;#39; input* &amp;#39;}&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;namespaced_map        &amp;lt;- &amp;#39;#&amp;#39; (macro_keyword / keyword / auto_resolve) ignore* map
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;auto_resolve          &amp;lt;- &amp;#39;::&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;var_quote             &amp;lt;- &amp;#34;#&amp;#39;&amp;#34; ignore* form
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;discard               &amp;lt;- &amp;#39;#_&amp;#39; ignore* form
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;tag                   &amp;lt;- &amp;#39;#&amp;#39; symbol ignore* form
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;conditional           &amp;lt;- &amp;#39;#?&amp;#39; whitespace* list
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;conditional_splicing  &amp;lt;- &amp;#39;#?@&amp;#39; whitespace* list
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# ##Inf, ##-Inf, ##NaN  (allows arbitrary symbolic values)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;symbolic              &amp;lt;- &amp;#39;##&amp;#39; ignore* SYMBOL
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;eval                  &amp;lt;- &amp;#39;#=&amp;#39; ignore* (symbol / list / conditional)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;whitespace &amp;lt;- WHITESPACE
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;comment    &amp;lt;- COMMENT
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Lexical rules (terminals)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;HEXADECIMAL &amp;lt;- _SIGN? &amp;#39;0&amp;#39; [xX] [0-9A-Fa-f]+ _BIG_INT?
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;OCTAL       &amp;lt;- _SIGN? &amp;#39;0&amp;#39; [0-7]+ _BIG_INT?
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# base 2-36, then r/R, then digits in that base
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;RADIX       &amp;lt;- _SIGN? ([2-9] / [12] [0-9] / &amp;#39;3&amp;#39; [0-6]) [rR] [0-9a-zA-Z]+
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;RATIO       &amp;lt;- _SIGN? _DIGIT+ &amp;#39;/&amp;#39; _DIGIT+
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;LONG        &amp;lt;- _SIGN? _DECIMAL _BIG_INT?
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# FRACTION EXPONENT before FRACTION alone (longer match first)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;DOUBLE      &amp;lt;- _SIGN? _DECIMAL+ ((_FRACTION _EXPONENT / _FRACTION / _EXPONENT) &amp;#39;M&amp;#39;? / &amp;#39;M&amp;#39;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;_BIG_INT  &amp;lt;- &amp;#39;N&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;_FRACTION &amp;lt;- &amp;#39;.&amp;#39; _DIGIT*
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;_EXPONENT &amp;lt;- [eE] _SIGN? _DIGIT+
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;_DECIMAL  &amp;lt;- &amp;#39;0&amp;#39; / [1-9] _DIGIT*
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;STRING &amp;lt;- &amp;#39;&amp;#34;&amp;#39; ([^&amp;#34;\\] / &amp;#39;\\&amp;#39; .)* &amp;#39;&amp;#34;&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# \p{White_Space} approximation
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;WHITESPACE &amp;lt;- [ \t\n\r\f,]+
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;COMMENT &amp;lt;- (&amp;#39;;&amp;#39; / &amp;#39;#!&amp;#39;) [^\r\n]*
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Named characters must not be followed by name-chars (word boundary)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;NAMED_CHAR   &amp;lt;- &amp;#39;\\&amp;#39; (&amp;#39;newline&amp;#39; / &amp;#39;return&amp;#39; / &amp;#39;space&amp;#39; / &amp;#39;tab&amp;#39; / &amp;#39;formfeed&amp;#39; / &amp;#39;backspace&amp;#39;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                !(_ALLOWED_NAME_CHARACTER / _DIGIT)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;UNICODE      &amp;lt;- &amp;#39;\\&amp;#39; &amp;#39;u&amp;#39; [0-9a-fA-F] [0-9a-fA-F] [0-9a-fA-F] [0-9a-fA-F]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                !(_ALLOWED_NAME_CHARACTER / _DIGIT)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# octal char: 0-377; longest alternative first
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;OCTAL_CHAR   &amp;lt;- &amp;#39;\\&amp;#39; &amp;#39;o&amp;#39; ([0-3] [0-7] [0-7] / [0-7] [0-7] / [0-7])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                !(_ALLOWED_NAME_CHARACTER / _DIGIT)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# any single non-combining-mark character after backslash
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;UNICODE_CHAR &amp;lt;- &amp;#39;\\&amp;#39; ![\u0300-\u036F\u1DC0-\u1DFF\u20D0-\u20FF] .
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                !(_ALLOWED_NAME_CHARACTER / _DIGIT)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# ::/ is NOT a valid macro keyword
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;MACRO_KEYWORD &amp;lt;- &amp;#39;::&amp;#39; (_SIMPLE_KEYWORD &amp;#39;/&amp;#39;)? _SIMPLE_KEYWORD
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;KEYWORD       &amp;lt;- &amp;#39;:&amp;#39; (_SIMPLE_KEYWORD &amp;#39;/&amp;#39;)? (_SIMPLE_KEYWORD / &amp;#39;/&amp;#39;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;_SIMPLE_KEYWORD &amp;lt;- _KEYWORD_HEAD _KEYWORD_BODY+
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 / _KEYWORD_HEAD
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;_KEYWORD_BODY &amp;lt;- _KEYWORD_HEAD / &amp;#39;:&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;_KEYWORD_HEAD &amp;lt;- _ALLOWED_NAME_CHARACTER / _DIGIT / [#&amp;#39;] / _SIGN
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;SYMBOL &amp;lt;- (_SIMPLE_SYMBOL &amp;#39;/&amp;#39;)? (_SIMPLE_SYMBOL / &amp;#39;/&amp;#39;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# longer alternatives first for correct PEG matching
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;_SIMPLE_SYMBOL &amp;lt;- _SIGN _SYMBOL_HEAD _SYMBOL_BODY*
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                / _ALLOWED_NAME_CHARACTER (_SYMBOL_HEAD / _DIGIT / &amp;#39;:&amp;#39;) _SYMBOL_BODY*
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                / _ALLOWED_NAME_CHARACTER
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                / _SIGN
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;_SYMBOL_BODY &amp;lt;- _SYMBOL_HEAD / _DIGIT / &amp;#39;:&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;_SYMBOL_HEAD &amp;lt;- _ALLOWED_NAME_CHARACTER / [#&amp;#39;] / _SIGN
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Characters allowed in names: everything EXCEPT reserved characters.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Equivalent to ANTLR ~[\p{White_Space},()[\]{}&amp;#34;@~^;`\\:#&amp;#39;/0-9+-]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Note: \p{White_Space} approximated with common whitespace chars here.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;_ALLOWED_NAME_CHARACTER &amp;lt;- ![ \t\n\r\f,()\[\]{}&amp;#34;@~^;`\\:#&amp;#39;/0-9+\-] .
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;_SIGN  &amp;lt;- [+\-]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;_DIGIT &amp;lt;- [0-9]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;But of course, you can&amp;rsquo;t just load a PEG grammar into LPeg.
Instead, you need to write the grammar programmatically, using LPeg&amp;rsquo;s API.
I&amp;rsquo;ll spare you the details, but here&amp;rsquo;s a &lt;a href=&#34;https://gitlab.com/andreyorst/clojurefnl/-/blob/main/src/impl/parser.fnl&#34; target=&#34;_blank&#34;&gt;full source code of the parser&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;After conversion work, I finally had a parser that could produce an AST:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;{&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parse&lt;/span&gt;} (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:impl.parser&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parse&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;(ns parcera.core
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;             (:require [clojure.data :as data]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;                       [clojure.string :as str]))&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:code&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:list&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:symbol&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;ns&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:whitespace&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:symbol&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;parcera.core&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:whitespace&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\n             &amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:list&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:keyword&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;:require&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:whitespace&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:vector&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:symbol&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;clojure.data&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:whitespace&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:keyword&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;:as&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:whitespace&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:symbol&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;data&amp;#34;&lt;/span&gt;]]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:whitespace&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\n                       &amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:vector&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:symbol&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;clojure.string&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:whitespace&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:keyword&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;:as&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:whitespace&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:symbol&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;str&amp;#34;&lt;/span&gt;]]]]]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Or not:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parse&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;(ns parcera.core
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;             (:require [clojure.data :as data]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;                       [clojure.string :as str])&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; &amp;lt;- missing &amp;#39;)&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Turns out, LPeg doesn&amp;rsquo;t have any way to report errors if the input string doesn&amp;rsquo;t match.
It simply returns &lt;code&gt;nil&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Luckily for me, there&amp;rsquo;s an additional library, called &lt;a href=&#34;https://github.com/sqmedeiros/lpeglabel&#34; target=&#34;_blank&#34;&gt;lpeglabel&lt;/a&gt; that can help with that.
It implements an extension to the LPeg library that allows defining tagged failures:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parse&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;(ns parcera.core
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;             (:require [clojure.data :as data]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;                       [clojure.string :as str])&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;unknown&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:3:49&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Parse&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;error&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;EOF&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;while &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;reading&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Expected&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;an&lt;/span&gt; &amp;#39;)&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now I have a working Clojure parser with a usable output.&lt;/p&gt;
&lt;h2 id=&#34;the-parser&#34;&gt;The parser&lt;/h2&gt;
&lt;p&gt;I mentioned before that Clojure metadata and special characters did introduce problems to my original parser.
Well, with this grammar, this is no longer an issue:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;each &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;ipairs &lt;/span&gt;[&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;@foo&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;^Foo bar&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;^{:baz true} qux&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;#_1 2&amp;#34;&lt;/span&gt;])]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pp&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parse&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:code&lt;/span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:deref&lt;/span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:symbol&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;foo&amp;#34;&lt;/span&gt;]]]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:code&lt;/span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:metadata&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:metadata-entry&lt;/span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:symbol&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Foo&amp;#34;&lt;/span&gt;]]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:whitespace&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:symbol&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;bar&amp;#34;&lt;/span&gt;]]]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:code&lt;/span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:metadata&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:metadata-entry&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:map&lt;/span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:keyword&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;:baz&amp;#34;&lt;/span&gt;] [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:whitespace&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;] [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:symbol&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;true&amp;#34;&lt;/span&gt;]]]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:whitespace&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:symbol&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;qux&amp;#34;&lt;/span&gt;]]]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:code&lt;/span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:discard&lt;/span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:number&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;1&amp;#34;&lt;/span&gt;]] [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:whitespace&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;] [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:number&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;2&amp;#34;&lt;/span&gt;]]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Yes, the parser doesn&amp;rsquo;t transform &lt;code&gt;@foo&lt;/code&gt; into &lt;code&gt;(deref foo)&lt;/code&gt;, but it&amp;rsquo;s OK, as I can handle it in the compiler easily now.
Metadata is fully supported by the parser and is stripped in the compiler.
And discard (&lt;code&gt;#_&lt;/code&gt;) actually works in all of its supported ways, i.e. &lt;code&gt;#_#_ 1 2&lt;/code&gt; works fine.&lt;/p&gt;
&lt;p&gt;Each parser result starts with &lt;code&gt;:code&lt;/code&gt;, an entry point for the compiler.
And the compiler itself is just a simple recursive descent over all of the nodes in a loop.
So, that&amp;rsquo;s good, right?&lt;/p&gt;
&lt;p&gt;Well, yes and no.
There are some cons to this approach.&lt;/p&gt;
&lt;p&gt;First, and foremost - this parser doesn&amp;rsquo;t support streaming, meaning I can&amp;rsquo;t stream chunks of code and compile them.
Well, it&amp;rsquo;s not impossible, but currently it works on strings only.
It is possible to write a second parser that would split text into top-level expressions, but for now it&amp;rsquo;s an optimization waiting to happen.
Right now, this means that files will be parsed in full - having a greater footprint in memory.&lt;/p&gt;
&lt;p&gt;Second, and arguably more important - this is a C library dependency.
Both LPeg and lpeglabel are C libraries, meaning that the compiler now works only on Lua runtimes that can load object files.
And the choice of systems where this compiler can run is now limited to those that can compile these libraries.
Not that big of a deal, if you ask me, since C runs almost everywhere, but it&amp;rsquo;ll make the compiler difficult to ship as a no-dependency binary.
It&amp;rsquo;s possible to compile a Fennel script into a binary and include all of its dependencies, but it would mean that I&amp;rsquo;ll have to produce binaries for many different operating systems and architectures.
Or, alternatively, require people to install LPeg and lpeglabel through luarocks.&lt;/p&gt;
&lt;p&gt;For now, I&amp;rsquo;m willing to accept this.
There&amp;rsquo;s a &lt;a href=&#34;https://github.com/pygy/LuLPeg&#34; target=&#34;_blank&#34;&gt;port of LPeg in pure Lua&lt;/a&gt;, but it&amp;rsquo;s quite slow and doesn&amp;rsquo;t have support for lpeglabel features.
There&amp;rsquo;s an &lt;a href=&#34;https://github.com/pygy/LuLPeg/issues/27&#34; target=&#34;_blank&#34;&gt;open request&lt;/a&gt; for that, but it&amp;rsquo;s been sitting open for quite some time.&lt;/p&gt;
&lt;p&gt;Other than that, the parsing is complete and we can look at the compiler part of the ClojureFnl project.
But that&amp;rsquo;s gonna be in the next post.&lt;/p&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: Clojure on Fennel part three: parsing&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Mon, 27 Apr 2026 19:48:00 +0300</pubDate>
    </item><item>
      <title>Clojure on Fennel part two: immutable.fnl optimizations</title>
      <link>https://andreyor.st/posts/2026-04-15-clojure-on-fennel-part-two-immutablefnl-optimizations/</link>
      <guid>https://andreyor.st/posts/2026-04-15-clojure-on-fennel-part-two-immutablefnl-optimizations/</guid>
      <description>&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://andreyor.st/posts/2026-04-07-clojure-on-fennel-part-one-persistent-data-structures/&#34;&gt;part one: persistent data structures&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;part two: immutable.fnl optimizations&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://andreyor.st/posts/2026-04-27-clojure-on-fennel-part-three-parsing/&#34;&gt;part three: parsing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://andreyor.st/posts/2026-06-29-clojure-on-fennel-part-four-parsing-again/&#34;&gt;part four: parsing (again)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;So the next post will hopefully be about the compiler itself.&lt;/p&gt;
&lt;p&gt;Unless I get distracted again.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Sike!&lt;/p&gt;
&lt;p&gt;While I did some work on the compiler, I&amp;rsquo;m not feeling ready to talk about it yet.
I want the post about it to be, well, more in-depth, so for now, let&amp;rsquo;s go back to immutable data structures.
I got some comments on their performance, which can be summarized to &amp;ldquo;bad&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;And I agree!
The performance is not great, especially when compared to plain Lua tables.
However, my benchmarking process was a bit flawed, and I&amp;rsquo;ve improved it since.&lt;/p&gt;
&lt;p&gt;This post won&amp;rsquo;t be long, but I wanted to make it anyway, to illustrate what I&amp;rsquo;m dealing with.
Again, this is not the final version, I&amp;rsquo;m still working on possible optimizations as I write this, but some things have improved already, though not by much.&lt;/p&gt;
&lt;p&gt;There were some low-hanging fruits that I could tackle:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Vector had a local &lt;code&gt;fragment&lt;/code&gt; function with pure arithmetic.
I already have the same &lt;code&gt;fragment&lt;/code&gt; function in my bitops module that uses native rshift+band.
The modulo operation is expensive.&lt;/li&gt;
&lt;li&gt;A similar case of using bit operations instead of modulo was in HashMap&amp;rsquo;s &lt;code&gt;index&lt;/code&gt; function.&lt;/li&gt;
&lt;li&gt;Increased the popcount table to 256 entries instead of 16.
Halves the loop iterations for typical bitmaps.&lt;/li&gt;
&lt;li&gt;Probably premature, but replaced most instances of &lt;code&gt;faccumulate&lt;/code&gt;, &lt;code&gt;fcollect&lt;/code&gt;, etc. with plain &lt;code&gt;for&lt;/code&gt; loops.
These loops are quite hot, and Fennel compiles them to have additional assignment at each iteration.
Should be free, but actually had a small impact.&lt;/li&gt;
&lt;li&gt;More pre-allocations when creating Lua tables.
Using &lt;code&gt;[nil nil nil nil]&lt;/code&gt; tells the Lua compiler to pre-allocate four slots when creating the table, meaning it won&amp;rsquo;t resize once we insert elements.
Tables in Lua resize by a factor of 2 and copy everything on resize, which is not great for performance.&lt;/li&gt;
&lt;li&gt;Vector iterator is now stateful.
And also fast.&lt;/li&gt;
&lt;li&gt;Internal fields for data structures used long, elaborate keys, which meant string comparison in certain cases of table lookup would be unnecessarily long.
Again, changing them to shorter keys should not matter that much, but it did have some impact.&lt;/li&gt;
&lt;li&gt;HashMap branching factor was increased to 32.
After some tests, it proved to be slightly better, despite what I said in my previous post.
More on that later.&lt;/li&gt;
&lt;li&gt;Hashes are now cached in a weak table.
Helps avoid re-hashing the same values at the expense of memory.
Not sure how well it will scale.&lt;/li&gt;
&lt;li&gt;Optimized array copying for sizes less than 4 by doing direct table construction.
Avoids loop overhead.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;With these changes in place (and some more I omitted), here are some of the benchmarks:&lt;/p&gt;
&lt;figure class=&#34;invertable&#34;&gt;&lt;img src=&#34;https://andreyor.st/2026-04-15-clojure-on-fennel-part-two-immutablefnl-optimizations/lua.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;These images show per-commit changes to the performance.
Really helped me track what was worth keeping, and what wasn&amp;rsquo;t.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s the LuaJIT version of the benchmark:&lt;/p&gt;
&lt;figure class=&#34;invertable&#34;&gt;&lt;img src=&#34;https://andreyor.st/2026-04-15-clojure-on-fennel-part-two-immutablefnl-optimizations/luajit.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;Here&amp;rsquo;s another graph:&lt;/p&gt;
&lt;figure class=&#34;invertable&#34;&gt;&lt;img src=&#34;https://andreyor.st/2026-04-15-clojure-on-fennel-part-two-immutablefnl-optimizations/hashmap.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;This is me testing how hash map branching factor affects operations.
As can be seen, switching from 16 to 32 makes inserts slower on PUC Lua 5.5 but makes indexing faster.
On LuaJIT both operations are faster.&lt;/p&gt;
&lt;figure class=&#34;invertable&#34;&gt;&lt;img src=&#34;https://andreyor.st/2026-04-15-clojure-on-fennel-part-two-immutablefnl-optimizations/insertion-lua.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;Looking at the charts, the &lt;code&gt;7989c32&lt;/code&gt; commit with that change (the second orange bar) — insertions are slower than the previous commit, and indexing is faster than the previous commit.
Unfortunately, LuaJIT charts are noisy and I can&amp;rsquo;t confirm the speedup there.
Something to do with instabilities in the LuaJIT tracer, I guess.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt; I know, the results for some operations are worse than before all optimizations that took place.
This is still a work in progress.
Just shows how important relative measuring is.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The results are a mixed bag.
Most operations that improved did so by only 1 or 2 milliseconds overall, meaning the per-operation cost is still quite high, compared to Lua tables.
Yes, some became faster, so I&amp;rsquo;m keeping these changes, but I can also see that for some operations, they actually got slower than they were before any optimization work.
The reason for that may be that I fixed a few bugs along the way.
Anyway, I tried to prioritize transient collection variants, as they benefit most from optimizations given how they&amp;rsquo;re used, and LuaJIT performance where possible.&lt;/p&gt;
&lt;p&gt;Some bars are not meaningful for certain operations.
E.g., I had changes that had nothing to do with Persistent Vector, but affected it anyway, so this benchmark is still a bit flawed.
At least those differences are within the deviation range.&lt;/p&gt;
&lt;p&gt;Anyhow, just wanted to show that optimization is hard, and not all changes yield the results you expect.
In the case of this library, I don&amp;rsquo;t think there are more low-hanging fruits to optimize, or at least I don&amp;rsquo;t see any.
For example, there are a lot of table allocations that are hard to get rid of in the current implementation.
A deeper analysis is needed, probably by people with more Lua knowledge.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m still satisfied with some improvements I got, but we&amp;rsquo;ll see if more are on the way.&lt;/p&gt;
&lt;h2 id=&#34;update&#34;&gt;Update&lt;/h2&gt;
&lt;p&gt;After a lot more benchmarks, flamegraphs, and throwing stuff at the wall, I think I can&amp;rsquo;t do much more.
I decided to update this post instead of writing another one (and really should have waited before publishing the original) because at that point, I thought there was nothing more to do.
Now I think there really isn&amp;rsquo;t.
So the results are in:&lt;/p&gt;
&lt;figure class=&#34;invertable&#34;&gt;&lt;img src=&#34;https://andreyor.st/2026-04-15-clojure-on-fennel-part-two-immutablefnl-optimizations/lua-final.png&#34;
         alt=&#34;Figure 1: PUC Lua 5.5 (green - before, orange - after)&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 1: &lt;/span&gt;PUC Lua 5.5 (green - before, orange - after)&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;figure class=&#34;invertable&#34;&gt;&lt;img src=&#34;https://andreyor.st/2026-04-15-clojure-on-fennel-part-two-immutablefnl-optimizations/luajit-final.png&#34;
         alt=&#34;Figure 2: LuaJIT (green - before, orange - after)&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 2: &lt;/span&gt;LuaJIT (green - before, orange - after)&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;As can be seen, the changes are more dramatic on Lua than on LuaJIT.
Mostly because it&amp;rsquo;s hard to optimize for LuaJIT without sacrificing performance on Lua, so I re-prioritized Lua, since LuaJIT is already much faster.&lt;/p&gt;
&lt;p&gt;The final benchmark tables are below.&lt;/p&gt;
&lt;h4 id=&#34;puc-lua-5-dot-5&#34;&gt;PUC Lua 5.5&lt;/h4&gt;
&lt;!--list-separator--&gt;
&lt;ul&gt;
&lt;li&gt;PersistentVector
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Operation&lt;/th&gt;
&lt;th&gt;Lua table&lt;/th&gt;
&lt;th&gt;Persistent&lt;/th&gt;
&lt;th&gt;ratio&lt;/th&gt;
&lt;th&gt;per op&lt;/th&gt;
&lt;th&gt;ratio (old)&lt;/th&gt;
&lt;th&gt;per op (old)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;build 50000&lt;/td&gt;
&lt;td&gt;0.18 ms&lt;/td&gt;
&lt;td&gt;18.88 ms&lt;/td&gt;
&lt;td&gt;102x&lt;/td&gt;
&lt;td&gt;0.378 us&lt;/td&gt;
&lt;td&gt;119x&lt;/td&gt;
&lt;td&gt;0.440 us&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;lookup random&lt;/td&gt;
&lt;td&gt;0.48 ms&lt;/td&gt;
&lt;td&gt;11.44 ms&lt;/td&gt;
&lt;td&gt;24x&lt;/td&gt;
&lt;td&gt;0.229 us&lt;/td&gt;
&lt;td&gt;28x&lt;/td&gt;
&lt;td&gt;0.266 us&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;assoc random&lt;/td&gt;
&lt;td&gt;0.31 ms&lt;/td&gt;
&lt;td&gt;42.72 ms&lt;/td&gt;
&lt;td&gt;139x&lt;/td&gt;
&lt;td&gt;0.854 us&lt;/td&gt;
&lt;td&gt;222x&lt;/td&gt;
&lt;td&gt;1.4 us&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;pop all&lt;/td&gt;
&lt;td&gt;0.14 ms&lt;/td&gt;
&lt;td&gt;14.56 ms&lt;/td&gt;
&lt;td&gt;106x&lt;/td&gt;
&lt;td&gt;0.291 us&lt;/td&gt;
&lt;td&gt;150x&lt;/td&gt;
&lt;td&gt;0.415 us&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;iterate&lt;/td&gt;
&lt;td&gt;0.60 ms&lt;/td&gt;
&lt;td&gt;2.74 ms&lt;/td&gt;
&lt;td&gt;5x&lt;/td&gt;
&lt;td&gt;0.055 us&lt;/td&gt;
&lt;td&gt;17x&lt;/td&gt;
&lt;td&gt;0.196 us&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;!--list-separator--&gt;
&lt;ul&gt;
&lt;li&gt;TransientVector
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Operation&lt;/th&gt;
&lt;th&gt;Lua table&lt;/th&gt;
&lt;th&gt;Transient&lt;/th&gt;
&lt;th&gt;ratio&lt;/th&gt;
&lt;th&gt;per op&lt;/th&gt;
&lt;th&gt;ratio (old)&lt;/th&gt;
&lt;th&gt;per op (old)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;build 50000&lt;/td&gt;
&lt;td&gt;0.19 ms&lt;/td&gt;
&lt;td&gt;6.55 ms&lt;/td&gt;
&lt;td&gt;35x&lt;/td&gt;
&lt;td&gt;0.131 us&lt;/td&gt;
&lt;td&gt;41x&lt;/td&gt;
&lt;td&gt;0.154 us&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;assoc random&lt;/td&gt;
&lt;td&gt;0.31 ms&lt;/td&gt;
&lt;td&gt;17.64 ms&lt;/td&gt;
&lt;td&gt;57x&lt;/td&gt;
&lt;td&gt;0.353 us&lt;/td&gt;
&lt;td&gt;67x&lt;/td&gt;
&lt;td&gt;0.408 us&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;pop all&lt;/td&gt;
&lt;td&gt;0.14 ms&lt;/td&gt;
&lt;td&gt;5.74 ms&lt;/td&gt;
&lt;td&gt;42x&lt;/td&gt;
&lt;td&gt;0.115 us&lt;/td&gt;
&lt;td&gt;51x&lt;/td&gt;
&lt;td&gt;0.142 us&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;!--list-separator--&gt;
&lt;ul&gt;
&lt;li&gt;PersistentHashMap
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Operation&lt;/th&gt;
&lt;th&gt;Lua table&lt;/th&gt;
&lt;th&gt;Persistent&lt;/th&gt;
&lt;th&gt;ratio&lt;/th&gt;
&lt;th&gt;per op&lt;/th&gt;
&lt;th&gt;ratio (old)&lt;/th&gt;
&lt;th&gt;per op (old)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;insert 50000&lt;/td&gt;
&lt;td&gt;2.01 ms&lt;/td&gt;
&lt;td&gt;81.44 ms&lt;/td&gt;
&lt;td&gt;41x&lt;/td&gt;
&lt;td&gt;1.6 us&lt;/td&gt;
&lt;td&gt;82x&lt;/td&gt;
&lt;td&gt;3.2 us&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;lookup random&lt;/td&gt;
&lt;td&gt;0.92 ms&lt;/td&gt;
&lt;td&gt;34.03 ms&lt;/td&gt;
&lt;td&gt;37x&lt;/td&gt;
&lt;td&gt;0.681 us&lt;/td&gt;
&lt;td&gt;81x&lt;/td&gt;
&lt;td&gt;1.7 us&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;contains random&lt;/td&gt;
&lt;td&gt;1.82 ms&lt;/td&gt;
&lt;td&gt;33.08 ms&lt;/td&gt;
&lt;td&gt;18x&lt;/td&gt;
&lt;td&gt;0.662 us&lt;/td&gt;
&lt;td&gt;49x&lt;/td&gt;
&lt;td&gt;1.7 us&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;dissoc all&lt;/td&gt;
&lt;td&gt;0.90 ms&lt;/td&gt;
&lt;td&gt;76.97 ms&lt;/td&gt;
&lt;td&gt;86x&lt;/td&gt;
&lt;td&gt;1.5 us&lt;/td&gt;
&lt;td&gt;187x&lt;/td&gt;
&lt;td&gt;3.3 us&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;dissoc 10%&lt;/td&gt;
&lt;td&gt;0.18 ms&lt;/td&gt;
&lt;td&gt;9.81 ms&lt;/td&gt;
&lt;td&gt;56x&lt;/td&gt;
&lt;td&gt;2.0 us&lt;/td&gt;
&lt;td&gt;112x&lt;/td&gt;
&lt;td&gt;3.7 us&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;iterate&lt;/td&gt;
&lt;td&gt;1.91 ms&lt;/td&gt;
&lt;td&gt;7.22 ms&lt;/td&gt;
&lt;td&gt;4x&lt;/td&gt;
&lt;td&gt;0.144 us&lt;/td&gt;
&lt;td&gt;4x&lt;/td&gt;
&lt;td&gt;0.146 us&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;lookup structural keys&lt;/td&gt;
&lt;td&gt;0.14 ms&lt;/td&gt;
&lt;td&gt;2.86 ms&lt;/td&gt;
&lt;td&gt;21x&lt;/td&gt;
&lt;td&gt;0.572 us&lt;/td&gt;
&lt;td&gt;146x&lt;/td&gt;
&lt;td&gt;4.1 us&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;insert collision-heavy&lt;/td&gt;
&lt;td&gt;0.13 ms&lt;/td&gt;
&lt;td&gt;6.50 ms&lt;/td&gt;
&lt;td&gt;51x&lt;/td&gt;
&lt;td&gt;1.3 us&lt;/td&gt;
&lt;td&gt;134x&lt;/td&gt;
&lt;td&gt;3.5 us&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;mixed 80/20&lt;/td&gt;
&lt;td&gt;1.92 ms&lt;/td&gt;
&lt;td&gt;53.67 ms&lt;/td&gt;
&lt;td&gt;28x&lt;/td&gt;
&lt;td&gt;1.1 us&lt;/td&gt;
&lt;td&gt;62x&lt;/td&gt;
&lt;td&gt;2.3 us&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;!--list-separator--&gt;
&lt;ul&gt;
&lt;li&gt;TransientHashMap
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Operation&lt;/th&gt;
&lt;th&gt;Lua table&lt;/th&gt;
&lt;th&gt;Transient&lt;/th&gt;
&lt;th&gt;ratio&lt;/th&gt;
&lt;th&gt;per op&lt;/th&gt;
&lt;th&gt;ratio (old)&lt;/th&gt;
&lt;th&gt;per op (old)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;insert 50000&lt;/td&gt;
&lt;td&gt;2.02 ms&lt;/td&gt;
&lt;td&gt;38.91 ms&lt;/td&gt;
&lt;td&gt;19x&lt;/td&gt;
&lt;td&gt;0.778 us&lt;/td&gt;
&lt;td&gt;44x&lt;/td&gt;
&lt;td&gt;1.7 us&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;lookup random&lt;/td&gt;
&lt;td&gt;1.14 ms&lt;/td&gt;
&lt;td&gt;35.56 ms&lt;/td&gt;
&lt;td&gt;31x&lt;/td&gt;
&lt;td&gt;0.711 us&lt;/td&gt;
&lt;td&gt;86x&lt;/td&gt;
&lt;td&gt;1.7 us&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;dissoc all&lt;/td&gt;
&lt;td&gt;0.89 ms&lt;/td&gt;
&lt;td&gt;44.52 ms&lt;/td&gt;
&lt;td&gt;50x&lt;/td&gt;
&lt;td&gt;0.890 us&lt;/td&gt;
&lt;td&gt;112x&lt;/td&gt;
&lt;td&gt;2.0 us&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;mixed 80/20&lt;/td&gt;
&lt;td&gt;4.39 ms&lt;/td&gt;
&lt;td&gt;44.87 ms&lt;/td&gt;
&lt;td&gt;10x&lt;/td&gt;
&lt;td&gt;0.897 us&lt;/td&gt;
&lt;td&gt;22x&lt;/td&gt;
&lt;td&gt;1.9 us&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&#34;luajit&#34;&gt;LuaJIT&lt;/h4&gt;
&lt;!--list-separator--&gt;
&lt;ul&gt;
&lt;li&gt;PersistentVector
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Operation&lt;/th&gt;
&lt;th&gt;Lua table&lt;/th&gt;
&lt;th&gt;Persistent&lt;/th&gt;
&lt;th&gt;ratio&lt;/th&gt;
&lt;th&gt;per op&lt;/th&gt;
&lt;th&gt;ratio (old)&lt;/th&gt;
&lt;th&gt;per op (old)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;build 50000&lt;/td&gt;
&lt;td&gt;0.11 ms&lt;/td&gt;
&lt;td&gt;8.12 ms&lt;/td&gt;
&lt;td&gt;71x&lt;/td&gt;
&lt;td&gt;0.162 us&lt;/td&gt;
&lt;td&gt;84x&lt;/td&gt;
&lt;td&gt;0.177 us&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;lookup random&lt;/td&gt;
&lt;td&gt;0.06 ms&lt;/td&gt;
&lt;td&gt;0.67 ms&lt;/td&gt;
&lt;td&gt;11x&lt;/td&gt;
&lt;td&gt;0.013 us&lt;/td&gt;
&lt;td&gt;11x&lt;/td&gt;
&lt;td&gt;0.013 us&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;assoc random&lt;/td&gt;
&lt;td&gt;0.04 ms&lt;/td&gt;
&lt;td&gt;22.91 ms&lt;/td&gt;
&lt;td&gt;559x&lt;/td&gt;
&lt;td&gt;0.458 us&lt;/td&gt;
&lt;td&gt;731x&lt;/td&gt;
&lt;td&gt;0.585 us&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;pop all&lt;/td&gt;
&lt;td&gt;0.02 ms&lt;/td&gt;
&lt;td&gt;10.77 ms&lt;/td&gt;
&lt;td&gt;718x&lt;/td&gt;
&lt;td&gt;0.215 us&lt;/td&gt;
&lt;td&gt;657x&lt;/td&gt;
&lt;td&gt;0.210 us&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;iterate&lt;/td&gt;
&lt;td&gt;0.02 ms&lt;/td&gt;
&lt;td&gt;0.23 ms&lt;/td&gt;
&lt;td&gt;12x&lt;/td&gt;
&lt;td&gt;0.005 us&lt;/td&gt;
&lt;td&gt;26x&lt;/td&gt;
&lt;td&gt;0.011 us&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;!--list-separator--&gt;
&lt;ul&gt;
&lt;li&gt;TransientVector
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Operation&lt;/th&gt;
&lt;th&gt;Lua table&lt;/th&gt;
&lt;th&gt;Transient&lt;/th&gt;
&lt;th&gt;ratio&lt;/th&gt;
&lt;th&gt;per op&lt;/th&gt;
&lt;th&gt;ratio (old)&lt;/th&gt;
&lt;th&gt;per op (old)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;build 50000&lt;/td&gt;
&lt;td&gt;0.05 ms&lt;/td&gt;
&lt;td&gt;0.79 ms&lt;/td&gt;
&lt;td&gt;16x&lt;/td&gt;
&lt;td&gt;0.016 us&lt;/td&gt;
&lt;td&gt;12x&lt;/td&gt;
&lt;td&gt;0.012 us&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;assoc random&lt;/td&gt;
&lt;td&gt;0.04 ms&lt;/td&gt;
&lt;td&gt;2.22 ms&lt;/td&gt;
&lt;td&gt;55x&lt;/td&gt;
&lt;td&gt;0.044 us&lt;/td&gt;
&lt;td&gt;28x&lt;/td&gt;
&lt;td&gt;0.022 us&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;pop all&lt;/td&gt;
&lt;td&gt;0.02 ms&lt;/td&gt;
&lt;td&gt;0.35 ms&lt;/td&gt;
&lt;td&gt;23x&lt;/td&gt;
&lt;td&gt;0.007 us&lt;/td&gt;
&lt;td&gt;50x&lt;/td&gt;
&lt;td&gt;0.016 us&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;!--list-separator--&gt;
&lt;ul&gt;
&lt;li&gt;PersistentHashMap
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Operation&lt;/th&gt;
&lt;th&gt;Lua table&lt;/th&gt;
&lt;th&gt;Persistent&lt;/th&gt;
&lt;th&gt;ratio&lt;/th&gt;
&lt;th&gt;per op&lt;/th&gt;
&lt;th&gt;ratio (old)&lt;/th&gt;
&lt;th&gt;per op (old)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;insert 50000&lt;/td&gt;
&lt;td&gt;0.79 ms&lt;/td&gt;
&lt;td&gt;32.32 ms&lt;/td&gt;
&lt;td&gt;41x&lt;/td&gt;
&lt;td&gt;0.646 us&lt;/td&gt;
&lt;td&gt;50x&lt;/td&gt;
&lt;td&gt;0.989 us&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;lookup random&lt;/td&gt;
&lt;td&gt;0.34 ms&lt;/td&gt;
&lt;td&gt;5.78 ms&lt;/td&gt;
&lt;td&gt;17x&lt;/td&gt;
&lt;td&gt;0.116 us&lt;/td&gt;
&lt;td&gt;43x&lt;/td&gt;
&lt;td&gt;0.248 us&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;contains random&lt;/td&gt;
&lt;td&gt;0.30 ms&lt;/td&gt;
&lt;td&gt;5.91 ms&lt;/td&gt;
&lt;td&gt;20x&lt;/td&gt;
&lt;td&gt;0.118 us&lt;/td&gt;
&lt;td&gt;40x&lt;/td&gt;
&lt;td&gt;0.257 us&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;dissoc all&lt;/td&gt;
&lt;td&gt;0.23 ms&lt;/td&gt;
&lt;td&gt;27.02 ms&lt;/td&gt;
&lt;td&gt;119x&lt;/td&gt;
&lt;td&gt;0.540 us&lt;/td&gt;
&lt;td&gt;191x&lt;/td&gt;
&lt;td&gt;0.894 us&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;dissoc 10%&lt;/td&gt;
&lt;td&gt;0.05 ms&lt;/td&gt;
&lt;td&gt;5.89 ms&lt;/td&gt;
&lt;td&gt;118x&lt;/td&gt;
&lt;td&gt;1.2 us&lt;/td&gt;
&lt;td&gt;121x&lt;/td&gt;
&lt;td&gt;1.4 us&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;iterate&lt;/td&gt;
&lt;td&gt;0.07 ms&lt;/td&gt;
&lt;td&gt;1.07 ms&lt;/td&gt;
&lt;td&gt;16x&lt;/td&gt;
&lt;td&gt;0.021 us&lt;/td&gt;
&lt;td&gt;30x&lt;/td&gt;
&lt;td&gt;0.040 us&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;lookup structural keys&lt;/td&gt;
&lt;td&gt;0.02 ms&lt;/td&gt;
&lt;td&gt;2.41 ms&lt;/td&gt;
&lt;td&gt;121x&lt;/td&gt;
&lt;td&gt;0.483 us&lt;/td&gt;
&lt;td&gt;119x&lt;/td&gt;
&lt;td&gt;0.498 us&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;insert collision-heavy&lt;/td&gt;
&lt;td&gt;0.28 ms&lt;/td&gt;
&lt;td&gt;5.20 ms&lt;/td&gt;
&lt;td&gt;19x&lt;/td&gt;
&lt;td&gt;1.0 us&lt;/td&gt;
&lt;td&gt;36x&lt;/td&gt;
&lt;td&gt;1.2 us&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;mixed 80/20&lt;/td&gt;
&lt;td&gt;0.50 ms&lt;/td&gt;
&lt;td&gt;46.59 ms&lt;/td&gt;
&lt;td&gt;94x&lt;/td&gt;
&lt;td&gt;0.932 us&lt;/td&gt;
&lt;td&gt;40x&lt;/td&gt;
&lt;td&gt;0.513 us&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;!--list-separator--&gt;
&lt;ul&gt;
&lt;li&gt;TransientHashMap
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Operation&lt;/th&gt;
&lt;th&gt;Lua table&lt;/th&gt;
&lt;th&gt;Transient&lt;/th&gt;
&lt;th&gt;ratio&lt;/th&gt;
&lt;th&gt;per op&lt;/th&gt;
&lt;th&gt;ratio (old)&lt;/th&gt;
&lt;th&gt;per op  (old)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;insert 50000&lt;/td&gt;
&lt;td&gt;0.91 ms&lt;/td&gt;
&lt;td&gt;30.92 ms&lt;/td&gt;
&lt;td&gt;34x&lt;/td&gt;
&lt;td&gt;0.618 us&lt;/td&gt;
&lt;td&gt;11x&lt;/td&gt;
&lt;td&gt;0.242 us&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;lookup random&lt;/td&gt;
&lt;td&gt;0.32 ms&lt;/td&gt;
&lt;td&gt;34.90 ms&lt;/td&gt;
&lt;td&gt;110x&lt;/td&gt;
&lt;td&gt;0.698 us&lt;/td&gt;
&lt;td&gt;44x&lt;/td&gt;
&lt;td&gt;0.246 us&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;dissoc all&lt;/td&gt;
&lt;td&gt;0.23 ms&lt;/td&gt;
&lt;td&gt;36.35 ms&lt;/td&gt;
&lt;td&gt;162x&lt;/td&gt;
&lt;td&gt;0.727 us&lt;/td&gt;
&lt;td&gt;57x&lt;/td&gt;
&lt;td&gt;0.271 us&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;mixed 80/20&lt;/td&gt;
&lt;td&gt;1.29 ms&lt;/td&gt;
&lt;td&gt;40.71 ms&lt;/td&gt;
&lt;td&gt;32x&lt;/td&gt;
&lt;td&gt;0.814 us&lt;/td&gt;
&lt;td&gt;11x&lt;/td&gt;
&lt;td&gt;0.309 us&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Yes, the benchmark shows that some operations slowed down, some sped up.
Ideally, I&amp;rsquo;d like to have no slowdown, but that&amp;rsquo;s that.
Still, I wouldn&amp;rsquo;t trust my LuaJIT benchmark, though - graphs show that for some weird reason unrelated changes affect performance in the modules not touched by those changes at all.
So these changes are now merged into the main branch.&lt;/p&gt;
&lt;p&gt;Main bottleneck now is table allocation and array copying - things I already spent optimizing a lot of time with mixed results.
So I think I can&amp;rsquo;t do better than that.
At least without major algorithmic restructuring.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;With that&lt;/strong&gt;, the next post &lt;em&gt;should&lt;/em&gt; be about the compiler.&lt;/p&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: Clojure on Fennel part two: immutable.fnl optimizations&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Wed, 15 Apr 2026 05:11:00 +0300</pubDate>
    </item><item>
      <title>Clojure on Fennel part one: Persistent Data Structures</title>
      <link>https://andreyor.st/posts/2026-04-07-clojure-on-fennel-part-one-persistent-data-structures/</link>
      <guid>https://andreyor.st/posts/2026-04-07-clojure-on-fennel-part-one-persistent-data-structures/</guid>
      <description>&lt;ul&gt;
&lt;li&gt;part one: persistent data structures&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://andreyor.st/posts/2026-04-15-clojure-on-fennel-part-two-immutablefnl-optimizations/&#34;&gt;part two: immutable.fnl optimizations&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://andreyor.st/posts/2026-04-27-clojure-on-fennel-part-three-parsing/&#34;&gt;part three: parsing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://andreyor.st/posts/2026-06-29-clojure-on-fennel-part-four-parsing-again/&#34;&gt;part four: parsing (again)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Somewhere in 2019 I started a project that aimed to bring some of Clojure features to Lua runtime - &lt;a href=&#34;https://gitlab.com/andreyorst/fennel-cljlib&#34; target=&#34;_blank&#34;&gt;fennel-cljlib&lt;/a&gt;.
It was a library for Fennel that implemented a basic subset of &lt;code&gt;clojure.core&lt;/code&gt; namespace functions and macros.
My goal was simple - I enjoy working with Clojure, but I don&amp;rsquo;t use it for hobby projects, so I wanted Fennel to feel more Clojure-like, besides what it already provides for that.&lt;/p&gt;
&lt;p&gt;This library grew over the years, I implemented &lt;a href=&#34;https://andreyor.st/posts/2021-10-09-lazy-sequences-and-iterators/&#34;&gt;lazy sequences&lt;/a&gt;, added &lt;a href=&#34;https://gitlab.com/andreyorst/itable&#34; target=&#34;_blank&#34;&gt;immutability&lt;/a&gt;, made a &lt;a href=&#34;https://gitlab.com/andreyorst/fennel-test&#34; target=&#34;_blank&#34;&gt;testing library&lt;/a&gt;, inspired by &lt;code&gt;clojure.test&lt;/code&gt; and kaocha, and even made a &lt;a href=&#34;https://andreyor.st/posts/2023-05-15-clojures-coreasync-port-for-the-fennel-language/&#34;&gt;port of &lt;code&gt;clojure.core.async&lt;/code&gt;&lt;/a&gt;.
It was a passion project, I almost never used it to write actual software.
One notable exception is &lt;a href=&#34;https://gitlab.com/andreyorst/fenneldoc&#34; target=&#34;_blank&#34;&gt;fenneldoc&lt;/a&gt; - a tool for documentation generation for Fennel libraries.
And I haven&amp;rsquo;t seen anyone else use it for a serious project.&lt;/p&gt;
&lt;p&gt;The reason for that is simple - it was an experiment.
Corners were cut, and Fennel, being a Clojure-inspired lisp is not associated with functional programming the same way Clojure is.
As a matter of fact, I wouldn&amp;rsquo;t recommend using this library for anything serious&amp;hellip; yet.&lt;/p&gt;
&lt;p&gt;Recently, however, I started a new project: &lt;a href=&#34;https://gitlab.com/andreyorst/clojurefnl&#34; target=&#34;_blank&#34;&gt;ClojureFnl&lt;/a&gt;.
This is a Clojure-to-Fennel compiler that uses fennel-cljlib as a foundation.
It&amp;rsquo;s still in early days of development, but I&amp;rsquo;ve been working on it for a few months in private until I found a suitable way to make things work in March.
As of this moment, it is capable of compiling most of &lt;code&gt;.cljc&lt;/code&gt; files I threw at it, but running the compiled code is a different matter.
I mean, it works to some degree, but the support for standard library is far from done.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; Welcome to ClojureFnl REPL&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; ClojureFnl v0.0.1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; Fennel 1.6.1 on PUC Lua 5.5&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user=&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;prime?&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;not &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;some zero? &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;map &lt;/span&gt;#(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;rem &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;%&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;range &lt;/span&gt;2 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;function&lt;/span&gt;&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; 0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x89ba7c550&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user=&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;for &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;range &lt;/span&gt;3 33 2)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:when&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;prime?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(3 5 7 11 13 17 19 23 29 31)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user=&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;However, there was a problem.&lt;/p&gt;
&lt;p&gt;My initial implementation of immutable data structures in the &lt;a href=&#34;https://gitlab.com/andreyorst/itable&#34; target=&#34;_blank&#34;&gt;itable&lt;/a&gt; library had a serious flaw.
The whole library was a simple hack based on the copy-on-write approach and a bunch of Lua metatables to enforce immutability.
As a result, all operations were extremely slow.
It was fine as an experiment, but if I wanted to go further with ClojureFnl, I had to replace it.
The same problem plagued &lt;a href=&#34;https://gitlab.com/andreyorst/immutableredblacktree.lua&#34; target=&#34;_blank&#34;&gt;immutableredblacktree.lua&lt;/a&gt;, an implementation of a copy-on-write red-black tree I made for sorted maps.
It did a full copy of the tree each time it was modified.&lt;/p&gt;
&lt;p&gt;For associative tables it wasn&amp;rsquo;t that big of a deal - usually maps contain a small amount of keys, and &lt;code&gt;itable&lt;/code&gt; only copied levels that needed to be changed.
So, if you had a map with, say, ten keys, and each of those keys contained another map with ten keys, adding, removing or updating a key in the outer map meant only copying these ten keys - not the whole nested map.
I could do that reliably, because inner maps were immutable too.&lt;/p&gt;
&lt;p&gt;But for arrays the story is usually quite different.
Arrays often store a lot of indices, and rarely are nested (or at least not as often as maps).
And copying arrays on every change quickly becomes expensive.
I&amp;rsquo;ve mitigated some of the performance problems by implementing my version of transients, however the beauty of Clojure&amp;rsquo;s data structures is that they&amp;rsquo;re quite fast even without this optimization.&lt;/p&gt;
&lt;h2 id=&#34;proper-persistent-data-structures&#34;&gt;Proper persistent data structures&lt;/h2&gt;
&lt;p&gt;Clojure uses Persistent HAMT as a base for its hash maps and sets, and a bit-partitioned trie for vectors.
For sorted maps and sets, Clojure uses an immutable red-black tree implementation, but as far as I know it&amp;rsquo;s not doing a full copy of the tree, and it also has structural sharing properties.&lt;/p&gt;
&lt;p&gt;I started looking into existing implementations of HAMT for Lua:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/raymond-w-ko/hamt.lua&#34; target=&#34;_blank&#34;&gt;hamt.lua&lt;/a&gt; (based on &lt;a href=&#34;https://github.com/mattbierner/hamt.git&#34; target=&#34;_blank&#34;&gt;mattbierner/hamt&lt;/a&gt;)
&lt;ul&gt;
&lt;li&gt;seemed incomplete&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://codeberg.org/alloyed/ltrie&#34; target=&#34;_blank&#34;&gt;ltrie&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;no transients&lt;/li&gt;
&lt;li&gt;no hashset&lt;/li&gt;
&lt;li&gt;no ordered map (expectable, different algorithm)&lt;/li&gt;
&lt;li&gt;no compound vector/hash&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://gist.github.com/SegFaultAX/3318559&#34; target=&#34;_blank&#34;&gt;Michael-Keith Bernard&amp;rsquo;s gist&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;no custom hashing&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I could use one of those, notably &lt;code&gt;ltrie&lt;/code&gt; seemed the most appropriate one, but given that I&amp;rsquo;m working on a fennel library that I want later to embed into my Clojure compiler I needed a library implemented in Fennel.&lt;/p&gt;
&lt;p&gt;So I made my own library: &lt;a href=&#34;https://gitlab.com/andreyorst/immutable.fnl&#34; target=&#34;_blank&#34;&gt;immutable.fnl&lt;/a&gt;.
This library features HAMT-hash maps, hash-sets, and vectors, as well as a better implementation of a persistent red-black tree, and lazy linked lists.&lt;/p&gt;
&lt;h3 id=&#34;persistent-hash-map&#34;&gt;Persistent Hash Map&lt;/h3&gt;
&lt;p&gt;I started the implementation with a Persistent HAMT with native Lua hashing.
The data structure itself is a Hash Array Mapped Trie (HAMT) with 16-factor branching.
Thus all operations are O(Log16 N), which is effectively O(1) for a practical amount of keys.&lt;/p&gt;
&lt;p&gt;As far as I know, Clojure uses branching factor of 32, but for a Lua runtime this would mean that the popcount would be more expensive, and despite a shallower tree, each mutation would need to copy a larger sparse array.
With branching factor of 16 a map with 50K entries is ~4 levels deep, which would be ~3 with 32 branching factor.
So my logic was that it&amp;rsquo;ll be a compromise, especially since Lua is not JVM when it comes to performance.&lt;/p&gt;
&lt;p&gt;Of course, it&amp;rsquo;s not as fast as a pure Lua table, which is to be expected.
Lua tables are implemented in C, use efficient hashing, and dynamically re-allocated based on key count.
So for my implementation most operations are a lot slower, but the total time for an operation is still usable.&lt;/p&gt;
&lt;p&gt;Here are some benchmarks:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Median time over 7 rounds (1 warmup discarded), N = 50000 elements.
GC stopped during measurement. Clock: os.clock (CPU).
Runtime: Fennel 1.7.0-dev on PUC Lua 5.5&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Regular operations are notably slower, when compared to Lua:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Operation&lt;/th&gt;
&lt;th&gt;Lua table&lt;/th&gt;
&lt;th&gt;Persistent HashMap&lt;/th&gt;
&lt;th&gt;Ratio&lt;/th&gt;
&lt;th&gt;per op&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;insert 50000 random keys&lt;/td&gt;
&lt;td&gt;2.05 ms&lt;/td&gt;
&lt;td&gt;164.80 ms&lt;/td&gt;
&lt;td&gt;80.3x slower&lt;/td&gt;
&lt;td&gt;3.3 us&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;lookup 50000 random keys&lt;/td&gt;
&lt;td&gt;0.83 ms&lt;/td&gt;
&lt;td&gt;92.51 ms&lt;/td&gt;
&lt;td&gt;110.8x slower&lt;/td&gt;
&lt;td&gt;1.9 us&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;delete all&lt;/td&gt;
&lt;td&gt;0.78 ms&lt;/td&gt;
&lt;td&gt;170.78 ms&lt;/td&gt;
&lt;td&gt;219.8x slower&lt;/td&gt;
&lt;td&gt;3.4 us&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;delete 10%&lt;/td&gt;
&lt;td&gt;0.14 ms&lt;/td&gt;
&lt;td&gt;19.50 ms&lt;/td&gt;
&lt;td&gt;136.4x slower&lt;/td&gt;
&lt;td&gt;3.9 us&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;iterate 50000 entries&lt;/td&gt;
&lt;td&gt;1.74 ms&lt;/td&gt;
&lt;td&gt;6.64 ms&lt;/td&gt;
&lt;td&gt;3.8x slower&lt;/td&gt;
&lt;td&gt;0.133 us&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;For transients the situation is a bit better, but not by much:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Operation&lt;/th&gt;
&lt;th&gt;Lua table&lt;/th&gt;
&lt;th&gt;Transient HashMap&lt;/th&gt;
&lt;th&gt;Ratio&lt;/th&gt;
&lt;th&gt;per op&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;insert 50000 random keys&lt;/td&gt;
&lt;td&gt;2.05 ms&lt;/td&gt;
&lt;td&gt;89.17 ms&lt;/td&gt;
&lt;td&gt;43.5x slower&lt;/td&gt;
&lt;td&gt;1.8 us&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;delete all&lt;/td&gt;
&lt;td&gt;0.76 ms&lt;/td&gt;
&lt;td&gt;104.31 ms&lt;/td&gt;
&lt;td&gt;138.0x slower&lt;/td&gt;
&lt;td&gt;2.1 us&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;delete 10%&lt;/td&gt;
&lt;td&gt;0.16 ms&lt;/td&gt;
&lt;td&gt;12.71 ms&lt;/td&gt;
&lt;td&gt;82.0x slower&lt;/td&gt;
&lt;td&gt;2.5 us&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;On LuaJIT numbers may seem worse, but per-operation cost is much lower, it&amp;rsquo;s just that native table operations are so much faster:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Median time over 7 rounds (1 warmup discarded), N = 50000 elements.
GC stopped during measurement. Clock: os.clock (CPU).
Runtime: Fennel 1.7.0-dev on LuaJIT 2.1.1774896198 macOS/arm64&lt;/p&gt;
&lt;/blockquote&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Operation&lt;/th&gt;
&lt;th&gt;Lua table&lt;/th&gt;
&lt;th&gt;Persistent HashMap&lt;/th&gt;
&lt;th&gt;Ratio&lt;/th&gt;
&lt;th&gt;per op&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;insert 50000 random keys&lt;/td&gt;
&lt;td&gt;0.86 ms&lt;/td&gt;
&lt;td&gt;49.05 ms&lt;/td&gt;
&lt;td&gt;56.8x slower&lt;/td&gt;
&lt;td&gt;0.981 us&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;lookup 50000 random keys&lt;/td&gt;
&lt;td&gt;0.27 ms&lt;/td&gt;
&lt;td&gt;14.21 ms&lt;/td&gt;
&lt;td&gt;53.4x slower&lt;/td&gt;
&lt;td&gt;0.284 us&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;delete all&lt;/td&gt;
&lt;td&gt;0.13 ms&lt;/td&gt;
&lt;td&gt;48.63 ms&lt;/td&gt;
&lt;td&gt;374.1x slower&lt;/td&gt;
&lt;td&gt;0.973 us&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;delete 10%&lt;/td&gt;
&lt;td&gt;0.05 ms&lt;/td&gt;
&lt;td&gt;6.49 ms&lt;/td&gt;
&lt;td&gt;138.1x slower&lt;/td&gt;
&lt;td&gt;1.3 us&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;iterate 50000 entries&lt;/td&gt;
&lt;td&gt;0.07 ms&lt;/td&gt;
&lt;td&gt;1.80 ms&lt;/td&gt;
&lt;td&gt;27.7x slower&lt;/td&gt;
&lt;td&gt;0.036 us&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Operation&lt;/th&gt;
&lt;th&gt;Lua table&lt;/th&gt;
&lt;th&gt;Transient HashMap&lt;/th&gt;
&lt;th&gt;Ratio&lt;/th&gt;
&lt;th&gt;per op&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;insert 50000 random keys&lt;/td&gt;
&lt;td&gt;0.76 ms&lt;/td&gt;
&lt;td&gt;22.43 ms&lt;/td&gt;
&lt;td&gt;29.6x slower&lt;/td&gt;
&lt;td&gt;0.449 us&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;delete all&lt;/td&gt;
&lt;td&gt;0.15 ms&lt;/td&gt;
&lt;td&gt;34.16 ms&lt;/td&gt;
&lt;td&gt;232.4x slower&lt;/td&gt;
&lt;td&gt;0.683 us&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;delete 10%&lt;/td&gt;
&lt;td&gt;0.04 ms&lt;/td&gt;
&lt;td&gt;5.02 ms&lt;/td&gt;
&lt;td&gt;132.1x slower&lt;/td&gt;
&lt;td&gt;1.0 us&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;With a branching factor of 32 the situation gets worse on PUC Lua, but is slightly better on LuaJIT.
So there&amp;rsquo;s still space for fine-tuning.&lt;/p&gt;
&lt;p&gt;For hashing strings and objects I decided to use &lt;code&gt;djb2&lt;/code&gt; algorithm.
I am almost as old as this hash function, so seemed like a good fit.
JK.
The main reason to use it was that it can be implemented even if we don&amp;rsquo;t have any bit-wise operators, and Lua doesn&amp;rsquo;t have them in all of the versions.
It only uses &lt;code&gt;+&lt;/code&gt;, &lt;code&gt;*&lt;/code&gt;, and &lt;code&gt;%&lt;/code&gt; arithmetic operators, so can be done on any Lua version.
It&amp;rsquo;s prone to collisions, and I try to mitigate that by randomizing it when the library is loaded.&lt;/p&gt;
&lt;p&gt;Still, collisions do happen, but HAMT core ensures that they will still resolve correctly by implementing a deep equality function for most objects.&lt;/p&gt;
&lt;p&gt;However, when first working on this, I noticed this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;hash-map&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:io.gitlab.andreyorst.immutable.PersistentHashMap&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;{&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;hash&lt;/span&gt;} (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:io.gitlab.andreyorst.immutable.impl.hash&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;hash&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;hash-map&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:foo&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:bar&lt;/span&gt; 2))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;161272824
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;hash&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:foo&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:bar&lt;/span&gt; 2})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;161272824
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;hash-map&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;hash-map&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:foo&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:bar&lt;/span&gt; 2) 1 {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:foo&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:bar&lt;/span&gt; 2} 2)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:foo&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:bar&lt;/span&gt; 2} 2}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This is an interesting loophole. What object ended up in our hash map as a key - our persistent map or plain Lua table?
Well, that depends on insertion order:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;each &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;k&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;pairs &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;hash-map&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;hash-map&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:foo&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:bar&lt;/span&gt; 2) 1 {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:foo&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:bar&lt;/span&gt; 2} 2))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;print &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;getmetatable &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;k&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;IPersistentHashMap&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x824d9b570&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;each &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;k&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;pairs &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;hash-map&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:foo&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:bar&lt;/span&gt; 2} 2 (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;hash-map&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:foo&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:bar&lt;/span&gt; 2) 1))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;print &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;getmetatable &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;k&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To &lt;em&gt;reiterate&lt;/em&gt;, I&amp;rsquo;m creating a hash map, with a key set to another persistent hash map, and then insert a plain Lua table with the same content.
The Lua table hashes to exactly the same hash, and goes into the same bucket, but there&amp;rsquo;s no collision, because &lt;em&gt;objects are equal by value&lt;/em&gt;.
But equality of mutable collections is very loosely defined - it may be equal right now, but the next time you look at it, it&amp;rsquo;s different.
So a different hashing was needed for persistent collections, to avoid these kinds of collision.
I ended up salting persistent collections with their prototype address in memory.&lt;/p&gt;
&lt;p&gt;Other than that, the HAMT implementation is by the book, and the rest is the interface for interacting with maps.&lt;/p&gt;
&lt;p&gt;Main operations:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;new&lt;/code&gt; - construct a new map of key value pairs&lt;/li&gt;
&lt;li&gt;&lt;code&gt;assoc&lt;/code&gt; - associate a key with a value&lt;/li&gt;
&lt;li&gt;&lt;code&gt;dissoc&lt;/code&gt; - remove key from the map&lt;/li&gt;
&lt;li&gt;&lt;code&gt;conj&lt;/code&gt; - universal method for association, much like in Clojure&lt;/li&gt;
&lt;li&gt;&lt;code&gt;contains&lt;/code&gt; - check if key is in the map&lt;/li&gt;
&lt;li&gt;&lt;code&gt;count&lt;/code&gt; - map size, constant time&lt;/li&gt;
&lt;li&gt;&lt;code&gt;get&lt;/code&gt; - get a key value from a map&lt;/li&gt;
&lt;li&gt;&lt;code&gt;keys&lt;/code&gt; - get a lazy list of keys&lt;/li&gt;
&lt;li&gt;&lt;code&gt;vals&lt;/code&gt; - get a lazy list of values&lt;/li&gt;
&lt;li&gt;&lt;code&gt;transient&lt;/code&gt; - convert a map to a transient&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Coercion/conversion:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;from&lt;/code&gt; - create a map from another object&lt;/li&gt;
&lt;li&gt;&lt;code&gt;to-table&lt;/code&gt; - convert a map to a Lua table&lt;/li&gt;
&lt;li&gt;&lt;code&gt;iterator&lt;/code&gt; - get an iterator to use in Lua loops&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Transient operations:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;assoc!&lt;/code&gt; - mutable &lt;code&gt;assoc&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;dissoc!&lt;/code&gt; - mutable &lt;code&gt;dissoc&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;persistent&lt;/code&gt; - convert back to persistent variant, and mark transient as completed&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This covers most of the needs in my &lt;code&gt;fennel-cljlib&lt;/code&gt; library, as anything besides it I can implement myself, or just adapt existing implementations.&lt;/p&gt;
&lt;p&gt;A Persistent Hash Set is also available as a thin wrapper around &lt;code&gt;PersistentHashMap&lt;/code&gt; with a few method changes.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A note on &lt;code&gt;PersistentArrayMap&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;In Clojure there is a second kind of maps that are ordered, not sorted, called a Persistent Array Map.
They are used by default when defining a map with eight keys or less, like &lt;code&gt;{:foo 1 :bar 2}&lt;/code&gt;.
The idea is simple - for such a small map, a linear search through all keys is faster than with a HAMT-based map.&lt;/p&gt;
&lt;p&gt;However, in my testing on the Lua runtime, there&amp;rsquo;s no benefit in this kind of a data structure, apart from it being an ordered variant.
Lookup is slower, because of a custom equality function, which does deep comparison.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&#34;persistent-vector&#34;&gt;Persistent Vector&lt;/h3&gt;
&lt;p&gt;Persistent Vectors came next, and while the trie structure is similar to hash maps, vectors use direct index-based navigation instead of hashing, with a branching factor of 32.
Unlike maps, vector arrays in the HAMT are more densely packed, and therefore a higher branching factor is better for performance.
So lookup, update, and pop are O(log32 N), append can be considered O(1) amortized.&lt;/p&gt;
&lt;p&gt;Still, compared to plain Lua sequential tables the performance is not as good:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Median time over 7 rounds (1 warmup discarded), N = 50000 elements.
GC stopped during measurement. Clock: os.clock (CPU).
Runtime: Fennel 1.7.0-dev on PUC Lua 5.5&lt;/p&gt;
&lt;/blockquote&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Operation&lt;/th&gt;
&lt;th&gt;Lua table&lt;/th&gt;
&lt;th&gt;Persistent Vector&lt;/th&gt;
&lt;th&gt;Ratio&lt;/th&gt;
&lt;th&gt;per op&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;insert 50000 elements&lt;/td&gt;
&lt;td&gt;0.19 ms&lt;/td&gt;
&lt;td&gt;21.07 ms&lt;/td&gt;
&lt;td&gt;109.7x slower&lt;/td&gt;
&lt;td&gt;0.421 us&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;lookup 50000 random indices&lt;/td&gt;
&lt;td&gt;0.47 ms&lt;/td&gt;
&lt;td&gt;14.05 ms&lt;/td&gt;
&lt;td&gt;29.7x slower&lt;/td&gt;
&lt;td&gt;0.281 us&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;update 50000 random indices&lt;/td&gt;
&lt;td&gt;0.32 ms&lt;/td&gt;
&lt;td&gt;70.04 ms&lt;/td&gt;
&lt;td&gt;221.6x slower&lt;/td&gt;
&lt;td&gt;1.4 us&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;pop all 50000 elements&lt;/td&gt;
&lt;td&gt;0.25 ms&lt;/td&gt;
&lt;td&gt;24.34 ms&lt;/td&gt;
&lt;td&gt;96.2x slower&lt;/td&gt;
&lt;td&gt;0.487 us&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;iterate 50000 elements&lt;/td&gt;
&lt;td&gt;0.63 ms&lt;/td&gt;
&lt;td&gt;10.16 ms&lt;/td&gt;
&lt;td&gt;16.2x slower&lt;/td&gt;
&lt;td&gt;0.203 us&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Operation&lt;/th&gt;
&lt;th&gt;Lua table&lt;/th&gt;
&lt;th&gt;Transient Vector&lt;/th&gt;
&lt;th&gt;Ratio&lt;/th&gt;
&lt;th&gt;per op&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;insert 50000  elements&lt;/td&gt;
&lt;td&gt;0.19 ms&lt;/td&gt;
&lt;td&gt;7.81 ms&lt;/td&gt;
&lt;td&gt;40.3x slower&lt;/td&gt;
&lt;td&gt;0.156 us&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;update 50000 random indices&lt;/td&gt;
&lt;td&gt;0.33 ms&lt;/td&gt;
&lt;td&gt;20.76 ms&lt;/td&gt;
&lt;td&gt;62.4x slower&lt;/td&gt;
&lt;td&gt;0.415 us&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;pop all 50000 elements&lt;/td&gt;
&lt;td&gt;0.25 ms&lt;/td&gt;
&lt;td&gt;11.14 ms&lt;/td&gt;
&lt;td&gt;44.4x slower&lt;/td&gt;
&lt;td&gt;0.223 us&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;On LuaJIT:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Median time over 7 rounds (1 warmup discarded), N = 50000 elements.
GC stopped during measurement. Clock: os.clock (CPU).
Runtime: Fennel 1.7.0-dev on LuaJIT 2.1.1774896198 macOS/arm64&lt;/p&gt;
&lt;/blockquote&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Operation&lt;/th&gt;
&lt;th&gt;Lua table&lt;/th&gt;
&lt;th&gt;Persistent Vector&lt;/th&gt;
&lt;th&gt;Ratio&lt;/th&gt;
&lt;th&gt;per op&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;insert 50000 elements&lt;/td&gt;
&lt;td&gt;0.10 ms&lt;/td&gt;
&lt;td&gt;7.62 ms&lt;/td&gt;
&lt;td&gt;74.0x slower&lt;/td&gt;
&lt;td&gt;0.152 us&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;lookup 50000 random indices&lt;/td&gt;
&lt;td&gt;0.06 ms&lt;/td&gt;
&lt;td&gt;0.67 ms&lt;/td&gt;
&lt;td&gt;11.8x slower&lt;/td&gt;
&lt;td&gt;0.013 us&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;update 50000 random indices&lt;/td&gt;
&lt;td&gt;0.04 ms&lt;/td&gt;
&lt;td&gt;29.13 ms&lt;/td&gt;
&lt;td&gt;710.4x slower&lt;/td&gt;
&lt;td&gt;0.583 us&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;pop all 50000 elements&lt;/td&gt;
&lt;td&gt;0.02 ms&lt;/td&gt;
&lt;td&gt;8.62 ms&lt;/td&gt;
&lt;td&gt;410.4x slower&lt;/td&gt;
&lt;td&gt;0.172 us&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;iterate 50000 elements&lt;/td&gt;
&lt;td&gt;0.02 ms&lt;/td&gt;
&lt;td&gt;0.57 ms&lt;/td&gt;
&lt;td&gt;28.7x slower&lt;/td&gt;
&lt;td&gt;0.011 us&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Operation&lt;/th&gt;
&lt;th&gt;Lua table&lt;/th&gt;
&lt;th&gt;Transient Vector&lt;/th&gt;
&lt;th&gt;Ratio&lt;/th&gt;
&lt;th&gt;per op&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;insert 50000 elements&lt;/td&gt;
&lt;td&gt;0.05 ms&lt;/td&gt;
&lt;td&gt;0.59 ms&lt;/td&gt;
&lt;td&gt;11.6x slower&lt;/td&gt;
&lt;td&gt;0.012 us&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;update 50000 random indices&lt;/td&gt;
&lt;td&gt;0.04 ms&lt;/td&gt;
&lt;td&gt;2.06 ms&lt;/td&gt;
&lt;td&gt;51.6x slower&lt;/td&gt;
&lt;td&gt;0.041 us&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;pop all 50000 elements&lt;/td&gt;
&lt;td&gt;0.02 ms&lt;/td&gt;
&lt;td&gt;0.84 ms&lt;/td&gt;
&lt;td&gt;46.7x slower&lt;/td&gt;
&lt;td&gt;0.017 us&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;I think this is an OK performance still.
Vectors don&amp;rsquo;t use hashing, instead it is a direct index traversal via bit-shifting, so there&amp;rsquo;s no hashing, just index math.&lt;/p&gt;
&lt;p&gt;Operations on vectors include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;new&lt;/code&gt; - constructor&lt;/li&gt;
&lt;li&gt;&lt;code&gt;conj&lt;/code&gt; - append to the tail&lt;/li&gt;
&lt;li&gt;&lt;code&gt;assoc&lt;/code&gt; - change a value at given index&lt;/li&gt;
&lt;li&gt;&lt;code&gt;count&lt;/code&gt; - element count (constant time)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;get&lt;/code&gt; - get value at given index&lt;/li&gt;
&lt;li&gt;&lt;code&gt;pop&lt;/code&gt; - remove last&lt;/li&gt;
&lt;li&gt;&lt;code&gt;transient&lt;/code&gt; - convert to a transient&lt;/li&gt;
&lt;li&gt;&lt;code&gt;subvec&lt;/code&gt; - create a slice of the vector in constant time&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Transient operations:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;assoc!&lt;/code&gt; - mutable &lt;code&gt;assoc&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;conj!&lt;/code&gt; - mutable &lt;code&gt;conj&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;pop!&lt;/code&gt; - mutable &lt;code&gt;pop&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;persistent&lt;/code&gt; - convert back to persistent and finalize&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Interop:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;from&lt;/code&gt; - creates a vector from any other collection&lt;/li&gt;
&lt;li&gt;&lt;code&gt;iterator&lt;/code&gt; - returns an iterator for use in Lua loops&lt;/li&gt;
&lt;li&gt;&lt;code&gt;to-table&lt;/code&gt; - converts to a sequential Lua table&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;One notable difference in both vector and hash-map is that it allows &lt;code&gt;nil&lt;/code&gt; to be used as a value (and as a key, in case of the hash-map).
Vectors don&amp;rsquo;t have the same problem that Lua sequential tables have, where length is not well-defined if the table has holes in it.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s a debate for another time, whether allowing &lt;code&gt;nil&lt;/code&gt; as a value (and especially as a key) is a good decision to make, but Clojure already made it for me.
So for this project I decided to support it.&lt;/p&gt;
&lt;h3 id=&#34;persistent-red-black-tree&#34;&gt;Persistent Red-Black Tree&lt;/h3&gt;
&lt;p&gt;For sorted maps and sorted sets I chose Okasaki&amp;rsquo;s insertion and Germane &amp;amp; Might&amp;rsquo;s deletion algorithms.
Most of the knowledge I got from this amazing &lt;a href=&#34;https://matt.might.net/articles/red-black-delete/&#34; target=&#34;_blank&#34;&gt;blog post&lt;/a&gt; by Matt Might.&lt;/p&gt;
&lt;p&gt;I believe the operations are O(Log N), as for any binary tree, but given that the deletion algorithm is tricky, I&amp;rsquo;m not exactly sure:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Median time over 7 rounds (1 warmup discarded), N = 50000 elements.
GC stopped during measurement. Clock: os.clock (CPU).
Runtime: Fennel 1.7.0-dev on PUC Lua 5.5&lt;/p&gt;
&lt;/blockquote&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Operation&lt;/th&gt;
&lt;th&gt;Lua table&lt;/th&gt;
&lt;th&gt;PersistentTreeMap&lt;/th&gt;
&lt;th&gt;Ratio&lt;/th&gt;
&lt;th&gt;per op&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;insert 50000 random keys&lt;/td&gt;
&lt;td&gt;2.10 ms&lt;/td&gt;
&lt;td&gt;209.23 ms&lt;/td&gt;
&lt;td&gt;99.8x slower&lt;/td&gt;
&lt;td&gt;4.2 us&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;lookup 50000 random keys&lt;/td&gt;
&lt;td&gt;0.88 ms&lt;/td&gt;
&lt;td&gt;82.97 ms&lt;/td&gt;
&lt;td&gt;94.2x slower&lt;/td&gt;
&lt;td&gt;1.7 us&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;delete all&lt;/td&gt;
&lt;td&gt;0.74 ms&lt;/td&gt;
&lt;td&gt;173.76 ms&lt;/td&gt;
&lt;td&gt;234.8x slower&lt;/td&gt;
&lt;td&gt;3.5 us&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;On LuaJIT:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Median time over 7 rounds (1 warmup discarded), N = 50000 elements.
GC stopped during measurement. Clock: os.clock (CPU).
Runtime: Fennel 1.7.0-dev on LuaJIT 2.1.1774896198 macOS/arm64&lt;/p&gt;
&lt;/blockquote&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Operation&lt;/th&gt;
&lt;th&gt;Lua table&lt;/th&gt;
&lt;th&gt;PersistentTreeMap&lt;/th&gt;
&lt;th&gt;Ratio&lt;/th&gt;
&lt;th&gt;per op&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;insert 50000 random keys&lt;/td&gt;
&lt;td&gt;0.72 ms&lt;/td&gt;
&lt;td&gt;101.08 ms&lt;/td&gt;
&lt;td&gt;140.4x slower&lt;/td&gt;
&lt;td&gt;2.0 us&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;lookup 50000 random keys&lt;/td&gt;
&lt;td&gt;0.25 ms&lt;/td&gt;
&lt;td&gt;12.67 ms&lt;/td&gt;
&lt;td&gt;49.9x slower&lt;/td&gt;
&lt;td&gt;0.253 us&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;delete all&lt;/td&gt;
&lt;td&gt;0.14 ms&lt;/td&gt;
&lt;td&gt;56.14 ms&lt;/td&gt;
&lt;td&gt;403.9x slower&lt;/td&gt;
&lt;td&gt;1.1 us&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The API for sorted maps and sets is the same as to their hash counterparts with a small difference - no transients.
Clojure doesn&amp;rsquo;t do them, and I&amp;rsquo;m not doing them too.&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s all for benchmarks.
I know that there are many problems with this kind of benchmarking, so take it with a grain of salt.
Still, the results are far, far better than what I had with &lt;code&gt;itable&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;But there are two more data structures to talk about.&lt;/p&gt;
&lt;h3 id=&#34;persistent-list&#34;&gt;Persistent List&lt;/h3&gt;
&lt;p&gt;As I mentioned, I made a lazy persistent list implementation a while ago but it had its problems and I couldn&amp;rsquo;t integrate that library with the current one well enough.&lt;/p&gt;
&lt;p&gt;The main problem was that this library uses a single shared metatable per data structure, and the old implementation of lazy lists didn&amp;rsquo;t.
This difference makes it hard to check whether the object is a table, hash-map, list, vector, set, etc.
So I reimplemented them.&lt;/p&gt;
&lt;p&gt;The reason for old implementation to use different metatables was because I decided to try the approach described in &lt;a href=&#34;https://aphyr.com/posts/340-reversing-the-technical-interview&#34; target=&#34;_blank&#34;&gt;Reversing the technical interview&lt;/a&gt; post by Kyle Kingsbury (Aphyr).
I know this post is more of a fun joke, but it actually makes sense to define linked lists like that in Lua.&lt;/p&gt;
&lt;p&gt;See, tables are mutable, and you can&amp;rsquo;t do much about it.
Closures, on the other hand are much harder to mutate - you can still do it via the &lt;code&gt;debug&lt;/code&gt; module, but it&amp;rsquo;s hard, and it&amp;rsquo;s not always present.
So storing &lt;code&gt;head&lt;/code&gt; and &lt;code&gt;tail&lt;/code&gt; in function closures was a deliberate choice.&lt;/p&gt;
&lt;p&gt;However, it meant that I needed to somehow attach metadata to the function, to make it act like a data structure, and you can&amp;rsquo;t just use &lt;code&gt;setmetatable&lt;/code&gt; on a function.
Again, you can do &lt;code&gt;debug.setmetatable&lt;/code&gt; but all function objects share the same metadata table.
So, while you can do fancy things like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;comp&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;g&lt;/span&gt;] (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;] (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;g&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;function&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x7bdb320a0&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;debug.setmetatable &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[]) {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:__add&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;comp&lt;/span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;function&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x7bd17f040&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; ((&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;string.reverse &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;string.upper&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;foo&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;OOF&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You can also notice, that our &lt;code&gt;+&lt;/code&gt; overload applied to functions in the string module.&lt;/p&gt;
&lt;p&gt;So instead, we use a table, and wrap it with a metatable that has a &lt;code&gt;__call&lt;/code&gt; metamethod, essentially making our table act like a function.
This, in turn means, that we have to create two tables per list node - one to give to the user, the other to set our &lt;code&gt;__call&lt;/code&gt; and use it as a meta-table.&lt;/p&gt;
&lt;p&gt;Convoluted, I know.
It&amp;rsquo;s all in the past now - current implementation is a simple &lt;code&gt;{:head 42 :tail {...}}&lt;/code&gt; table.
Not sure what is worse.&lt;/p&gt;
&lt;p&gt;But that meant that I had to rework how lazy lists worked, because previously it was just a metatable swap.
Now list stores a &amp;ldquo;thunk&amp;rdquo;, that when called replaces itself in the node with the &lt;code&gt;:head&lt;/code&gt; and &lt;code&gt;:tail&lt;/code&gt; keys.
Unless it&amp;rsquo;s an empty list, of course - in that case we swap the metatable to an empty list one.&lt;/p&gt;
&lt;p&gt;So Lists have three metatables now:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;IPersistentList&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;IPersistentList$Empty&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;IPersistentList$Lazy&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Instead of god knows how many in the old implementation.&lt;/p&gt;
&lt;p&gt;The list interface is also better now.
Previously it was hardcoded how to construct a list from a data structure.
Current implementation also hardcodes it, but also allows to build a list in a lazy way from an iterator.&lt;/p&gt;
&lt;p&gt;This is better, because now a custom data structure that has weird iteration schema (like maps and sets in this library), we still can convert it to a list.
A general case is just:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;PersistentList.from-iterator&lt;/span&gt; #(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;pairs &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;v&lt;/span&gt;] &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;v&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Meaning that we pass a function that will produce the iterator, and a function to capture values from that iterator.
Reminds me of clojure transducers in some way.&lt;/p&gt;
&lt;h3 id=&#34;persistent-queue&#34;&gt;Persistent Queue&lt;/h3&gt;
&lt;p&gt;And the final data structure - a persistent queue.
Fast append at the end, and also fast remove from the front.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s done by holding two collections - a linked list at the front, and a persistent vector for the rear.
So removing from the list is O(1), and appending to the vector is also pretty much O(1).&lt;/p&gt;
&lt;p&gt;Interesting things start to happen when we exhaust the list part - we need to move vector&amp;rsquo;s contents into the list.
It is done by calling &lt;code&gt;PersistentList.from&lt;/code&gt; on the rear.
And building a list out of a persistent vector is an O(1) operation as well!
Well, because nothing happens, we simply create an iterator, and build the list in a lazy way.
But since indexing the vector is essentially ~O(1), we can say that we still retain this property.&lt;/p&gt;
&lt;p&gt;Or at least that&amp;rsquo;s how I reasoned about this - I&amp;rsquo;m not that good with time-complexity stuff.&lt;/p&gt;
&lt;h2 id=&#34;clojurefnl&#34;&gt;ClojureFnl&lt;/h2&gt;
&lt;p&gt;That concludes part one about ClojureFnl.&lt;/p&gt;
&lt;p&gt;I know that this post was not about ClojureFnl at all, but I had to fix my underlying implementation first.
Now, that I have better data structures to build from, I can get back working on the compiler itself.
So the next post will hopefully be about the compiler itself.&lt;/p&gt;
&lt;p&gt;Unless I get distracted again.&lt;/p&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: Clojure on Fennel part one: Persistent Data Structures&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Tue, 07 Apr 2026 02:47:00 +0300</pubDate>
    </item><item>
      <title>Implementing SSE with fnl-http and async.fnl</title>
      <link>https://andreyor.st/posts/2025-07-30-implementing-sse-with-fnl-http-and-asyncfnl/</link>
      <guid>https://andreyor.st/posts/2025-07-30-implementing-sse-with-fnl-http-and-asyncfnl/</guid>
      <description>&lt;p&gt;Some time ago, I was working on an HTTP library for Fennel.
As a proof of concept, I added a module that implements a simple web server and wanted to experiment with it.
The server can serve files from a directory using this simple handler:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;handler&lt;/span&gt; [{&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;method&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;path&lt;/span&gt; &amp;amp;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;as&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;request&lt;/span&gt;}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;method&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:GET&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;file&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;io.open &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;path&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:gsub&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;^/&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:r&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;font-weight:bold&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;file&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:status&lt;/span&gt; 404 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:body&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;not found&amp;#34;&lt;/span&gt;}))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:status&lt;/span&gt; 405
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:body&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Method not allowed&amp;#34;&lt;/span&gt;}))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This handler is simple - when the client sends a &lt;code&gt;GET&lt;/code&gt; request with a given path, for example &lt;code&gt;GET http://localhost:8080/some/file.txt&lt;/code&gt;, the handler simply removes the leading &lt;code&gt;/&lt;/code&gt; and tries to open the given path as a file handle.
If the file is present, we return it as is, and the server will handle the closure of this file once the client disconnects.
Otherwise, we return a table with the &lt;code&gt;404&lt;/code&gt; status code, indicating that the file wasn&amp;rsquo;t found.
Other methods are not allowed, and we respond with a &lt;code&gt;405&lt;/code&gt; error by matching on &lt;code&gt;method&lt;/code&gt; with &lt;code&gt;case&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Now we can require the &lt;code&gt;server&lt;/code&gt; module and start a small file-serving server:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;server&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:io.gitlab.andreyorst.fnl-http.server&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;server.start&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;handler&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:port&lt;/span&gt; 8080}))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:wait&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;(s:wait)&lt;/code&gt; call simply locks the current thread because, without it, the process will just exit.&lt;/p&gt;
&lt;p&gt;This is, of course, the simplest web server there is; it just accesses files in the current directory, returning them as &lt;code&gt;application/octet-stream&lt;/code&gt;.
The handler function can be more sophisticated, handling different methods, parsing arguments, etc.
For our purposes today, we won&amp;rsquo;t need most of these features, but I thought it would be better to familiarize you with how the server is set up.&lt;/p&gt;
&lt;p&gt;The topic of today&amp;rsquo;s post is Server-Sent Events, or SSE for short.
It is a protocol for communicating between a server and multiple clients that uses a persistent connection and pushes messages from the server to the client.
The client can then process these messages at their own pace and react accordingly.&lt;/p&gt;
&lt;p&gt;We&amp;rsquo;ll need an asynchronous library to handle SSE for multiple clients, so let&amp;rsquo;s add it to the mix:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;import-macros &lt;/span&gt;{&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;go&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;go-loop&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:io.gitlab.andreyorst.async&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;{&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;!&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;!&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;timeout&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;alts!&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chan&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;close!&lt;/span&gt; &amp;amp;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;as&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;async&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:io.gitlab.andreyorst.async&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;json&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:io.gitlab.andreyorst.json&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I&amp;rsquo;ve also included a JSON library; both are already used by &lt;code&gt;fnl-http&lt;/code&gt;.
Now, let&amp;rsquo;s begin!&lt;/p&gt;
&lt;h3 id=&#34;sse-stream&#34;&gt;SSE stream&lt;/h3&gt;
&lt;p&gt;We&amp;rsquo;ll send events to our clients via a channel:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;event-ch&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chan&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This event channel will be our main way to send events to the clients, but we won&amp;rsquo;t read from it directly.
Instead, we can create a &amp;ldquo;publication&amp;rdquo; or &lt;code&gt;pub&lt;/code&gt; that will allow clients to subscribe to the messages:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;event-pub&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;event-ch&lt;/span&gt; #&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:sse&lt;/span&gt; #(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;async.sliding-buffer&lt;/span&gt; 100)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;For the purposes of this post, there&amp;rsquo;s only one type of message in this &lt;code&gt;event-pub&lt;/code&gt; thing, but in a more complex scenario, you can separate messages and subscribe to different topics altogether.
Speaking of subscribing, here&amp;rsquo;s a helper function:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;subscribe-to-events&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;client-ch&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sub&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;event-pub&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:sse&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;client-ch&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Finally, we need a function to register an event:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;register-event&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;event&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;event-ch&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;event&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now the fun part.
Right now, our event system is ready to be accessed by clients, but the events themselves don&amp;rsquo;t make any sense, as they&amp;rsquo;re just some objects.
We&amp;rsquo;ll define events as tables with the following structure:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:event&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;optional event type&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:id&lt;/span&gt;    &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;optional event id&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:data&lt;/span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;event data&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Since our &lt;code&gt;register-event&lt;/code&gt; function simply writes to the &lt;code&gt;event-ch&lt;/code&gt;, we need a way to intercept that.
We can do so by writing middleware that accepts a channel with events as tables and returns a new channel that will have all of the events formatted:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;wrap-format-sse-event&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ch&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;out&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chan&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;go-loop&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;e&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ch&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;e&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;event&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;id&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold&#34;&gt;doto &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;out&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;!&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;event: &amp;#34;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;tostring &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;event&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\n&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;!&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;id: &amp;#34;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;tostring &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;id&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\n&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;!&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;data: &amp;#34;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;tostring &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\n&amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;event&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold&#34;&gt;doto &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;out&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;!&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;event: &amp;#34;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;tostring &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;event&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\n&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;!&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;data: &amp;#34;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;tostring &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\n&amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold&#34;&gt;doto &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;out&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;!&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;data: &amp;#34;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;tostring &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\n&amp;#34;&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;e&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;recur&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ch&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;close!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;out&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;out&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now, the general mechanism is as follows:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;When a client connects, we create a channel and subscribe to events.&lt;/li&gt;
&lt;li&gt;We wrap this channel with our formatter and some other middleware if needed.&lt;/li&gt;
&lt;li&gt;Finally, we return this channel as the response body.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Before we write an HTTP handler that does this, we need to consider one other thing: the connection.
If the connection is not used for a long time, it can be closed automatically.
Because of that, it is common to send meaningless heartbeat events every now and then.
Let&amp;rsquo;s write another wrapper that will track if the client&amp;rsquo;s event stream doesn&amp;rsquo;t have any events for some time and return a heartbeat:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;wrap-heartbeat&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ch&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;timeout-ms&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;out&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chan&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;go-loop&lt;/span&gt; []
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tout&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;timeout&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;timeout-ms&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold&#34;&gt;match &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;alts!&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tout&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ch&lt;/span&gt;])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tout&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;font-weight:bold&#34;&gt;do &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;out&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:event&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;heartbeat&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:data&lt;/span&gt; 0})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;recur&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;event&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ch&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;font-weight:bold&#34;&gt;do &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;out&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;event&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;recur&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ch&lt;/span&gt;] (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;close!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;out&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;out&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Similarly to our previous wrapper, we accept a channel with events and return a new channel.
The asynchronous &lt;code&gt;go-loop&lt;/code&gt;, which I didn&amp;rsquo;t mention before, will run in a separate virtual thread, trying to read from both the given channel and a timeout channel.
Whichever returns first will determine what event will be sent to the client.
If a normal event comes through, we send it to the &lt;code&gt;out&lt;/code&gt; channel as is and restart the timer.
If no events come and our timer has been exhausted, we send a heartbeat and restart the timer again.
If our events channel returns &lt;code&gt;nil&lt;/code&gt;, it means that it was closed, so we also close the &lt;code&gt;out&lt;/code&gt; channel.&lt;/p&gt;
&lt;p&gt;Finally, we can implement our handler:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;handler&lt;/span&gt; [{&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;path&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;method&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;headers&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;content&lt;/span&gt;}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;path&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;where&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;/events&amp;#34;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:GET&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;method&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;events&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chan&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;subscribe-to-events&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;events&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:status&lt;/span&gt; 200
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:headers&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:content-type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;text/event-stream&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:body&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;-&amp;gt; &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;events&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;wrap-heartbeat&lt;/span&gt; 10&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_000&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;wrap-format-sse-event&lt;/span&gt;)})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;where&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;/notify&amp;#34;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:POST&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;method&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;case&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;tonumber &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;headers.Content-Length&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;len&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;event&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;json.decode&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;content&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;len&lt;/span&gt;))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;register-event&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;event&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:status&lt;/span&gt; 200
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:body&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;OK&amp;#34;&lt;/span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;error &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;malformed Content-Lenght&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:status&lt;/span&gt; 405
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:headers&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:content-type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;application/json&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:body&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;json.encode&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:error&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Method not allowed&amp;#34;&lt;/span&gt;})}))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This handler has two main entry points: &lt;code&gt;/events&lt;/code&gt; and &lt;code&gt;/notify&lt;/code&gt;.
The &lt;code&gt;/events&lt;/code&gt; entry is for subscribing to the events stream with a &lt;code&gt;GET&lt;/code&gt; request.
The &lt;code&gt;/notify&lt;/code&gt; entry is for sending events from the client to the server (because right now we don&amp;rsquo;t want to make the server too complicated to generate events on its own).&lt;/p&gt;
&lt;p&gt;Same as before, we can start a server:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;server.start&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;handler&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:port&lt;/span&gt; 12345}))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:wait&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;reading-the-event-stream-and-triggering-events&#34;&gt;Reading the event stream and triggering events&lt;/h3&gt;
&lt;p&gt;With the server up and running, we can connect a pair of clients.&lt;/p&gt;
&lt;p&gt;The first client will subscribe to the event stream by executing a &lt;code&gt;GET&lt;/code&gt; request:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;http&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:io.gitlab.andreyorst.fnl-http.client&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;resp&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;http.get&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;http://localhost:12345/events&amp;#34;&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:as&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:stream&lt;/span&gt;}))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If we look at the response, we&amp;rsquo;ll see the headers containing &lt;code&gt;text/event-stream&lt;/code&gt; as the content type, as per the response from our server, and the body as a stream, as requested by the client:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:body&lt;/span&gt; #&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;Reader&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x564ae85ca7d0&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:headers&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Connection&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;keep-alive&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Content-Type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;text/event-stream&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Transfer-Encoding&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;chunked&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:http-client&lt;/span&gt; #&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;tcp-client&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x564ae812fa10&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:protocol-version&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:major&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:minor&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;HTTP&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:reason-phrase&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;OK&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:request-time&lt;/span&gt; 38
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:status&lt;/span&gt; 200
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:trace-redirects&lt;/span&gt; {}}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We can consume events with a helper function:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;consume-events&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;stream&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-line&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;stream&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buf&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;stream&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; 1)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;when &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;not= &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\n&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;table.insert &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buf&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-line&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;stream&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buf&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;while &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buf&lt;/span&gt; []]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-line&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;stream&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buf&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;io.write &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;[&amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;os.date&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;]\t&amp;#34;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;table.concat &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buf&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\n&amp;#34;&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;consume-events&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;resp.body&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In the process output, we&amp;rsquo;ll be able to see heartbeat events appearing every ten seconds:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[Wed Jul 30 00:34:35 2025]	event: heartbeat
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[Wed Jul 30 00:34:45 2025]	data: 0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[Wed Jul 30 00:34:45 2025]	event: heartbeat
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[Wed Jul 30 00:34:55 2025]	data: 0
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Next, we can send a &lt;code&gt;POST&lt;/code&gt; request from another process, sending an event:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;http&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:io.gitlab.andreyorst.fnl-http.client&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;json&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:io.gitlab.andreyorst.json&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;http.post&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;http://localhost:12345/notify&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:body&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;json.encode&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:event&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;message&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:id&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;client-2&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:data&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Hi from client-2&amp;#34;&lt;/span&gt;})})
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We immediately see the event in the first client&amp;rsquo;s output, followed by heartbeat events:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[Wed Jul 30 00:35:03 2025]	event: message
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[Wed Jul 30 00:35:03 2025]	id: client-2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[Wed Jul 30 00:35:03 2025]	data: Hi from client-2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[Wed Jul 30 00:35:03 2025]	event: heartbeat
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[Wed Jul 30 00:35:13 2025]	data: 0
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As you can see, the time when the heartbeat event arrived is exactly ten seconds after the last non-heartbeat event.
Of course, we can connect multiple clients subscribed to the event stream, and they will all receive events.&lt;/p&gt;
&lt;h2 id=&#34;conclusion&#34;&gt;Conclusion&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/h2&gt;
&lt;p&gt;This should give you an idea of how to implement an SSE stream in your server using the &lt;code&gt;fnl-http&lt;/code&gt; library.
Of course, this implementation is only loosely based on the specification, so I wouldn&amp;rsquo;t suggest it as a general implementation guide, but I hope it provides a clear enough explanation of how things work.&lt;/p&gt;
&lt;p&gt;The server module is still very much in a proof-of-concept stage, but as this article shows, it is working quite well.
All in all, I believe the ability to return an asynchronous channel as a body from the server is a nice way to handle this kind of event system.
The code can be written as usual, and no specific handling for returning asynchronous data via HTTP is required.&lt;/p&gt;
&lt;p&gt;Thanks for reading, and I hope you&amp;rsquo;ll find &lt;a href=&#34;https://gitlab.com/andreyorst/fnl-http&#34; target=&#34;_blank&#34;&gt;fnl-http&lt;/a&gt; interesting enough to try!&lt;/p&gt;
&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;
&lt;p&gt;As much as I don&amp;rsquo;t like &amp;ldquo;Conclusion&amp;rdquo; as the last heading in an article, I can&amp;rsquo;t think of a different one here.&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: Implementing SSE with fnl-http and async.fnl&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Wed, 30 Jul 2025 01:05:00 +0300</pubDate>
    </item><item>
      <title>Implementing dynamic scope for Fennel and Lua</title>
      <link>https://andreyor.st/posts/2025-06-09-implementing-dynamic-scope-for-fennel-and-lua/</link>
      <guid>https://andreyor.st/posts/2025-06-09-implementing-dynamic-scope-for-fennel-and-lua/</guid>
      <description>&lt;p&gt;I&amp;rsquo;m continuing my work on &lt;a href=&#34;https://gitlab.com/andreyorst/fennel-cljlib&#34; target=&#34;_blank&#34;&gt;fennel-cljlib&lt;/a&gt;, my port of &lt;code&gt;clojure.core&lt;/code&gt; and some other core libraries, focusing on porting missing functions and features to it.
One such feature, which I sometimes miss in Lua and Fennel, is &lt;a href=&#34;https://en.wikipedia.org/wiki/Scope_%28computer_science%29#Dynamic_scope&#34; target=&#34;_blank&#34;&gt;dynamic binding&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The Lua VM doesn&amp;rsquo;t provide dynamic scoping as a language feature, and Fennel itself doesn&amp;rsquo;t introduce any concepts like Clojure&amp;rsquo;s &lt;code&gt;Var&lt;/code&gt;.
However, we can still implement dynamic scoping that works similarly to Clojure and other Lisps using the &lt;code&gt;debug&lt;/code&gt; library.
Most of the ideas are based on information from the &lt;a href=&#34;https://leafo.net/guides.html&#34; target=&#34;_blank&#34;&gt;guides&lt;/a&gt; at &lt;a href=&#34;https://leafo.net/&#34; target=&#34;_blank&#34;&gt;leafo.net&lt;/a&gt;.
There&amp;rsquo;s even a &lt;a href=&#34;https://leafo.net/guides/dynamic-scoping-in-lua.html&#34; target=&#34;_blank&#34;&gt;&amp;ldquo;Dynamic scoping in Lua&amp;rdquo;&lt;/a&gt; guide that implements a slightly different version of this feature, requiring variables to be referenced by name via &lt;code&gt;dynamic(&amp;quot;var_name&amp;quot;)&lt;/code&gt; call.
While this approach is feasible, I wanted something more in line with how other Lisps work, so let&amp;rsquo;s explore advancing it further.
Luckily for us, Leafo already has all the necessary guides!&lt;/p&gt;
&lt;p&gt;But first things first.
I wanted to delay working on dynamic scoping as much as possible because it is a feature that&amp;rsquo;s hard to get right.
I already have some experience with implementing dynamic scoping for one of my older libraries that implemented a &lt;a href=&#34;https://gitlab.com/andreyorst/fennel-conditions&#34; target=&#34;_blank&#34;&gt;condition system&lt;/a&gt; from Common Lisp in Fennel.
This library, however, required special syntax to access all of the dynamically bound symbols and thus did not actually require anything fancy for it to work.&lt;/p&gt;
&lt;p&gt;So what does dynamic binding/scoping mean in a language?
If you know about lexical and dynamic scoping and wish to skip this tangent, feel free to &lt;a href=&#34;#implementing-dynamic-scope-in-fennel&#34;&gt;do so&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In short, lexically scoped variables exist only where their lexical scope allows them to.
For example, a variable defined in a block of code will only exist in that block because it is its lexical scope.&lt;/p&gt;
&lt;p&gt;When working with languages that have higher-order functions, I often find myself in a situation where I want to refactor some code that uses anonymous functions by moving them out and giving them a name.
Sometimes it&amp;rsquo;s possible; sometimes it&amp;rsquo;s not.&lt;/p&gt;
&lt;p&gt;For example, imagine I wanted to move out this function from &lt;code&gt;map&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;some-func&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;messages&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;extra-data&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;other-func&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;map&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;do-stuff&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;extra-data&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;messages&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If I were to do so, we would have a problem:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;process-message&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; oops, extra-data is now an unknown variable&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;do-stuff&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;extra-data&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;some-func&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;messages&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;extra-data&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;other-func&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;map&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;process-message&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;messages&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So &lt;code&gt;extra-data&lt;/code&gt; is bound lexically, and thus if we look at the lexical scope of the &lt;code&gt;process-messages&lt;/code&gt; function, we&amp;rsquo;ll see that it tries to use &lt;code&gt;extra-data&lt;/code&gt; while it&amp;rsquo;s not defined there.
If &lt;code&gt;extra-data&lt;/code&gt; were a global variable, it wouldn&amp;rsquo;t be problematic, but it is a local variable with a lexical scope.
We could move the entire &lt;code&gt;let&lt;/code&gt; that binds &lt;code&gt;extra-data&lt;/code&gt; to the result of calling &lt;code&gt;other-func&lt;/code&gt;, but let&amp;rsquo;s say we don&amp;rsquo;t want to call it on each iteration of a &lt;code&gt;map&lt;/code&gt; because it&amp;rsquo;s slow and will do the same work repeatedly.
So, what are our options here?&lt;/p&gt;
&lt;p&gt;Well, we can make it a closure!&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;make-message-processor&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;extra-data&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;process-message&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;do-stuff&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;extra-data&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;some-func&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;messages&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;extra-data&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;other-func&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;map&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;make-message-processor&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;extra-data&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;messages&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now, we pass &lt;code&gt;extra-data&lt;/code&gt; only once to the &lt;code&gt;make-message-processor&lt;/code&gt; function, and it returns a function that has this variable stored in a closure.
However, this is still a lexical scope because, as you can see, &lt;code&gt;extra-data&lt;/code&gt; is present there.&lt;/p&gt;
&lt;p&gt;In a language that uses dynamic scoping, this could be a whole different story.
Let&amp;rsquo;s look at Clojure; although I wouldn&amp;rsquo;t recommend doing it this way, it is possible to do it this way&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;process-message&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;do-stuff&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;extra-data&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;some-func&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;messages&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;binding &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;extra-data&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;other-func&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mapv&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;process-message&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;messages&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Here, I assume that &lt;code&gt;extra-data&lt;/code&gt; is a dynamic variable that obeys the rules of dynamic scoping.
The &lt;code&gt;binding&lt;/code&gt; call introduces a dynamic scope within which &lt;code&gt;extra-data&lt;/code&gt; is set to the value of &lt;code&gt;(other-func)&lt;/code&gt;.
It acts more like a scoped global variable, or at least you can think of it that way.&lt;/p&gt;
&lt;p&gt;To introduce a dynamic scope, Clojure uses &lt;code&gt;binding&lt;/code&gt;.
Let&amp;rsquo;s look at it briefly:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defmacro &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;binding&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;binding =&amp;gt; var-symbol init-expr
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;  Creates new bindings for the (already-existing) vars, with the
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;  supplied initial values, executes the exprs in an implicit do, then
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;  re-establishes the bindings that existed before.  The new bindings
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;  are made in parallel (unlike let); all init-exprs are evaluated
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;  before the vars are bound to their new values.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:added&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;1.0&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bindings&lt;/span&gt; &amp;amp; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;body&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;assert-args&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;vector? &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bindings&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;a vector for its binding&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;even?&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;count &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bindings&lt;/span&gt;)) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;an even number of forms in binding vector&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;var-ize&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;var-vals&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  (&lt;span style=&#34;font-weight:bold&#34;&gt;loop &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ret&lt;/span&gt; [] &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vvs&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;seq &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;var-vals&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vvs&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;recur&lt;/span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;conj &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;conj &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ret&lt;/span&gt; `(&lt;span style=&#34;font-weight:bold&#34;&gt;var &lt;/span&gt;~(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;first &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vvs&lt;/span&gt;))) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;second &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vvs&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                             (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;next &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;next &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vvs&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;seq &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ret&lt;/span&gt;))))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    `(&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;push-thread-bindings&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;hash-map &lt;/span&gt;~@(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;var-ize&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bindings&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;try&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         ~@&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;body&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;finally&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pop-thread-bindings&lt;/span&gt;))))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It&amp;rsquo;s a simple idea: a &lt;code&gt;try&lt;/code&gt; block without &lt;code&gt;catch&lt;/code&gt; statements, only with a &lt;code&gt;finally&lt;/code&gt; clause.
Before we enter the &lt;code&gt;try&lt;/code&gt; block, we set all mentioned variables to their values, and after we&amp;rsquo;re done with the &lt;code&gt;body&lt;/code&gt;, we restore those values.&lt;/p&gt;
&lt;p&gt;In Clojure, dynamic bindings work really well, but this is due to a combination of factors.
First, the &lt;code&gt;try&lt;/code&gt; support in the JVM is excellent, ensuring that &lt;code&gt;finally&lt;/code&gt; will perform its intended function.
Additionally, the JVM supports thread-local bindings, so even in a multithreaded context, &lt;code&gt;binding&lt;/code&gt; still works.
&lt;em&gt;Finally&lt;/em&gt;, heh, Clojure has Vars, which makes it all possible.&lt;/p&gt;
&lt;p&gt;Now, let&amp;rsquo;s try to implement the same concept in Fennel!&lt;/p&gt;
&lt;h2 id=&#34;implementing-dynamic-scope-in-fennel&#34;&gt;Implementing dynamic scope in Fennel&lt;/h2&gt;
&lt;p&gt;Before I descend into madness, I would say that we could do the same thing as in Clojure: set some variables, run code in a protected call, and reset the variables afterward.
While this approach would indeed work, I wanted to tidy up my understanding of function environments in Lua.
It&amp;rsquo;s a neat concept that Lua and a few other languages have, but Lua is one of the few languages that actually allows users to manipulate function environments.
So, let&amp;rsquo;s explore this idea.&lt;/p&gt;
&lt;p&gt;First, we need a way to forcefully set a function&amp;rsquo;s environment.
This could be done in Lua 5.1 via &lt;code&gt;setfenv&lt;/code&gt;; however, it was removed starting from Lua 5.2 onward.
It can be implemented like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;setfenv&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_G.setfenv&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;setfenv&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;env&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; 1)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;case&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;debug.getupvalue &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:_ENV&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;doto &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;debug.upvaluejoin &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[] &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;env&lt;/span&gt;) 1))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;setfenv&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;env&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; 1)))))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now, we can set an environment for any function.&lt;/p&gt;
&lt;p&gt;But what exactly is this function environment? I&amp;rsquo;ve realized that I never explained that, so here we go.&lt;/p&gt;
&lt;p&gt;In Lua, the environment is a table&lt;sup id=&#34;fnref:2&#34;&gt;&lt;a href=&#34;#fn:2&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;2&lt;/a&gt;&lt;/sup&gt; that stores the names of the variables.
Starting from Lua 5.2, the environment is represented by a variable called &lt;code&gt;_ENV&lt;/code&gt;, which is what we&amp;rsquo;re testing for in &lt;code&gt;setfenv&lt;/code&gt; above.
By default, &lt;code&gt;_ENV&lt;/code&gt; has the same value as &lt;code&gt;_G&lt;/code&gt;, a table that contains all global variables.
However, we can change the function&amp;rsquo;s environment by modifying the value of &lt;code&gt;_ENV&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;For instance, in Lua, we can set &lt;code&gt;_ENV&lt;/code&gt; to a table, and all global definitions would end up in that table:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;a = 0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; (t)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    _ENV = t
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    a = 42
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    b = 322
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; t
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; t = {}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;f(t)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;print(a, b) &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- 0, nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;print(t.a, t.b) &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- 42, 322&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This is a cool feature, and we can actually use environments for sandboxing code, but that&amp;rsquo;s a story for another time.
Let&amp;rsquo;s return to dynamic scoping.&lt;/p&gt;
&lt;p&gt;Looking at this, you might get the idea that if we change the function&amp;rsquo;s environment and set our dynamic variables in it specifically, once we leave the lexical scope of that &lt;code&gt;_ENV&lt;/code&gt;, all changes revert to normal because they never happened in a global environment!&lt;/p&gt;
&lt;p&gt;Unfortunately, it&amp;rsquo;s not that simple.
Yes, we can change the function&amp;rsquo;s environment, but it will only affect that specific function.
Moreover, this change is permanent, meaning that we&amp;rsquo;ll have to reset the function back to its original environment.
So, it&amp;rsquo;s not as straightforward as just changing &lt;code&gt;_ENV&lt;/code&gt; around the code we want to run.
Of course, we could write &lt;code&gt;getfenv&lt;/code&gt;, then wrap the entire thing in a &lt;code&gt;pcall&lt;/code&gt;, and safely restore the environment once the work is done.&lt;/p&gt;
&lt;p&gt;However, we can&amp;rsquo;t set the environment of just the function we&amp;rsquo;re calling.
&lt;code&gt;_ENV&lt;/code&gt; is stored in a closure, so we&amp;rsquo;ll need to change all of the functions called by the function we wish to invoke with a custom environment.
This makes undoing changes trickier to implement.&lt;/p&gt;
&lt;p&gt;Luckily for us, we can bypass the need to roll back the changes to the function&amp;rsquo;s environment completely!
Instead, we can simply clone the function and set its environment as we wish!
Here&amp;rsquo;s an implementation:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clone-function-with-env&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;env&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Recursively clones the function `f`, and any subsequent functions that it
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;might call via upvalues.  Sets `env` as environment for the cloned function.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dumped&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;string.dump &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cloned&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;load &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dumped&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;var &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;done?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold&#34;&gt;values &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;false&lt;/span&gt; 1))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;while &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;not &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;done?&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;case&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;debug.getupvalue &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;where&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;val&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:function&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;type &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;val&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;subf&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clone-function-with-env&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;val&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;env&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;debug.setupvalue &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cloned&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;subf&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;debug.upvaluejoin &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cloned&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;done?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;true&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; 1)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;setfenv&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cloned&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;env&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Finally, we write the function that will call a given function &lt;code&gt;f&lt;/code&gt; in a context where the given &lt;code&gt;bindings&lt;/code&gt; are dynamically bound:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dynamic-call&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bindings&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Calls `f` with `bindings` as its root environment.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;new-env&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;setmetatable &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bindings&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:__index&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_ENV&lt;/span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f*&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clone-function-with-env&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;new-env&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f*&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As well, as a convenience macro for using it like a &lt;code&gt;let&lt;/code&gt; but with dynamic binding:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;macro &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;binding&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bindings&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;assert-compile&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sequence?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bindings&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;expected a sequence of bindings&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bindings&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;assert-compile&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   (&lt;span style=&#34;font-weight:bold&#34;&gt;= &lt;/span&gt;0 (&lt;span style=&#34;font-weight:bold&#34;&gt;% &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;length &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bindings&lt;/span&gt;) 2))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;expected an even number of forms in binding sequence&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bindings&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  `(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dynamic-call&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;&#34;&gt;,&lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;faccumulate&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt; {} &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; 1 (&lt;span style=&#34;font-weight:bold&#34;&gt;length &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bindings&lt;/span&gt;) 2]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;font-weight:bold&#34;&gt;doto &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         (&lt;span style=&#34;font-weight:bold&#34;&gt;tset &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;tostring &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bindings&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt;)) (&lt;span style=&#34;font-weight:bold&#34;&gt;. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bindings&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; 1)))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[] &lt;span style=&#34;&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now we can use dynamic binding in Fennel!&lt;/p&gt;
&lt;h3 id=&#34;usage-example&#34;&gt;Usage example&lt;/h3&gt;
&lt;p&gt;To illustrate, let&amp;rsquo;s create some variables that we wish to treat dynamically:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;global &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;foo&lt;/span&gt; 21)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;global &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bar&lt;/span&gt; 73)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;print &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;foo&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bar&lt;/span&gt;) &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; 21	73&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With globals in place, we can try our &lt;code&gt;binding&lt;/code&gt; macro:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;binding&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;foo&lt;/span&gt; 42]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;print &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;foo&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bar&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; 42 73&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As can be seen, &lt;code&gt;foo&lt;/code&gt; no longer refers to &lt;code&gt;21&lt;/code&gt;, but now it is &lt;code&gt;42&lt;/code&gt;.
However, if we try to print &lt;code&gt;foo&lt;/code&gt; outside of &lt;code&gt;binding&lt;/code&gt;&amp;rsquo;s scope, we will again get &lt;code&gt;21&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;binding&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;foo&lt;/span&gt; 42]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;print &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;foo&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; 42&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;print &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;foo&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; 21&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;A keen reader would mention that this example is not so different from using a plain &lt;code&gt;let&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;foo&lt;/span&gt; 42]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;print &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;foo&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; 42&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;print &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;foo&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; 21&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And you&amp;rsquo;d be right!
However, where it&amp;rsquo;s going to be different is when we put functions into the mix:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; []
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;print &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;f:&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;foo&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bar&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;How, if we were to call it inside of &lt;code&gt;let&lt;/code&gt;, the bindings introduced by it won&amp;rsquo;t affect the function, because both &lt;code&gt;foo&lt;/code&gt; and &lt;code&gt;bar&lt;/code&gt; are not lexically present here:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;foo&lt;/span&gt; 42
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bar&lt;/span&gt; 1337]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; still prints:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; f: 21 73&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This is where &lt;code&gt;binding&lt;/code&gt; jumps in.
Instead of following lexical binding rules, that are natural for most languages, we now introduce dynamic binding of &lt;code&gt;foo&lt;/code&gt; and &lt;code&gt;bar&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;binding&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;foo&lt;/span&gt; 42
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bar&lt;/span&gt; 1337]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; prints:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; f: 42 1337&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; prints:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; f: 21 73&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And, as can be seen above, inside &lt;code&gt;binding&lt;/code&gt;&amp;rsquo;s scope, &lt;code&gt;f&lt;/code&gt; sees &lt;code&gt;foo&lt;/code&gt; as &lt;code&gt;42&lt;/code&gt;, and &lt;code&gt;bar&lt;/code&gt; as &lt;code&gt;1337&lt;/code&gt;, while outside of it, the values are still &lt;code&gt;21&lt;/code&gt; and &lt;code&gt;73&lt;/code&gt;.
So, we never actually changed the values of &lt;code&gt;foo&lt;/code&gt; and &lt;code&gt;bar&lt;/code&gt;, they&amp;rsquo;re still &lt;code&gt;21&lt;/code&gt; and &lt;code&gt;73&lt;/code&gt;, respectfully.
Instead, in the scope of &lt;code&gt;binding&lt;/code&gt; we changed how &lt;code&gt;f&lt;/code&gt; accesses these variables.&lt;/p&gt;
&lt;p&gt;This also works with functions that call other functions:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; []
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;print &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;f:&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;foo&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;g&lt;/span&gt; []
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;print &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;g:&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bar&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;h&lt;/span&gt; []
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ((&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[] (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;print &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;h:&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;foo&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bar&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;binding&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;foo&lt;/span&gt; 42
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bar&lt;/span&gt; 322]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; prints:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; f: 42&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;g&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; prints:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; f: 42&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; g: 322&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;h&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; prints:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; h: 42 322&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  )
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That&amp;rsquo;s pretty much it!
This approach has a lot of flaws though.&lt;/p&gt;
&lt;p&gt;First, it will only work on ordinary functions, so no tricks with &lt;code&gt;__call&lt;/code&gt; metamethod, or native functions are supported.&lt;/p&gt;
&lt;p&gt;Second, it won&amp;rsquo;t work with coroutines either.
You can&amp;rsquo;t use &lt;code&gt;string.dump&lt;/code&gt; on something like &lt;code&gt;coroutine.resume&lt;/code&gt; directly, so we won&amp;rsquo;t be able to do &lt;code&gt;(dynamic-call {:foo 42} coroutine.resume some-coroutine)&lt;/code&gt;.
It won&amp;rsquo;t even work if we wrap &lt;code&gt;coroutine.resume&lt;/code&gt; into an anonymous function like &lt;code&gt;(dynamic-call {:foo 42} (fn [] (coroutine.resume coro)))&lt;/code&gt;, because &lt;code&gt;coro&lt;/code&gt; here, while being an upvalue, is not a function, so we can&amp;rsquo;t clone it.&lt;/p&gt;
&lt;p&gt;Finally, it relies on the &lt;code&gt;debug&lt;/code&gt; library, and recursive function dumping, which itself is already pretty crazy.&lt;/p&gt;
&lt;p&gt;There are probably more things that can go wrong with this.&lt;/p&gt;
&lt;h2 id=&#34;so-why-not-just-set-the-globals-temporarily&#34;&gt;So why not just set the globals temporarily?&lt;/h2&gt;
&lt;p&gt;First of all, yes, we could just set the globals temporarily, and restore their values later:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;set-globals&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;globals&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;collect &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;new-val&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;pairs &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;globals&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;old-val&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;. &lt;/span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;_G &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;set &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;. &lt;/span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;_G &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;new-val&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;values &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;old-val&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;close-handler&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;old-vals&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ok?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;each &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;val&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;pairs &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;old-vals&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;set &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;. &lt;/span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;_G &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;val&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ok?&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;error &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt; 0)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;call-with-temp-globals&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;globals&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;-&amp;gt; &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;globals&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;set-globals&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;close-handler&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;pcall &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;call-with-temp-globals&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:foo&lt;/span&gt; 123 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:bar&lt;/span&gt; 456} &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;g&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; prints:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; f: 123&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; g: 456&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;g&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; prints:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; f: 21&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; g: 73&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;While this works, I don&amp;rsquo;t like the idea that we&amp;rsquo;re actually changing the values instead of shadowing them in the environment, though this is more akin to the original Clojure implementation.
Since Lua is single-threaded it should not be problematic, however, I think it can still mess things up if we were to introduce some kind of an asynchronous scheduler, like in my &lt;a href=&#34;https://gitlab.com/andreyorst/async.fnl&#34; target=&#34;_blank&#34;&gt;async.fnl&lt;/a&gt; library.
This also messes up stacktraces in cases where an error occurs as a result of calling &lt;code&gt;f&lt;/code&gt; because you can&amp;rsquo;t re-throw errors in Lua like in other languages.
There&amp;rsquo;s also a potential to use &lt;code&gt;&amp;lt;close&amp;gt;&lt;/code&gt; marker that came in Lua 5.4 to avoid &lt;code&gt;pcall&lt;/code&gt; altogether:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;set_globals&lt;/span&gt;(globals)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; old_values = {}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;for&lt;/span&gt; name, new_val &lt;span style=&#34;font-weight:bold&#34;&gt;in&lt;/span&gt; pairs(globals) &lt;span style=&#34;font-weight:bold&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        old_values[name] = _G[name]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        _G[name] = new_val
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; old_values
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;close_handler&lt;/span&gt;(old_values)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;for&lt;/span&gt; name, val &lt;span style=&#34;font-weight:bold&#34;&gt;in&lt;/span&gt; pairs(old_values) &lt;span style=&#34;font-weight:bold&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        _G[name] = val
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dynamic_call_close&lt;/span&gt;(globals, f, ...)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; old_values &amp;lt;close&amp;gt; =
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        setmetatable(set_globals(globals), {__close = close_handler})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; f(...)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This would keep stack traces intact, and values would be restored right when we exit &lt;code&gt;dynamic_call_close&lt;/code&gt; but will only work in Lua 5.4.&lt;/p&gt;
&lt;p&gt;Thus, while doing it with &lt;code&gt;pcall&lt;/code&gt; is more generic, I wanted to explore the environment approach first since Lua already provides a mechanism for working with function environments.
But for now, I think I&amp;rsquo;ll leave dynamic scoping out of &lt;code&gt;cljlib&lt;/code&gt; as I&amp;rsquo;m not really sold on any of the ways of doing it that I&amp;rsquo;ve come up with so far.&lt;/p&gt;
&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;
&lt;p&gt;I really don&amp;rsquo;t like this way of refactoring this code, but sometimes it is exactly what you need.
Not this time, though.
The approach with closures is what I&amp;rsquo;d use in this case in Clojure too.&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:2&#34;&gt;
&lt;p&gt;Everything in Lua is a table, because of course it is.&amp;#160;&lt;a href=&#34;#fnref:2&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: Implementing dynamic scope for Fennel and Lua&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Mon, 09 Jun 2025 22:31:00 +0300</pubDate>
    </item><item>
      <title>Dynamic font-lock for Fennel</title>
      <link>https://andreyor.st/posts/2025-03-10-dynamic-font-lock-for-fennel/</link>
      <guid>https://andreyor.st/posts/2025-03-10-dynamic-font-lock-for-fennel/</guid>
      <description>&lt;p&gt;I&amp;rsquo;ve been working on adding a dynamic font-locking for &lt;a href=&#34;https://git.sr.ht/~technomancy/fennel-mode&#34; target=&#34;_blank&#34;&gt;fennel-mode&lt;/a&gt; for a while now.
The first attempt started years ago, in July 2022, and were quite crude.
It consisted of sending a special code to the REPL that would return me a list of macro names, and then I created a regular expression that matched all these names for syntax highlighting.
This had several problems.&lt;/p&gt;
&lt;p&gt;First, this meant that any macro known to the REPL would be highlighted.
This is not great, as macros in Fennel can be loaded from any file that you require, but it doesn&amp;rsquo;t mean that they&amp;rsquo;re available to your file in particular.&lt;/p&gt;
&lt;p&gt;For example, imagine you have this code:&lt;/p&gt;
&lt;figure class=&#34;invertable&#34;&gt;&lt;img src=&#34;https://andreyor.st/2025-03-10-dynamic-font-lock-for-fennel/bad-hl.png&#34;
         alt=&#34;Figure 1: All code in this post will be provided as images to better show code highlighting&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 1: &lt;/span&gt;All code in this post will be provided as images to better show code highlighting&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;As you can see, this code requires the module &lt;code&gt;:foo&lt;/code&gt;, defines a few functions, and finally calls them.
Ignore the fact that the module &lt;code&gt;foo&lt;/code&gt; is unused for now - turn your attention to the colors instead.&lt;/p&gt;
&lt;p&gt;As you can see, &lt;code&gt;fennel-mode&lt;/code&gt; uses colors to tell the user a few things.
Special forms and macros are highlighted in a blueish color.
Inbuilt functions are highlighted in purple.
Names of declared functions are also in purple, but not their calls.&lt;/p&gt;
&lt;p&gt;However, you can see that for some reason, &lt;code&gt;bar&lt;/code&gt; is highlighted blue, as if it was a special or a macro.
This is because I&amp;rsquo;m using my old implementation of dynamic highlighting.
If we look into the &lt;code&gt;foo&lt;/code&gt; module, we&amp;rsquo;ll see that it requires a macro module, that defines &lt;code&gt;bar&lt;/code&gt; as a macro.
It&amp;rsquo;s not a problem - macros in Fennel are only available in the module they&amp;rsquo;re required, so there&amp;rsquo;s no name conflict here, as you would expect.
However, highlighting is not very smart.&lt;/p&gt;
&lt;p&gt;When syntax highlighting is applied, a request is sent to the REPL to get all available macros.
Then no distinction is made for where these macros are coming from, hence the wrong highlighting.&lt;/p&gt;
&lt;p&gt;Another tricky case, that I don&amp;rsquo;t see implemented around is scoping:&lt;/p&gt;
&lt;figure class=&#34;invertable&#34;&gt;&lt;img src=&#34;https://andreyor.st/2025-03-10-dynamic-font-lock-for-fennel/bad-scoping.png&#34;
         alt=&#34;Figure 2: Like, imagine, otherwise I&amp;amp;rsquo;d have to do this highlighting in CSS manually&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 2: &lt;/span&gt;Like, imagine, otherwise I&amp;rsquo;d have to do this highlighting in CSS manually&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;In Fennel, the &lt;code&gt;macro&lt;/code&gt; special, which is used to define macros, obeys the scoping rules.
Thus when we create a macro inside of the &lt;code&gt;do&lt;/code&gt;&amp;rsquo;s scope, this macro should not be highlighted outside of it.
But again, because the initial implementation of dynamic highlighting didn&amp;rsquo;t care about anything but macro names, the macro was incorrectly highlighted in this case as well.&lt;/p&gt;
&lt;p&gt;Because of these problems, Phil and I decided that this won&amp;rsquo;t be a good feature to bring into &lt;code&gt;fennel-mode&lt;/code&gt; in this state.
The branch rested for almost three years, up until recently, when I started working on &lt;code&gt;fennel-mode&lt;/code&gt; again.&lt;/p&gt;
&lt;p&gt;Recently, I added support for Flymake via the &lt;a href=&#34;https://git.sr.ht/~xerool/fennel-ls/&#34; target=&#34;_blank&#34;&gt;fennel-ls&lt;/a&gt; language server.
That was another old branch of mine, where I added linting via Fennel&amp;rsquo;s own linter plugin, but Phil mentioned that the plugin was never supposed to be used like this.
It was also suggested that since &lt;code&gt;fennel-ls&lt;/code&gt; already existed back then, and it was working with &lt;code&gt;eglot&lt;/code&gt; there was no real need for using Flymake with Fennel&amp;rsquo;s linter plugin.&lt;/p&gt;
&lt;p&gt;I gave this branch a rest, and after a while, when I started using &lt;code&gt;fennel-ls&lt;/code&gt; myself, I decided to contribute a small change so that it could be used from Flymake.
Personally, I don&amp;rsquo;t need a full-blown language server for Fennel, because everything I need is provided by the Fennel Proto REPL, but I do want some linting capabilities.
So after merging the Flymake branch into the main &lt;code&gt;fennel-mode&lt;/code&gt; branch, I noticed this old &lt;code&gt;dynamic-font-lock&lt;/code&gt; branch, and decided that &amp;ldquo;it&amp;rsquo;s time to do this&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;Thus, I&amp;rsquo;m happy to announce, that all the problems listed above were fixed!
Take a look at this:&lt;/p&gt;
&lt;figure class=&#34;invertable&#34;&gt;&lt;img src=&#34;https://andreyor.st/2025-03-10-dynamic-font-lock-for-fennel/highlighting-not-yet-applied.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;Of course, when we just load the file, nothing is highlighted yet, as the syntax highlighting is dynamic.
However, when we load the module into the REPL, the highlighting is applied correctly:&lt;/p&gt;
&lt;figure class=&#34;invertable&#34;&gt;&lt;img src=&#34;https://andreyor.st/2025-03-10-dynamic-font-lock-for-fennel/good-hl.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;Once the module is loaded, highlighting is cached, and no further requests to the REPL are sent.
This doesn&amp;rsquo;t, however, mean that when we change the code, the highlighting won&amp;rsquo;t react:&lt;/p&gt;
&lt;p&gt;&lt;video autoplay loop muted style=&#34;border-radius: 16px&#34; class=&#34;invertable&#34;&gt;&lt;source src=&#34;https://andreyor.st/2025-03-10-dynamic-font-lock-for-fennel/dynamic.webm&#34; type=&#34;video/webm&#34;&gt;
Your browser does not support the video tag.&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;I wanted to make this feature for quite some time.
I&amp;rsquo;m a big fan of &lt;a href=&#34;https://cider.mx/&#34; target=&#34;_blank&#34;&gt;CIDER&lt;/a&gt;&amp;rsquo;s dynamic font-locking and have been using it for some years.
It never occurred to me, however, that CIDER doesn&amp;rsquo;t do scoping:&lt;/p&gt;
&lt;figure class=&#34;invertable&#34;&gt;&lt;img src=&#34;https://andreyor.st/2025-03-10-dynamic-font-lock-for-fennel/cider1.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;But Clojure macros are not scoped, like in Fennel, so that&amp;rsquo;s probably fine.
What&amp;rsquo;s not as fine is that it will highlight the macro before it was declared:&lt;/p&gt;
&lt;figure class=&#34;invertable&#34;&gt;&lt;img src=&#34;https://andreyor.st/2025-03-10-dynamic-font-lock-for-fennel/cider2.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;Which would be an error if we were to try to reload this file.
But, for what it&amp;rsquo;s worth, I think CIDER&amp;rsquo;s solution is fine, because again - no special scoping rules, and unless the file loads without errors, no dynamic syntax highlighting would be applied.
For Fennel, however, I wanted a more robust solution.&lt;/p&gt;
&lt;p&gt;For now, this is still available in a &lt;a href=&#34;https://git.sr.ht/~technomancy/fennel-mode/tree/dynamic-font-lock&#34; target=&#34;_blank&#34;&gt;feature branch&lt;/a&gt;, but I&amp;rsquo;m positive that I&amp;rsquo;ll merge this soon, after I give it a bit more testing, and gather some feedback from the users.
If you&amp;rsquo;re a &lt;code&gt;fennel-mode&lt;/code&gt; user, and you use my &lt;code&gt;fennel-proto-repl&lt;/code&gt; module, I encourage you to try out dynamic font-locking and see if it works for you!&lt;/p&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: Dynamic font-lock for Fennel&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Mon, 10 Mar 2025 01:26:00 +0300</pubDate>
    </item><item>
      <title>deps.fnl 0.2.2 released</title>
      <link>https://andreyor.st/posts/2025-02-16-depsfnl-022-released/</link>
      <guid>https://andreyor.st/posts/2025-02-16-depsfnl-022-released/</guid>
      <description>&lt;p&gt;I just released a new version of the &lt;a href=&#34;https://gitlab.com/andreyorst/deps.fnl&#34; target=&#34;_blank&#34;&gt;deps.fnl&lt;/a&gt; project!&lt;/p&gt;
&lt;p&gt;After getting some feedback on the 0.1.0 version and addressing most of it, I&amp;rsquo;m ready to present a new version with improved dependency and conflict handling.&lt;/p&gt;
&lt;h2 id=&#34;major-changes&#34;&gt;Major changes&lt;/h2&gt;
&lt;h3 id=&#34;the-deps-dot-fnl-file-format&#34;&gt;The &lt;code&gt;deps.fnl&lt;/code&gt; file format&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;:deps&lt;/code&gt; field was changed back to use maps, as it was during the prototyping stage:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:deps&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;https://gitlab.com/andreyorst/async.fnl&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:git&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:sha&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;98e8680b46a777f9ddcff9e761b782ec6bf077f5&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;https://gitlab.com/andreyorst/json.fnl&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:git&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:sha&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;eebcb40750d6f41ed03fed04373f944dcf297383&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;https://gitlab.com/andreyorst/reader.fnl&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:git&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:sha&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;252ea2474cb7399020e6922f700a5190373e6f98&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;luasocket&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:rock&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:version&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;3.1.0-1&amp;#34;&lt;/span&gt;}}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:paths&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:fennel&lt;/span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;src/?.fnl&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;src/?/init.fnl&amp;#34;&lt;/span&gt;]}}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Before this change the &lt;code&gt;deps.fnl&lt;/code&gt; file would have looked like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:deps&lt;/span&gt; [[&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;https://gitlab.com/andreyorst/async.fnl&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:git&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:sha&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;98e8680b46a777f9ddcff9e761b782ec6bf077f5&amp;#34;&lt;/span&gt;}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;https://gitlab.com/andreyorst/json.fnl&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:git&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:sha&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;eebcb40750d6f41ed03fed04373f944dcf297383&amp;#34;&lt;/span&gt;}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;https://gitlab.com/andreyorst/reader.fnl&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:git&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:sha&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;252ea2474cb7399020e6922f700a5190373e6f98&amp;#34;&lt;/span&gt;}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;luasocket&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:rock&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:version&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;3.1.0-1&amp;#34;&lt;/span&gt;}]]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:paths&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:fennel&lt;/span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;src/?.fnl&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;src/?/init.fnl&amp;#34;&lt;/span&gt;]}}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The main reason for a change to the use of vectors was the fact that all of the Luarocks dependencies were using the same tree.
Because conflict resolution was made during dependency installation, and maps are unordered, and if any of the libraries had a Luarocks library as its transient dependency, Luarocks would silently override the dependency.
This made conflict checking nondeterministic, and thus error-prone.&lt;/p&gt;
&lt;p&gt;This is no longer an issue, and thus the format can be changed back to maps.&lt;/p&gt;
&lt;h3 id=&#34;conflict-resolution&#34;&gt;Conflict resolution&lt;/h3&gt;
&lt;p&gt;Previously, &lt;code&gt;deps&lt;/code&gt; would use a deterministic order of dependencies and the &lt;code&gt;--allow-conflicts&lt;/code&gt; flag to resolve conflicts.
This meant, that if your project had two dependencies, that had the same transient dependency but of a different version, &lt;code&gt;--allow-conflicts&lt;/code&gt; would honor dependencies that appeared earlier in the order.
For example, if you had dependencies &lt;code&gt;A&lt;/code&gt;, and &lt;code&gt;B&lt;/code&gt;, both of which depended on &lt;code&gt;C&lt;/code&gt; of versions &lt;code&gt;v1&lt;/code&gt; and &lt;code&gt;v2&lt;/code&gt; like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; project deps.fnl&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:deps&lt;/span&gt; [[&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;A&amp;#34;&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:version&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;1&amp;#34;&lt;/span&gt;}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;B&amp;#34;&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:version&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;1&amp;#34;&lt;/span&gt;}]]}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; A deps.fnl&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:deps&lt;/span&gt; [[&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;C&amp;#34;&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:version&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;1&amp;#34;&lt;/span&gt;}]]}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; B deps.fnl&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:deps&lt;/span&gt; [[&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;C&amp;#34;&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:version&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;2&amp;#34;&lt;/span&gt;}]]}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;deps&lt;/code&gt; script would throw an error:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[A:1]-&amp;gt;[C:1] conflicts with [B:1]-&amp;gt;[C:2]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Previously, this could be resolved by using the &lt;code&gt;--allow-conflicts&lt;/code&gt; flag, meaning that &lt;code&gt;deps&lt;/code&gt; would see the conflict, but ignore it, and use the &lt;code&gt;C&lt;/code&gt; library from the first one encountered in the &lt;code&gt;deps.fnl&lt;/code&gt;.
So for the following &lt;code&gt;deps.fnl&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:deps&lt;/span&gt; [[&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;A&amp;#34;&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:version&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;1&amp;#34;&lt;/span&gt;}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;B&amp;#34;&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:version&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;1&amp;#34;&lt;/span&gt;}]]}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The libraries used would be &lt;code&gt;A&lt;/code&gt; version &lt;code&gt;1&lt;/code&gt;, transient &lt;code&gt;C&lt;/code&gt; version &lt;code&gt;1&lt;/code&gt; from &lt;code&gt;A&lt;/code&gt;, and &lt;code&gt;B&lt;/code&gt; version &lt;code&gt;1&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;However, for the following &lt;code&gt;deps.fnl&lt;/code&gt; (&lt;code&gt;A&lt;/code&gt; and &lt;code&gt;B&lt;/code&gt; appear in the reverse order):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:deps&lt;/span&gt; [[&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;B&amp;#34;&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:version&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;1&amp;#34;&lt;/span&gt;}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;A&amp;#34;&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:version&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;1&amp;#34;&lt;/span&gt;}]]}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The libraries used would be &lt;code&gt;A&lt;/code&gt; version &lt;code&gt;1&lt;/code&gt;, transient &lt;code&gt;C&lt;/code&gt; version &lt;code&gt;2&lt;/code&gt; from &lt;code&gt;B&lt;/code&gt;, and &lt;code&gt;B&lt;/code&gt; version &lt;code&gt;1&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This wasn&amp;rsquo;t clear enough, and could introduce unexpected results when editing &lt;code&gt;deps.fnl&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;For example, adding another dependency before &lt;code&gt;A&lt;/code&gt; that (unknowingly) also depends on yet another version of &lt;code&gt;C&lt;/code&gt; would override the version for the project.&lt;/p&gt;
&lt;p&gt;At first, I was thinking about using &lt;code&gt;:exlusions&lt;/code&gt; key to specify that we want to exclude certain transient dependencies, but it also introduced the need to do this at arbitrary depth:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:deps&lt;/span&gt; [[&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;A&amp;#34;&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:version&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;1&amp;#34;&lt;/span&gt;}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;B&amp;#34;&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:version&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;1&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:exclusions&lt;/span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;C&amp;#34;&lt;/span&gt;]}]]}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And we would still not know what version of &lt;code&gt;C&lt;/code&gt; we&amp;rsquo;re using.&lt;/p&gt;
&lt;p&gt;So instead, conflict resolution works by specifying the specific version of dependency &lt;code&gt;C&lt;/code&gt; at the same level as &lt;code&gt;A&lt;/code&gt; and &lt;code&gt;B&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:deps&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;A&amp;#34;&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:version&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;1&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;B&amp;#34;&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:version&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;1&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;C&amp;#34;&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:version&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;1&amp;#34;&lt;/span&gt;}}}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This way the project author is in full control of what versions will be used.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;--allow-conflicts&lt;/code&gt; flag is no more.
By default, conflicts are checked, and the only way to resolve conflicts is either to update the library in question, or override it at the root level.&lt;/p&gt;
&lt;h3 id=&#34;conflict-resolution-is-now-module-based&#34;&gt;Conflict resolution is now module-based&lt;/h3&gt;
&lt;p&gt;Another new feature I&amp;rsquo;m pretty excited about is module-based conflict resolution.
In the &lt;code&gt;0.1.0&lt;/code&gt; version of &lt;code&gt;deps&lt;/code&gt; it was not possible to detect conflicts when something is a fork.&lt;/p&gt;
&lt;p&gt;What I mean by that is, say, I have a library: &lt;a href=&#34;https://gitlab.com/andreyorst/async.fnl&#34; target=&#34;_blank&#34;&gt;async.fnl&lt;/a&gt; and someone decides to fork it to change something or fix a bug.
They add the following to their project &lt;code&gt;deps.fnl&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:deps&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;https://gitlab.com/some-fork/async.fnl&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:git&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:sha&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;98e8680b46a777f9ddcff9e761b782ec6bf077f5&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;https://gitlab.com/andreyorst/async.fnl&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:git&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:sha&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;98e8680b46a777f9ddcff9e761b782ec6bf077f5&amp;#34;&lt;/span&gt;}}}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The main question thus was - what &lt;code&gt;async.fnl&lt;/code&gt; implementation would actually be loaded?
We could answer this question if &lt;code&gt;:deps&lt;/code&gt; was a list instead of a table because the ordering would rule out and &lt;code&gt;(require :io.gitlab.andreyorst.async)&lt;/code&gt; would load the first library.
However, with deps stored as a map, we would have gotten different implementations each time because key hashing is randomized.&lt;/p&gt;
&lt;p&gt;The problem is - previously &lt;code&gt;deps&lt;/code&gt; didn&amp;rsquo;t see this as a conflict.
These two libraries are the &lt;em&gt;same library&lt;/em&gt; but different &lt;em&gt;projects&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Now, instead of comparing just library names (URLs in this case) and versions (SHAs for Git dependencies), &lt;code&gt;deps&lt;/code&gt; also compares exported modules.
So we can detect the conflict because both libraries export &lt;code&gt;io.gitlab.andreyorst.async&lt;/code&gt; module.
If the person who forked the library chooses to change the module name to &lt;code&gt;io.gitlab.some-fork.async&lt;/code&gt; instead, there won&amp;rsquo;t be a conflict, as this is now a properly different library.&lt;/p&gt;
&lt;p&gt;The example above is unlikely to happen as is, but if some library uses a fork as a transient dependency this might happen.
This was pointed out to me by Ambrose Bonnaire-Sergeant off the mailing list, and we&amp;rsquo;ve come up with this solution.&lt;/p&gt;
&lt;h3 id=&#34;luarocks--transient--dependencies&#34;&gt;Luarocks (transient) dependencies&lt;/h3&gt;
&lt;p&gt;Another problem with transient dependencies is the fact that Luaorcks dependency manifests are very lax about versions of the transient dependencies.
Usually, you would see just library names, and sometimes version ranges.
For example, here&amp;rsquo;s a fragment from the &lt;a href=&#34;https://luarocks.org/manifests/leafo/lapis-1.16.0-1.rockspec&#34; target=&#34;_blank&#34;&gt;lapis&lt;/a&gt; library manifest describing dependencies:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;dependencies = {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;lua&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;ansicolors&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;argparse&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;date&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;etlua&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;loadkit&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;lpeg&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;lua-cjson&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;luaossl&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;luasocket&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;pgmoon&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;pgmoon&lt;/code&gt; dependency itself depends on &lt;code&gt;lpeg&lt;/code&gt;.
So Luarocks default strategy is to pull the latest available version of the library.&lt;/p&gt;
&lt;p&gt;This makes conflict resolution harder, because &lt;code&gt;deps.fnl&lt;/code&gt; requires specifying a concrete version of any dependency.
Paired with the fact that Luarocks silently overrides already installed dependencies when you give it a specific version to install, and the fact that &lt;code&gt;deps.fnl&lt;/code&gt; is now unordered, the only way to get deterministic versions from Luarocks was to ask users to specify all of the transient dependencies:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:deps&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;lapis&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:rock&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:version&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;1.16.0-1&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:dependencies&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;loadkit&amp;#34;&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:rock&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:version&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;1.1.0-1&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;etlua&amp;#34;&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:rock&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:version&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;1.3.0-1&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;luasocket&amp;#34;&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:rock&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:version&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;3.1.0-1&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;lua-cjson&amp;#34;&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:rock&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:version&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;2.1.0.10-1&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;argparse&amp;#34;&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:rock&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:version&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;0.7.1-1&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;lpeg&amp;#34;&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:rock&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:version&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;1.1.0-2&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;ansicolors&amp;#34;&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:rock&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:version&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;1.0.2-3&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;date&amp;#34;&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:rock&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:version&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;2.2.1-1&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;pgmoon&amp;#34;&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:rock&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:version&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;1.16.0-1&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:dependencies&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;lpeg&amp;#34;&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:rock&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:version&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;1.1.0-2&amp;#34;&lt;/span&gt;}}}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;luaossl&amp;#34;&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:rock&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:version&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;20220711-0&amp;#34;&lt;/span&gt;}}}}}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;:dependencies&lt;/code&gt; key is akin to the &lt;code&gt;dependencies&lt;/code&gt; map in the rock manifest.&lt;/p&gt;
&lt;p&gt;The conflict resolution works exactly the same.&lt;/p&gt;
&lt;h3 id=&#34;runtime-library-manipulation-with-deps-dot-add-lib-and-sync-deps&#34;&gt;Runtime library manipulation with &lt;code&gt;deps.add-lib&lt;/code&gt;, and &lt;code&gt;sync-deps&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Something that escaped my previous announcement, because it was developed a bit later is that it is now possible to add libraries while working on the application without restarting the REPL.
When the REPL is started via the &lt;code&gt;deps --repl&lt;/code&gt; command, a new &lt;code&gt;deps&lt;/code&gt; module is available:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:deps&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:_VERSION&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;0.2.0&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:add-lib&lt;/span&gt; #&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;function&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x560a243c2990&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:add-libs&lt;/span&gt; #&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;function&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x560a245b5820&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:sync-deps&lt;/span&gt; #&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;function&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x560a246d8d50&amp;gt;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Thus, if you&amp;rsquo;re working on some project and in need of a new dependency, or want to compare a few and choose which one to use, you can quickly do so in the REPL:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;deps.add-libs&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;bump&amp;#34;&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:rock&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:version&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;3.1.7-1&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;anim8&amp;#34;&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:rock&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:version&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;v2.3.1-1&amp;#34;&lt;/span&gt;}})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;bump&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;anim8&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;deps.add-lib&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;penlight&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:rock&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:version&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;1.14.0-2&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:dependencies&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;luafilesystem&amp;#34;&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:rock&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:version&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;1.8.0-1&amp;#34;&lt;/span&gt;}}})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;pl.input&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;pl.path&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;pl.array2d&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;pl.compat&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;pl.luabalanced&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;pl.pretty&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;pl.import_into&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;pl.dir&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;pl.func&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;pl.Map&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;pl.comprehension&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;pl.app&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;pl.seq&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;pl.sip&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;pl.file&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;pl.stringx&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;pl.class&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;pl.Date&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;pl.strict&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;pl.template&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;pl.types&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;pl.permute&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;pl.MultiMap&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;pl.text&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;pl.utils&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;pl.OrderedMap&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;pl.xml&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;pl.url&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;pl.tablex&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;pl.test&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;pl.lapp&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;pl.List&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;pl.Set&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;pl.operator&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;pl.data&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;pl.lexer&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;pl.config&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;pl.init&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;pl.stringio&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;lfs&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The returned value is a table of module names that are now available to &lt;code&gt;require&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Alternatively, the &lt;code&gt;deps.fnl&lt;/code&gt; file can be edited, and changes can be synced into the running REPL via the &lt;code&gt;sync-deps&lt;/code&gt; call.&lt;/p&gt;
&lt;h3 id=&#34;new-flags&#34;&gt;New flags&lt;/h3&gt;
&lt;p&gt;Several new flags were added.&lt;/p&gt;
&lt;h4 id=&#34;tree&#34;&gt;&lt;code&gt;--tree&lt;/code&gt;&lt;/h4&gt;
&lt;p&gt;Prints the dependency tree, outlining what dependencies are on your path, and what transient dependencies are brought by each dependency:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[[&amp;#34;lapis&amp;#34; &amp;#34;1.16.0-1&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  [[&amp;#34;argparse&amp;#34; &amp;#34;0.7.1-1&amp;#34;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   [&amp;#34;luaossl&amp;#34; &amp;#34;20220711-0&amp;#34;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   [&amp;#34;pgmoon&amp;#34; &amp;#34;1.16.0-1&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    [[&amp;#34;lpeg&amp;#34; &amp;#34;1.1.0-2&amp;#34;]]]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   [&amp;#34;date&amp;#34; &amp;#34;2.2.1-1&amp;#34;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   [&amp;#34;luasocket&amp;#34; &amp;#34;3.1.0-1&amp;#34;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   [&amp;#34;loadkit&amp;#34; &amp;#34;1.1.0-1&amp;#34;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   [&amp;#34;ansicolors&amp;#34; &amp;#34;1.0.2-3&amp;#34;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   [&amp;#34;lpeg&amp;#34; &amp;#34;1.1.0-2&amp;#34;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   [&amp;#34;etlua&amp;#34; &amp;#34;1.3.0-1&amp;#34;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   [&amp;#34;lua-cjson&amp;#34; &amp;#34;2.1.0.10-1&amp;#34;]]]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; [&amp;#34;andreyorst/fennel-test&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &amp;#34;9aae4dd52be1f5dd1ee97e61c639e6c5a2f9afee&amp;#34;]]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;fennel-ls&#34;&gt;&lt;code&gt;--fennel-ls&lt;/code&gt;&lt;/h4&gt;
&lt;p&gt;The &lt;code&gt;deps&lt;/code&gt; script is now able to create or update an existing configuration for the &lt;a href=&#34;https://git.sr.ht/~xerool/fennel-ls/&#34; target=&#34;_blank&#34;&gt;fennel-ls&lt;/a&gt; project.&lt;/p&gt;
&lt;p&gt;When calling &lt;code&gt;deps --fennel-ls&lt;/code&gt; a &lt;code&gt;flsproject.fnl&lt;/code&gt; file will be created if it doesn&amp;rsquo;t exist already.
This file will contain all of the PATH-related data:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:fennel-path&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;test/?.fnl;.deps/git/andreyorst/fennel-test/9aae4dd52be1f5dd1ee97e61c639e6c5a2f9afee/src/?/init.fnl&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:lua-version&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;lua54&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:macro-path&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;.deps/git/andreyorst/fennel-test/9aae4dd52be1f5dd1ee97e61c639e6c5a2f9afee/src/?/init.fnlm&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;profiles&#34;&gt;&lt;code&gt;--profiles&lt;/code&gt;&lt;/h4&gt;
&lt;p&gt;Another new feature - profiles!
Before this flag existed profiles were kind of possible by using &lt;code&gt;--merge&lt;/code&gt; and additional &lt;code&gt;deps.fnl&lt;/code&gt; files:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; deps.fnl&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:deps&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;https://gitlab.com/andreyorst/reader.fnl&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:git&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:sha&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;252ea2474cb7399020e6922f700a5190373e6f98&amp;#34;&lt;/span&gt;}}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:paths&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:fennel&lt;/span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;src/?.fnl&amp;#34;&lt;/span&gt;]}}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; dev-deps.fnl&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:deps&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;https://gitlab.com/andreyorst/fennel-test&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:git&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:sha&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;72a74394f89fdaf15abf11f33752a07e9e0bee91&amp;#34;&lt;/span&gt;}}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:paths&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:fennel&lt;/span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;tests/?.fnl&amp;#34;&lt;/span&gt;]}}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Having these two files, a final deps map can be obtained with &lt;code&gt;deps --merge dev-deps.fnl&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; output of `deps --merge dev-deps.fnl --show`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:deps&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;https://gitlab.com/andreyorst/fennel-test&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:sha&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;72a74394f89fdaf15abf11f33752a07e9e0bee91&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;git&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;https://gitlab.com/andreyorst/reader.fnl&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:sha&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;252ea2474cb7399020e6922f700a5190373e6f98&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;git&amp;#34;&lt;/span&gt;}}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:paths&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:clua&lt;/span&gt; {} &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:fennel&lt;/span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;src/?.fnl&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;tests/?.fnl&amp;#34;&lt;/span&gt;] &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:lua&lt;/span&gt; {} &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:macro&lt;/span&gt; {}}}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This works, but semantically it is a bit unclear.
To know that the development &amp;ldquo;profile&amp;rdquo; exists you need to actively look for it in the project files.
Multiple such profiles also pile up in the project, which is not great.&lt;/p&gt;
&lt;p&gt;Now, this can be done a bit more consistently with:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; deps.fnl&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:deps&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;https://gitlab.com/andreyorst/reader.fnl&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:git&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:sha&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;252ea2474cb7399020e6922f700a5190373e6f98&amp;#34;&lt;/span&gt;}}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:paths&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:fennel&lt;/span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;src/?.fnl&amp;#34;&lt;/span&gt;]}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:profiles&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:dev&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:deps&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;https://gitlab.com/andreyorst/fennel-test&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:git&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:sha&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;72a74394f89fdaf15abf11f33752a07e9e0bee91&amp;#34;&lt;/span&gt;}}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:paths&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:fennel&lt;/span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;tests/?.fnl&amp;#34;&lt;/span&gt;]}}}}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And the same final deps map can be obtained with &lt;code&gt;deps --profiles dev&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; output of `deps --profiles dev --show`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:deps&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;https://gitlab.com/andreyorst/fennel-test&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:sha&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;72a74394f89fdaf15abf11f33752a07e9e0bee91&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;git&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;https://gitlab.com/andreyorst/reader.fnl&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:sha&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;252ea2474cb7399020e6922f700a5190373e6f98&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;git&amp;#34;&lt;/span&gt;}}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:paths&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:clua&lt;/span&gt; {} &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:fennel&lt;/span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;src/?.fnl&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;tests/?.fnl&amp;#34;&lt;/span&gt;] &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:lua&lt;/span&gt; {} &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:macro&lt;/span&gt; {}}}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;--merge&lt;/code&gt; flag is here to stay for compatibility.
Maybe there are other use cases for it too, so it won&amp;rsquo;t be removed unless deemed unnecessary.
Moreover, &lt;code&gt;--profiles&lt;/code&gt; actually supports multiple comma-separated profile names, so it is much more compact compared to &lt;code&gt;--merge&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ deps --profiles dev,test,doc ...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ deps --merge dev-deps.fnl --merge test-deps.fnl --merge doc-deps.fnl ...
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;upcoming-work&#34;&gt;Upcoming work&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;ll probably take a short break from working on &lt;code&gt;deps&lt;/code&gt; for a while, or at least I won&amp;rsquo;t work on it as actively.
Both to let it settle a bit, give it time to gather some feedback, and let me rest a bit too.
I&amp;rsquo;m feeling good about what I did so far, and &lt;code&gt;deps&lt;/code&gt; in my opinion is out of the alpha stage for sure.
So I think it can be safely used in other projects, and I&amp;rsquo;m still open for feedback!&lt;/p&gt;
&lt;p&gt;As for plans, I have something I want to experiment with.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve started outlining an interface for custom backend implementations.
Right now there are only two backends: Git and Luarocks, but if the community desires, I&amp;rsquo;ll extend &lt;code&gt;deps&lt;/code&gt; in such a way that custom backends could be added via some sort of a plugin system.
Thus other ways to download and add dependencies would be possible.
For example, recently I learned that some Lua libraries exist only in SVN.
There may be others that are only available through GNU Bazaar, the new hot &lt;a href=&#34;https://github.com/jj-vcs/jj&#34; target=&#34;_blank&#34;&gt;Jujutsu VCS&lt;/a&gt;, or maybe some use Mercurial, I don&amp;rsquo;t know!&lt;/p&gt;
&lt;p&gt;Additionally, I think it is safe to say, that using version control systems for libraries is not a great idea, so I might start working on a dependency packaging system for Fennel libraries that we could later upload to some package archive.
Thinking of a name - Fennel Bulbs sounds fun!&lt;/p&gt;
&lt;p&gt;Dependency building needs to be changed to be a bit more robust.
Right now I think it should work fine, but probably only on *nix-based systems.
Windows support for &lt;code&gt;deps.fnl&lt;/code&gt; is there, but completely untested.
So if any Fennel users happen to do their stuff on Windows - let me know if it works, please!&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s all for now.
Huge thanks to Phil Hagelberg, Ambrose Bonnaire-Sergeant, and Emma B. for the feedback and code reviews!&lt;/p&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: deps.fnl 0.2.2 released&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Sun, 16 Feb 2025 06:30:00 +0300</pubDate>
    </item><item>
      <title>deps.fnl - a new dependency manager for Fennel projects</title>
      <link>https://andreyor.st/posts/2025-01-10-depsfnl-a-new-dependency-manager-for-fennel-projects/</link>
      <guid>https://andreyor.st/posts/2025-01-10-depsfnl-a-new-dependency-manager-for-fennel-projects/</guid>
      <description>&lt;p&gt;I&amp;rsquo;d like to present a new project, aimed at one of the areas where the Fennel ecosystem can be improved - project dependency management.&lt;/p&gt;
&lt;p&gt;Other programming languages have tools to pull in, build, and load external dependencies.
Java has Maven, Clojure has Leiningen and other projects like this, Python has Pip and Poetry, and Lua has Luarocks.
All these tools provide ways for pulling in dependencies concerning how the language is organized.&lt;/p&gt;
&lt;p&gt;Since Fennel runs on Lua, we could use Luarocks, but, well, it&amp;rsquo;s not really good.
It has a lot of design problems and doesn&amp;rsquo;t fit for Fennel for a number of reasons, like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It is tailored for Lua dependencies only, so shipping Fennel libraries would require AOT compiling them to Lua;&lt;/li&gt;
&lt;li&gt;Luarocks only knows how to build &lt;code&gt;LUA_PATH&lt;/code&gt; and &lt;code&gt;LUA_CPATH&lt;/code&gt;, but Fennel requires &lt;code&gt;FENNEL_PATH&lt;/code&gt; and more importantly &lt;code&gt;FENNEL_MACRO_PATH&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;Shipping macros is hard or impossible.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;a-few-notes-on-why-i-decided-to-make-a-dependency-manager&#34;&gt;A few notes on why I decided to make a dependency manager&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;ve made a lot of libraries for Fennel and encountered various problems with shipping these libraries to users.&lt;/p&gt;
&lt;p&gt;Most of the Fennel libraries I write feature user-exposed macros, which means that the library can&amp;rsquo;t be shipped as a single file most of the time.
I did find a workaround for that eventually, but it still poses some interesting challenges for library writers.&lt;/p&gt;
&lt;p&gt;Another problem I encountered are libraries that need other libraries to work.
Some of my libraries depend on other libraries I made, and thus I either need to include them in the source code directly for shipping or do some other trickery.
And libraries depending on other libraries (transient dependencies) could potentially conflict with other dependencies in the project.&lt;/p&gt;
&lt;p&gt;Finally, multifile libraries that can&amp;rsquo;t be compiled into a single file, since they have multiple modules that serve as entry points are hard to ship because users will have to properly set up &lt;code&gt;PATH&lt;/code&gt; in their project.&lt;/p&gt;
&lt;p&gt;So I made &lt;a href=&#34;https://gitlab.com/andreyorst/deps.fnl&#34; target=&#34;_blank&#34;&gt;deps.fnl&lt;/a&gt; to solve these problems.&lt;/p&gt;
&lt;h2 id=&#34;deps-dot-fnl&#34;&gt;&lt;code&gt;deps.fnl&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;This project consists of a single script, called &lt;code&gt;deps&lt;/code&gt;, that works as a drop-in replacement for the fennel executable.
This means that you can call &lt;code&gt;deps&lt;/code&gt; with any arguments that you specify to Fennel, and it will work transparently.
In other words:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;deps --require-as-include --compile file.fnl &amp;gt; file.lua
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;But the main thing that &lt;code&gt;deps&lt;/code&gt; was designed to do is to set up the environment for your project.
When the &lt;code&gt;deps.fnl&lt;/code&gt; file is present in the project, the &lt;code&gt;deps&lt;/code&gt; script analyzes this file and pulls in all of the specified libraries, sets all required &lt;code&gt;PATH&lt;/code&gt; variables, like &lt;code&gt;LUA_PATH&lt;/code&gt;, &lt;code&gt;LUA_CPATH&lt;/code&gt;, &lt;code&gt;FENNEL_PATH&lt;/code&gt;, and &lt;code&gt;FENNEL_MACRO_PATH&lt;/code&gt;, and launches &lt;code&gt;fennel&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;For example, here&amp;rsquo;s a &lt;code&gt;deps.fnl&lt;/code&gt; for my &lt;a href=&#34;https://gitlab.com/andreyorst/fnl-http&#34; target=&#34;_blank&#34;&gt;fnl-http&lt;/a&gt; project:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:deps&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; [[&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;https://gitlab.com/andreyorst/async.fnl&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;git&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:sha&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;a83b13b397fdfab3ebf7f17a16d21a7ec2674ceb&amp;#34;&lt;/span&gt;}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;https://gitlab.com/andreyorst/json.fnl&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;git&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:sha&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;bfb8d7d03c26619768eefaa47782a3e95dbe5156&amp;#34;&lt;/span&gt;}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;https://gitlab.com/andreyorst/reader.fnl&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;git&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:sha&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;3ff2bc790c8b7922267af5712a64a14572a172cf&amp;#34;&lt;/span&gt;}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;luasocket&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;rock&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:version&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;3.0rc1-2&amp;#34;&lt;/span&gt;}]]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:paths&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:fennel&lt;/span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;src/?.fnl&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;src/?/init.fnl&amp;#34;&lt;/span&gt;]}}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As can be seen, this project depends on four libraries: &lt;a href=&#34;https://gitlab.com/andreyorst/async.fnl&#34; target=&#34;_blank&#34;&gt;async.fnl&lt;/a&gt;, &lt;a href=&#34;https://gitlab.com/andreyorst/json.fnl&#34; target=&#34;_blank&#34;&gt;json.fnl&lt;/a&gt;, &lt;a href=&#34;https://gitlab.com/andreyorst/reader.fnl&#34; target=&#34;_blank&#34;&gt;reader.fnl&lt;/a&gt;, and &lt;a href=&#34;https://w3.impa.br/~diego/software/luasocket/home.html&#34; target=&#34;_blank&#34;&gt;luasocket&lt;/a&gt;.
Previously I had to vendor these dependencies in the repository, and instruct people how to install &lt;code&gt;fnl-http&lt;/code&gt; and use it as a library.&lt;/p&gt;
&lt;p&gt;Moreover, &lt;code&gt;fnl-http&lt;/code&gt; is a multi-file library, so manually setting up &lt;code&gt;PATH&lt;/code&gt; for it and all of its dependencies is not a pleasant task.
But with deps you can use this library in your project by placing this deps.fnl file at your project root:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:deps&lt;/span&gt; [[&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;https://gitlab.com/andreyorst/fnl-http&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;git&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:sha&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;ea885a8c767a627206126cc36f1befb1a2d71850&amp;#34;&lt;/span&gt;}]]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:paths&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:fennel&lt;/span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;?.fnl&amp;#34;&lt;/span&gt;]}}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Then just call &lt;code&gt;deps --repl&lt;/code&gt;, and you&amp;rsquo;re good to go:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;$&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;deps&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;--repl&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;processing&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;git&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;repo&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;https&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;://gitlab.com/andreyorst/fnl-http&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;processing&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;git&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;repo&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;https&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;://gitlab.com/andreyorst/async.fnl&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;processing&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;git&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;repo&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;https&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;://gitlab.com/andreyorst/json.fnl&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;processing&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;git&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;repo&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;https&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;://gitlab.com/andreyorst/reader.fnl&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;processing&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rock&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;luasocket&lt;/span&gt; 3.0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rc1-2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Welcome&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;to&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Fennel&lt;/span&gt; 1.5&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;.1-dev&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;on&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;PUC&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Lua&lt;/span&gt; 5.4&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;!&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Use&lt;/span&gt; &lt;span style=&#34;&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;help&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;to&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;see&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;available&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;commands.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:io.gitlab.andreyorst.fnl-http.client&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:connect&lt;/span&gt; #&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;function&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x5605682104e0&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:delete&lt;/span&gt; #&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;function&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x560568bc64c0&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:get&lt;/span&gt; #&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;function&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x5605685315c0&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:head&lt;/span&gt; #&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;function&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x5605689c9ca0&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:options&lt;/span&gt; #&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;function&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x5605682b0a20&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:patch&lt;/span&gt; #&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;function&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x5605687d8f40&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:post&lt;/span&gt; #&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;function&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x560568c40270&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:put&lt;/span&gt; #&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;function&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x5605681d9d80&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:request&lt;/span&gt; #&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;function&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x560568b37450&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:trace&lt;/span&gt; #&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;function&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x560568580320&amp;gt;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In the output above after analyzing the project&amp;rsquo;s &lt;code&gt;deps.fnl&lt;/code&gt; the &lt;code&gt;deps&lt;/code&gt; script proceeds to download dependencies.
The project&amp;rsquo;s only dependency is fnl-http, but after downloading it, the &lt;code&gt;deps&lt;/code&gt; script check if there&amp;rsquo;s a &lt;code&gt;deps.fnl&lt;/code&gt; in the root of the repository.
Since there is, it proceeds to download all transient dependencies.
Calling &lt;code&gt;deps --repl&lt;/code&gt; the second time would not download anything, unless new dependencies were added to the &lt;code&gt;deps.fnl&lt;/code&gt; file or hashes/version were changed.&lt;/p&gt;
&lt;p&gt;After processing all of the dependencies the REPL is started as requested, and the library is ready to be used.&lt;/p&gt;
&lt;h2 id=&#34;dependency-types&#34;&gt;Dependency types&lt;/h2&gt;
&lt;p&gt;Dependencies can be of two types - &lt;code&gt;git&lt;/code&gt; and &lt;code&gt;rock&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Git dependencies are just a link to the repository and a commit hash to checkout.
Until we have some kind of a registry and a way to package libraries for downloading this is the best we can do.
But as seen above, this already makes using libraries a lot simpler.&lt;/p&gt;
&lt;p&gt;Rock dependencies are processed with Luarocks.
Yes, &lt;code&gt;deps&lt;/code&gt; wraps not only the Fennel executable but Luarocks as well.
Luarocks is fine enough to be used like this and provides enough command-line arguments for &lt;code&gt;deps&lt;/code&gt; needs.&lt;/p&gt;
&lt;p&gt;All of the dependencies are stored in the project&amp;rsquo;s root unless requested elsewhere.
I decided not to go the &lt;code&gt;.m2&lt;/code&gt; route.
One reason for that is the fact, that Luarocks can&amp;rsquo;t install two versions of the same library into a single &amp;ldquo;tree&amp;rdquo;, as they call it.
Instead, it overrides any library already present in the tree.
This is probably related to how the &lt;code&gt;LUA_PATH&lt;/code&gt; is constructed by Luarocks.&lt;/p&gt;
&lt;p&gt;Speaking of &lt;code&gt;PATH=⁣s. The =deps.fnl&lt;/code&gt; file contains a mandatory field &lt;code&gt;:paths&lt;/code&gt;, that contains a table.
This table specifies the project&amp;rsquo;s path configuration.
Each library may require a different path configuration, and when &lt;code&gt;deps&lt;/code&gt; script processes a said &lt;code&gt;deps.fnl&lt;/code&gt; file, it reads the path table and constructs the final &lt;code&gt;PATH&lt;/code&gt; for your project.&lt;/p&gt;
&lt;p&gt;You can analyze the path generated for the project with &lt;code&gt;deps --path&lt;/code&gt;.
It prints the path to standard out in a format similar to &lt;code&gt;luarocks path&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Finally, some Git repositories may not use &lt;code&gt;deps.fnl&lt;/code&gt;, but it is still possible to manage them with &lt;code&gt;deps.fnl&lt;/code&gt;.
For example, my library fennel-test doesn&amp;rsquo;t yet feature a &lt;code&gt;deps.fnl&lt;/code&gt; file, but the &lt;code&gt;deps&lt;/code&gt; script itself uses it for testing.
To make this work, you can specify &lt;code&gt;:paths&lt;/code&gt; field for each dependency:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:deps&lt;/span&gt; [[&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;https://gitlab.com/andreyorst/fennel-test&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:git&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:sha&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;01ea080dc8176512c5890462252c5bf214baf137&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:paths&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:fennel&lt;/span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;?.fnl&amp;#34;&lt;/span&gt;] &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:macro&lt;/span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;?.fnl&amp;#34;&lt;/span&gt;]}}]]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:paths&lt;/span&gt; {}}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Thus, we can even pull in pure Lua dependencies, and specify the &lt;code&gt;:paths&lt;/code&gt; table with something like &lt;code&gt;{:lua [&amp;quot;?.lua&amp;quot;]}&lt;/code&gt;, and &lt;code&gt;deps&lt;/code&gt; will set everything up.&lt;/p&gt;
&lt;p&gt;You can read more information on the &lt;code&gt;deps.fnl&lt;/code&gt; file format, and &lt;code&gt;deps&lt;/code&gt; script usage in the project&amp;rsquo;s &lt;a href=&#34;https://gitlab.com/andreyorst/deps.fnl/-/blob/main/README.md&#34; target=&#34;_blank&#34;&gt;readme&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&#34;i-need-feedback&#34;&gt;I need feedback&lt;/h2&gt;
&lt;p&gt;I have high hopes for this project, and I&amp;rsquo;m looking for feedback.
If you&amp;rsquo;re working on some application that requires external dependencies, give &lt;code&gt;deps.fnl&lt;/code&gt; a shot.
If you&amp;rsquo;re a library maker like me, consider using &lt;code&gt;deps.fnl&lt;/code&gt; so your users have an easier way of using your work.
You can submit feedback either via email, or &lt;a href=&#34;https://gitlab.com/andreyorst/deps.fnl&#34; target=&#34;_blank&#34;&gt;GitLab&lt;/a&gt; &lt;a href=&#34;https://gitlab.com/andreyorst/deps.fnl/-/issues&#34; target=&#34;_blank&#34;&gt;issues&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If the project gets enough traction and is to community&amp;rsquo;s satisfaction, Phil and I are discussing the possibility of including this into Fennel itself, so no installation would be required.
Since &lt;code&gt;deps&lt;/code&gt; is already a drop-in replacement for &lt;code&gt;fennel&lt;/code&gt;, once &lt;code&gt;deps&lt;/code&gt; is a part of the fennel executable, all commands from the above would work with just fennel itself.&lt;/p&gt;
&lt;p&gt;Thanks for reading, and I hope this project will be useful to you!&lt;/p&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: deps.fnl - a new dependency manager for Fennel projects&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Fri, 10 Jan 2025 00:47:00 +0300</pubDate>
    </item><item>
      <title>Extending Emacs with Fennel</title>
      <link>https://andreyor.st/posts/2024-12-20-extending-emacs-with-fennel/</link>
      <guid>https://andreyor.st/posts/2024-12-20-extending-emacs-with-fennel/</guid>
      <description>&lt;p&gt;After watching this year&amp;rsquo;s EmacsConf and seeing Guile Emacs being resurrected I thought to myself - why limit ourselves to Guile?
Sure, Guile isn&amp;rsquo;t just a Scheme implementation, thanks to its compiler-tower-based design.
Other languages exist for Guile VM, such as Emacs Lisp, and Guile manual lists the following languages with various stages of completeness:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;ECMAScript&lt;/li&gt;
&lt;li&gt;Brainfuck&lt;/li&gt;
&lt;li&gt;Lua&lt;/li&gt;
&lt;li&gt;Ruby&lt;/li&gt;
&lt;li&gt;Python&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Sure, it would be nice, if Emacs could natively run all of these, but we have to understand, that Guile Lua is not PUC Lua.
Even LuaJIT has difficulties maintaining full compatibility with modern releases of Lua, having us stuck in the realm somewhere between Lua 5.1 and 5.2, while PUC Lua is already 5.4.
Future releases would bring more differences, making PUC Lua and Luajit diverge even more.&lt;/p&gt;
&lt;p&gt;And Lua is a &lt;em&gt;simple&lt;/em&gt; language, unlike something like JS, Ruby, or Python.
So I wouldn&amp;rsquo;t bet on the fact that Guile Ruby would be exactly the same as Ruby.
Maybe it will, but it&amp;rsquo;ll probably take years.&lt;/p&gt;
&lt;p&gt;So I thought, why not just use Lua as is?
The only thing we can&amp;rsquo;t do is to run Fennel functions from Emacs Lisp.
There were &lt;a href=&#34;https://github.com/edrx/emlua&#34; target=&#34;_blank&#34;&gt;attempts at bringing Lua VM into Emacs&lt;/a&gt;, running in the same process, however, as I know, it isn&amp;rsquo;t stable enough.&lt;/p&gt;
&lt;p&gt;However, Emacs can connect to a Fennel REPL, like it does for many other languages, such as Common Lisp or Clojure.
Sure, the language is running in a separate process, and this comes with a lot of nuances, but it&amp;rsquo;s still a possible route.&lt;/p&gt;
&lt;p&gt;So I made a small package: &lt;a href=&#34;https://gitlab.com/andreyorst/require-fennel.el&#34; target=&#34;_blank&#34;&gt;require-fennel.el&lt;/a&gt;.
It&amp;rsquo;s capable of loading Fennel (or Lua) modules, and defining a set of functions on the Emacs side for every Fennel function in the module.&lt;/p&gt;
&lt;h2 id=&#34;running-fennel-from-emacs-lisp&#34;&gt;Running Fennel from Emacs Lisp&lt;/h2&gt;
&lt;p&gt;For example, we can load Fennel itself into Emacs like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;require-fennel&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fennel&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now we have all sorts of functions available, for example, here&amp;rsquo;s &lt;code&gt;fennel.eval&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fennel.eval&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;(fcollect [i 1 10] (* i i))&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; =&amp;gt; [1 4 9 16 25 36 49 64 81 100]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Or, we can create a file &lt;code&gt;greet.fnl&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;greet&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Greets NAME with a message.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;print &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Hello, &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; from Fennel!&amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;and load it:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;require-fennel&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;greet&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;greet&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Andrey&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;require-fennel&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;foo&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;require-fennel&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vec-add&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;src-block-caption&#34;&gt;
  &lt;span class=&#34;src-block-number&#34;&gt;Code Snippet 1:&lt;/span&gt;
  &#34;Hello, Andrey from Fennel!&#34; will be displayed in the echo area of Emacs
&lt;/div&gt;
&lt;p&gt;Let&amp;rsquo;s ask Emacs to describe the &lt;code&gt;greet&lt;/code&gt; function:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;greet is a interpreted-function.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(greet NAME)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Greets NAME with a message.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As can be seen, Emacs can show us the function signature and its documentation string obtained from Fennel.&lt;/p&gt;
&lt;p&gt;Unlike Emacs Lisp, Fennel functions support destructuring with special syntax based on how data literals are written in Fennel.
For example, let&amp;rsquo;s create a function that accepts a map, and destructures its keys:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;foo&lt;/span&gt; [{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt;}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Accepts a map with the X and Y keys, and adds them together.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;After loading it in Emacs we&amp;rsquo;ll see the following documentation:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;foo is a interpreted-function.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(foo ((:y . y) (:x . x)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Accepts a map with the X and Y keys, and adds them together.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I took some creative liberties and made it so Fennel hash tables are represented as association lists in Emacs Lisp.
So the &lt;code&gt;((:x . 1) (:y . 2))&lt;/code&gt; in Elisp is equal to &lt;code&gt;{:x 1 :y 2}&lt;/code&gt; in Fennel.
The argument list on the Emacs Lisp side is a bit unconventional, but I think that&amp;rsquo;s OK.&lt;/p&gt;
&lt;p&gt;The same goes for vector destructuring:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vec-add&lt;/span&gt; [[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x0&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y0&lt;/span&gt;] [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x1&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y1&lt;/span&gt;]]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Adds two 2D vectors.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  [(&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x0&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x1&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y0&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y1&lt;/span&gt;)])
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Emacs&amp;rsquo; documentation uses lists:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;vec-add is a interpreted-function.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(vec-add (X0 y0) (X1 y1))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Adds two 2D vectors.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I couldn&amp;rsquo;t make it work with vectors for some reason, and as can be seen, Emacs tries to upcase parameters, but it doesn&amp;rsquo;t recognize that &lt;code&gt;y0&lt;/code&gt; is also a parameter.
Probably fine, as such documentation would never be generated for Emacs Lisp functions.&lt;/p&gt;
&lt;p&gt;We can call such a function with both vectors and lists:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vec-add&lt;/span&gt; [1 2] [1 2])   &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;=&amp;gt; [2 4]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vec-add&lt;/span&gt; &amp;#39;(1 2) &amp;#39;(1 2)) &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;=&amp;gt; [2 4]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That&amp;rsquo;s because Fennel doesn&amp;rsquo;t have a list datatype, it only has associative and sequential tables.
Thus I&amp;rsquo;m using Elisp vectors as the result type.&lt;/p&gt;
&lt;h3 id=&#34;data-conversion&#34;&gt;Data conversion&lt;/h3&gt;
&lt;p&gt;Here&amp;rsquo;s how conversion table when passing data from Elisp to Fennel:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Elisp&lt;/th&gt;
&lt;th&gt;Fennel&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;[1 2 3]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;[1 2 3]&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;(1 2 3)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;[1 2 3]&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;((:foo . 1) (:bar . 2))&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{:foo 1 :bar 2}&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;#s(hash-table test equal data (&amp;quot;foo&amp;quot; 1 &amp;quot;bar&amp;quot; 2))&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{:foo 1 :bar 2}&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;:foo&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;&amp;quot;foo&amp;quot;&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;&#39;false&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;false&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;&amp;quot;foo&amp;quot;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;&amp;quot;foo&amp;quot;&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;And here&amp;rsquo;s the conversion table when receiving data from Fennel in Emacs:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Fennel&lt;/th&gt;
&lt;th&gt;Elisp&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;[1 2 3]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;[1 2 3]&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;{:foo 1 :bar 2}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;((:foo . 1) (:bar . 2))&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;(values 1 2 3)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;(1 2 3)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;(fn [])&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;(lambda (&amp;amp;rest args) ...)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;userdata&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;#&amp;lt;udata: 0x55b66bd6ac28&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;true&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;t&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nil&lt;/code&gt;, &lt;code&gt;false&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;nil&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;A small note about hash tables and multiple value returns.
As can be seen, both are returned as lists.
I specifically chose the cons notation for association lists, i.e. &lt;code&gt;(a . b)&lt;/code&gt; because this way we can tell apart hash tables and mustivalues.
There are no cons cells in Fennel, so no other data structure will be represented like that.&lt;/p&gt;
&lt;p&gt;Because multiple values are returned as lists, we have to call apply, if we wish to compose two Fennel functions.
In other words, in Fennel we can do this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rest&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;] &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;first&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt;] &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;first&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rest&lt;/span&gt; 1 2 3)) &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;=&amp;gt; 2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;first&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rest&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;src-block-caption&#34;&gt;
  &lt;span class=&#34;src-block-number&#34;&gt;Code Snippet 2:&lt;/span&gt;
  &lt;code&gt;fr.fnl&lt;/code&gt;
&lt;/div&gt;
&lt;p&gt;In Elisp, however, we would have to do:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;require-fennel&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fr&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;apply&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;#&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fr.first&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fr.rest&lt;/span&gt; 1 2 3)) &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;=&amp;gt; 2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If we were to call it as &lt;code&gt;(fr.first (fr.rest 1 2 3))&lt;/code&gt; the result would be &lt;code&gt;[2 3]&lt;/code&gt;, because &lt;code&gt;fr.rest&lt;/code&gt; returned a list of return values, and lists are converted to vectors or hash maps depending on their structure.&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s the basic gist of this package.&lt;/p&gt;
&lt;h3 id=&#34;more-examples&#34;&gt;More examples&lt;/h3&gt;
&lt;p&gt;After implementing it I was like a kid in a toy store.
With a childish grin, I started loading all my crazy Fennel libraries that I made over the years.&lt;/p&gt;
&lt;p&gt;For example, here&amp;rsquo;s &lt;code&gt;cljlib&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;require-fennel&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cljlib&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cljlib.conj&lt;/span&gt; [1] 2) &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;=&amp;gt; [1 2]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Or, here&amp;rsquo;s a JSON parser I made:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fennel&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;json&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;json.decode&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;{\&amp;#34;foo\&amp;#34;: [1, 2, 3]}&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; ((&amp;#34;foo&amp;#34; . [1 2 3]))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;json.encode&lt;/span&gt; &amp;#39;((&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;foo&amp;#34;&lt;/span&gt; . [1 2 3])))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; &amp;#34;{\&amp;#34;foo\&amp;#34;: [1, 2, 3]}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Here&amp;rsquo;s a crazy one - I&amp;rsquo;m loading my Fennel port of a Clojure library clj-http into Emacs, and calling it from Elisp:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;require-fennel&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;io.gitlab.andreyorst.fnl-http&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;require-fennel&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;io.gitlab.andreyorst.fnl-http.client&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:as&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;client&lt;/span&gt;) &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;; nested module&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;client.get&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;http://httpbin.org/get&amp;#34;&lt;/span&gt; &amp;#39;((&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:as&lt;/span&gt; . &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:json&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; =&amp;gt; ((&amp;#34;headers&amp;#34; . ((&amp;#34;Content-Length&amp;#34; . &amp;#34;198&amp;#34;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;;                   (&amp;#34;Access-Control-Allow-Credentials&amp;#34; . t)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;;                   (&amp;#34;Access-Control-Allow-Origin&amp;#34; . &amp;#34;*&amp;#34;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;;                   (&amp;#34;Content-Type&amp;#34; . &amp;#34;application/json&amp;#34;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;;                   (&amp;#34;Connection&amp;#34; . &amp;#34;keep-alive&amp;#34;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;;                   (&amp;#34;Server&amp;#34; . &amp;#34;gunicorn/19.9.0&amp;#34;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;;                   (&amp;#34;Date&amp;#34; . &amp;#34;Mon, 16 Dec 2024 22:56:35 GMT&amp;#34;)))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;;     (&amp;#34;reason-phrase&amp;#34; . &amp;#34;OK&amp;#34;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;;     (&amp;#34;length&amp;#34; . 198)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;;     (&amp;#34;protocol-version&amp;#34; . ((&amp;#34;name&amp;#34; . &amp;#34;HTTP&amp;#34;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;;                            (&amp;#34;minor&amp;#34; . 1)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;;                            (&amp;#34;major&amp;#34; . 1)))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;;     (&amp;#34;request-time&amp;#34; . 214)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;;     (&amp;#34;trace-redirects&amp;#34; . [])&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;;     (&amp;#34;status&amp;#34; . 200)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;;     (&amp;#34;body&amp;#34; . ((&amp;#34;args&amp;#34; . [])&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;;                (&amp;#34;headers&amp;#34; . ((&amp;#34;Host&amp;#34; . &amp;#34;httpbin.org&amp;#34;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;;                              (&amp;#34;X-Amzn-Trace-Id&amp;#34; . &amp;#34;Root=1-6760b023-39ca8e413573df5d14d09486&amp;#34;)))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;;                (&amp;#34;url&amp;#34; . &amp;#34;http://httpbin.org/get&amp;#34;))))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;src-block-caption&#34;&gt;
  &lt;span class=&#34;src-block-number&#34;&gt;Code Snippet 3:&lt;/span&gt;
  I&#39;ve formatted nested alists to use dot notation for better reading clarity. In other words changed &lt;code&gt;(a (b . c) (d . e))&lt;/code&gt; into &lt;code&gt;(a . ((b . c) (d . e)))&lt;/code&gt; which are the same thing.
&lt;/div&gt;
&lt;p&gt;The client made an HTTP request from the Fennel side and passed the response back to Emacs.
The response body was in JSON, but specifying &lt;code&gt;((:as . :json))&lt;/code&gt; as options map forced parsing the response body into Fennel tables.
Which, upon arriving in Emacs Lisp were converted into association lists.&lt;/p&gt;
&lt;p&gt;So now we can call Fennel from Elisp.
But why stop there?
Let&amp;rsquo;s call Emacs Lisp from Fennel!&lt;/p&gt;
&lt;h2 id=&#34;running-elisp-from-fennel-dot-dot&#34;&gt;Running ELisp from Fennel?..&lt;/h2&gt;
&lt;p&gt;Since this package uses the &lt;a href=&#34;https://andreyor.st/posts/2023-03-25-implementing-a-protocol-based-fennel-repl-and-emacs-client/&#34;&gt;Fennel Proto REPL&lt;/a&gt;, which is a custom protocol that can be extended at runtime, we can create a set of functions that will allow us to call back to Elisp.
Here&amp;rsquo;s how we extend the protocol:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;format-elisp&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_G.___repl___.pp&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocol.env-set!&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:emacs&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:call&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;-&amp;gt;&amp;gt; &lt;/span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:__index&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                       (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;k&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                         (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                           (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocol.message&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            [[&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:id&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:sym&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocol.id&lt;/span&gt;}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                             [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:op&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:string&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:require-fennel/call&lt;/span&gt;}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                             [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:fun&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:sym&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;k&lt;/span&gt;}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                             [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:arguments&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:list&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fcollect&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt; 1 (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;select &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;#&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                                  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;format-elisp&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;pick-values &lt;/span&gt;1 (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;select &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;))))}]])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                           (&lt;span style=&#34;font-weight:bold&#34;&gt;. &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocol.receive&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:data&lt;/span&gt;)))}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;setmetatable &lt;/span&gt;{}))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:var&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;-&amp;gt;&amp;gt; &lt;/span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:__index&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;k&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocol.message&lt;/span&gt; [[&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:id&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:sym&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocol.id&lt;/span&gt;}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                           [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:op&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:string&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:require-fennel/var&lt;/span&gt;}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                           [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:var&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:sym&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;k&lt;/span&gt;}]])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        (&lt;span style=&#34;font-weight:bold&#34;&gt;. &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocol.receive&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:data&lt;/span&gt;))}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                     (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;setmetatable &lt;/span&gt;{}))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:eval&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;expr&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocol.message&lt;/span&gt; [[&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:id&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:sym&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocol.id&lt;/span&gt;}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                      [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:op&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:string&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:require-fennel/eval&lt;/span&gt;}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                      [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:expr&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:sym&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;expr&lt;/span&gt;}]])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   (&lt;span style=&#34;font-weight:bold&#34;&gt;. &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocol.receive&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:data&lt;/span&gt;))})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:id&lt;/span&gt; 1000 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:nop&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I had to update the protocol core a bit, adding the &lt;code&gt;protocol.env-set!&lt;/code&gt; and &lt;code&gt;protocol.receive&lt;/code&gt; functions.
The &lt;code&gt;env-set!&lt;/code&gt; allows us to create user-visible definitions.
So we add the &lt;code&gt;emacs&lt;/code&gt; table that holds three fields.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;call&lt;/code&gt; field is a table with some metatable trickery.
Since it&amp;rsquo;s an empty table, any key would trigger the &lt;code&gt;__index&lt;/code&gt; metamethod.
This metamethod can be another table or a function - in our case, it is the latter.
This function returns a handler that calls into &lt;code&gt;protocol.message&lt;/code&gt; that sends a custom OP &lt;code&gt;require-fennel/call&lt;/code&gt; that we can handle in our package.&lt;/p&gt;
&lt;p&gt;The same goes for the &lt;code&gt;var&lt;/code&gt; field, except it doesn&amp;rsquo;t return a function, it just returns a value.&lt;/p&gt;
&lt;p&gt;The last field, &lt;code&gt;eval&lt;/code&gt;, is a combination of both, kinda.
It is a function, not a table, and it accepts one argument - an expression to evaluate in Emacs.&lt;/p&gt;
&lt;p&gt;However, we can&amp;rsquo;t use these just yet.
The second part of the trick comes from the new ability to extend the main protocol handler with custom handlers:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cl-defgeneric&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fennel-proto-repl-handle-custom-op&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_op&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_message&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_callbacks&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Handler for a custom protocol OP.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;The first argument OP is used for dispatching.  Accepts the whole
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;MESSAGE, and its CALLBACKS.  The default implementation of unknown OP is
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;a nop.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With this generic function, we can define new handlers in separate packages.
These are the methods I&amp;rsquo;ve added in &lt;code&gt;require-fennel.el&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cl-defmethod&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fennel-proto-repl-handle-custom-op&lt;/span&gt; ((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;op&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;eql&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:require-fennel/call&lt;/span&gt;)) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;callbacks&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Custom handler for the require-fennel/call OP.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;Accepts a MESSAGE and its CALLBACKS.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;The MESSAGE contains a function to evaluate and its arguments.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fennel-proto-repl-send-message&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;format&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;{:id %s :data %s}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;plist-get&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:id&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;apply&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;plist-get&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:fun&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;plist-get&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:arguments&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cl-defmethod&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fennel-proto-repl-handle-custom-op&lt;/span&gt; ((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;op&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;eql&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:require-fennel/var&lt;/span&gt;)) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;callbacks&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Custom handler for the require-fennel/var OP.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;Accepts a MESSAGE and its CALLBACKS.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;The MESSAGE contains a var which value is then returned to Fennel.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fennel-proto-repl-send-message&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;format&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;{:id %s :data %s}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;plist-get&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:id&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;require-fennel--elisp-to-fennel&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;eval&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;plist-get&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:var&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cl-defmethod&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fennel-proto-repl-handle-custom-op&lt;/span&gt; ((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;op&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;eql&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:require-fennel/eval&lt;/span&gt;)) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;callbacks&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Custom handler for the require-fennel/var OP.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;Accepts a MESSAGE and its CALLBACKS.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;The MESSAGE contains an expression which is evaluated and its result is returned to Fennel.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fennel-proto-repl-send-message&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;format&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;{:id %s :data %s}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;plist-get&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:id&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;require-fennel--elisp-to-fennel&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;eval&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;plist-get&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:expr&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;These three fields and methods allow us to do anything with Emacs, and it happens in the same process, so we can access the full Emacs state.
For example:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; Welcome to Fennel Proto REPL 0.6.0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; Fennel version: 1.5.1-dev&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; Lua version: PUC Lua 5.4&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;emacs.call.emacs-uptime&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;19 minutes, 17 seconds&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;emacs.var.emacs-version&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;31.0.50&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;emacs.eval&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;(with-current-buffer \&amp;#34; *fennel-elisp*\&amp;#34; (buffer-substring-no-properties (point-min) (point-max)))&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;;; Welcome to Fennel Proto REPL 0.6.0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;;; Fennel version: 1.5.1-dev
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;;; Lua version: PUC Lua 5.4
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;gt;&amp;gt; (emacs.call.emacs-uptime)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;\&amp;#34;19 minutes, 17 seconds\&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;gt;&amp;gt; emacs.var.emacs-version
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;\&amp;#34;31.0.50\&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;gt;&amp;gt; (emacs.eval \&amp;#34;(with-current-buffer \\\&amp;#34; *fennel-elisp*\\\&amp;#34; (buffer-substring-no-properties (point-min) (point-max)))\&amp;#34;)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;gt;&amp;gt; &amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Crazy!&lt;/p&gt;
&lt;h2 id=&#34;fennelmacs&#34;&gt;Fennelmacs&lt;/h2&gt;
&lt;p&gt;So now we can write Fennel scripts that can obtain data from Emacs, process it, and pass back the results.
Thus, our goal is achieved - we&amp;rsquo;ve added a second language to Emacs!&lt;/p&gt;
&lt;p&gt;Of course, it&amp;rsquo;s not the same as what Guile Emacs does.
We&amp;rsquo;re still running code in a separate process, adding communication between the two via some protocol.
It&amp;rsquo;s a neat trick, nothing more.
Guile Emacs, if it ever becomes the thing, will be more powerful, as we would be able to leverage all these different languages in the same process, possibly sharing the memory, calling functions interchangeably, etc.
Some may even write Emacs packages in Brainfuck, who knows.&lt;/p&gt;
&lt;p&gt;Still, this is really cool, in my opinion, and shows the power of Emacs pretty well.
If you&amp;rsquo;re into Fennel, like me, I hope you&amp;rsquo;ll enjoy using this package as I enjoyed making it.
See you at &lt;a href=&#34;https://conf.fennel-lang.org/2024&#34; target=&#34;_blank&#34;&gt;Fennel Conf&lt;/a&gt;!&lt;/p&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: Extending Emacs with Fennel&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Fri, 20 Dec 2024 03:23:00 +0300</pubDate>
    </item><item>
      <title>Extending JSON encoder with custom types</title>
      <link>https://andreyor.st/posts/2024-11-04-extending-json-encoder-with-custom-types/</link>
      <guid>https://andreyor.st/posts/2024-11-04-extending-json-encoder-with-custom-types/</guid>
      <description>&lt;p&gt;One thing I like about Lua is that it has a limited amount of built-in types and data structures.
There are no objects, just tables.
And if you need a custom behavior, a metatable can be attached to any table to extend it with custom methods that integrate with the rest of Lua runtime.&lt;/p&gt;
&lt;p&gt;However, this is both a blessing and a curse.
And unfortunately, Lua developers made a huge mistake by breaking this API&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt; once already, in a minor release even.&lt;/p&gt;
&lt;p&gt;As you may noticed, &lt;a href=&#34;https://gitlab.com/andreyorst/fnl-http&#34; target=&#34;_blank&#34;&gt;fnl-http&lt;/a&gt; has a lot of stuff.
It has asynchronous Channels, and various Readers, which act like objects, but are still ordinary tables underneath.
And this is true for a lot of Lua projects, tables are flexible enough to implement many cool things, so people do.&lt;/p&gt;
&lt;p&gt;However, this poses an interesting problem - because objects are not a thing in Lua, and a set of default metamethods is quite limited, there&amp;rsquo;s no default way of extending objects with custom behavior.
In Java, you would specify what interfaces are required for an object to have, and it often means that if something doesn&amp;rsquo;t implement them, a wrapper object is needed.
In Clojure, we can get away with protocols and multimethods, but Lua has neither of those.
In Lua, and subsequently Fennel, we have to be creative, because even though we can add stuff through metatables, not every value can have one.&lt;/p&gt;
&lt;p&gt;While working on fnl-http, I added a basic JSON parser and encoder.
The parser part is quite simple, as JSON has a specification and a fixed amount of data types to worry about.
It&amp;rsquo;s not like &lt;a href=&#34;https://github.com/edn-format/edn&#34; target=&#34;_blank&#34;&gt;EDN&lt;/a&gt; or XML, for example, which are both extensible data notations that can represent pretty much anything.
In JSON you get only these data types:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Number&lt;/li&gt;
&lt;li&gt;String&lt;/li&gt;
&lt;li&gt;Array&lt;/li&gt;
&lt;li&gt;Object&lt;/li&gt;
&lt;li&gt;Boolean&lt;/li&gt;
&lt;li&gt;Null&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The only difference from Lua here is that &lt;code&gt;null&lt;/code&gt; is &lt;code&gt;nil&lt;/code&gt; and Lua doesn&amp;rsquo;t have arrays as a separate type.
So implementing a parser was easy, and everything pretty much maps to Lua data structures one-to-one.&lt;/p&gt;
&lt;p&gt;Implementing JSON encoder, however, was not as easy.
For basic data types, it is easy enough, but once we touch custom objects created with metatables things get messy.&lt;/p&gt;
&lt;p&gt;For example, let&amp;rsquo;s say we need a set data structure.
A set is similar to a table, except the values are the same as the keys.
But, we may want to distinguish them from ordinary tables, if, say, we&amp;rsquo;re making a library that has a set of functions for working with mathematical sets.
Like &lt;code&gt;intersection&lt;/code&gt;, &lt;code&gt;difference&lt;/code&gt;, etc.
Here&amp;rsquo;s a set constructor:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Set&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;faccumulate&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt; {}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                           &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; 1 (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;select &lt;/span&gt;&lt;span style=&#34;&#34;&gt;:&lt;/span&gt;# &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;k&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;select &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 (&lt;span style=&#34;font-weight:bold&#34;&gt;doto &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;tset &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;k&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;k&lt;/span&gt;))))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;setmetatable&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     {}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:__index&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:__newindex&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;k&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt;] (&lt;span style=&#34;font-weight:bold&#34;&gt;tset &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;k&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;k&lt;/span&gt;))})))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As you can see, we create an empty table and set its metatable to a bunch of functions that close over the local &lt;code&gt;data&lt;/code&gt;.
This technique is quite common in Lua and is called &lt;a href=&#34;https://www.lua.org/pil/13.4.4.html&#34; target=&#34;_blank&#34;&gt;proxy tables&lt;/a&gt;.
By using the empty table as a base, we ensure that any table access triggers the &lt;code&gt;__index&lt;/code&gt; or &lt;code&gt;__newindex&lt;/code&gt; metamethod, depending on the action.&lt;/p&gt;
&lt;p&gt;However, there&amp;rsquo;s a problem.
If we try to print such an object in the REPL, we don&amp;rsquo;t get any information about it, even though it has values:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Set&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:a&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:b&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:c&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:a&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;a&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;set &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:d&lt;/span&gt;) 42)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:d&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;d&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Additionally to that, we have no means of iteration over this data structure, as the default &lt;code&gt;next&lt;/code&gt; function will just return &lt;code&gt;nil&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;next &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We can fix this by adding a &lt;code&gt;__pairs&lt;/code&gt; metamethod:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Set&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;faccumulate&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt; {}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                           &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; 1 (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;select &lt;/span&gt;&lt;span style=&#34;&#34;&gt;:&lt;/span&gt;# &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;k&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;select &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 (&lt;span style=&#34;font-weight:bold&#34;&gt;doto &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;tset &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;k&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;k&lt;/span&gt;))))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;setmetatable&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     {}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:__index&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:__newindex&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;k&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt;] (&lt;span style=&#34;font-weight:bold&#34;&gt;tset &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;k&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;k&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:__pairs&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt;] #(&lt;span style=&#34;font-weight:bold&#34;&gt;pick-values &lt;/span&gt;1 (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;next &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;$2&lt;/span&gt;)))})))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now, printing works, albeit in a bit strange way:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Set&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:a&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:b&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:c&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:a&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:b&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:c&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;A few years ago, I &lt;a href=&#34;https://andreyor.st/posts/2021-01-09-pretty-printing-for-fennel-language/&#34;&gt;remade&lt;/a&gt; the pretty-printer for Fennel, and support for custom objects was a huge part of its design.
In short, we can fix our object textual representation by using the &lt;code&gt;__fennelview&lt;/code&gt; metamethod.&lt;/p&gt;
&lt;p&gt;Now, &lt;code&gt;__fennelview&lt;/code&gt; is fine and all, but it is not exactly meant for extending existing objects.
Of course, given a Lua library, that implements these proxy tables you can add support for Fennel, but it&amp;rsquo;s more of an ad-hoc solution.
So it&amp;rsquo;s meant for library authors to make the Fennel REPL experience more user-friendly, and make sure that the printed representation can be read back by Fennel.&lt;/p&gt;
&lt;p&gt;And it&amp;rsquo;s not always possible to add &lt;code&gt;__fennelview&lt;/code&gt; to existing objects.
For example, one common complaint in Lua is that arrays start from &lt;code&gt;1&lt;/code&gt; and not &lt;code&gt;0&lt;/code&gt;.
We can &amp;ldquo;fix&amp;rdquo; that by implementing our own Array type:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Array&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vals&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;]]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;setmetatable&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     []
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:__index&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 (&lt;span style=&#34;font-weight:bold&#34;&gt;. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vals&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; 1)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:__newindex&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;val&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    (&lt;span style=&#34;font-weight:bold&#34;&gt;tset &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vals&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;- &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; 1) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;val&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:__len&lt;/span&gt; #(&lt;span style=&#34;font-weight:bold&#34;&gt;length &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vals&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:__pairs&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt;] #(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;next &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vals&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;$2&lt;/span&gt;))})))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Right now, the object above prints like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Array&lt;/span&gt; 1 2 3)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[1 2 3]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Let&amp;rsquo;s assume this came from the library, and we wish to print this differently, e.g. as &lt;code&gt;(Array 1 2 3)&lt;/code&gt; instead of &lt;code&gt;[1 2 3]&lt;/code&gt; to make sure that such arrays are read back as 0-based arrays, and not as ordinary Lua tables.
We can do that, but it is tricky because we don&amp;rsquo;t have any means of accessing the &lt;code&gt;data&lt;/code&gt; closure:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;wrap&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;arr&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;tset &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;getmetatable &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;arr&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:__fennelview&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pp-doc-example&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;view&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;options&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;indent&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lines&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;icollect &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;v&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;pairs &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;v&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;view&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;v&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;options&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;7 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;indent&lt;/span&gt;))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                      (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; 1) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;v&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                          (&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;       &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;v&lt;/span&gt;))))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold&#34;&gt;doto &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lines&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;font-weight:bold&#34;&gt;tset &lt;/span&gt;1 (&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;(Array &amp;#34;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;or &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lines&lt;/span&gt; 1) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;font-weight:bold&#34;&gt;tset &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;length &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lines&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lines&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;length &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lines&lt;/span&gt;)) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;)&amp;#34;&lt;/span&gt;))))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;arr&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;However, as you can see, we have to use &lt;code&gt;wrap&lt;/code&gt; on every &lt;code&gt;Array&lt;/code&gt;, because each instance comes with its own metatable, and setting it once wouldn&amp;rsquo;t work.
And if we try to read back the printed representation we&amp;rsquo;ll get the old representation:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;wrap&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Array&lt;/span&gt; 1 2 3))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Array&lt;/span&gt; 1 2 3)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Array&lt;/span&gt; 1 2 3)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[1 2 3]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So we can make another wrapper:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Array*&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Array&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Array&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;wrap&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Array*&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Array&lt;/span&gt; 1 2 3)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Array&lt;/span&gt; 1 2 3)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So you can see, how this is a bit problematic.&lt;/p&gt;
&lt;h2 id=&#34;custom-json-encoders&#34;&gt;Custom JSON encoders&lt;/h2&gt;
&lt;p&gt;Now, this was a bit of a tangent, so let&amp;rsquo;s get back to the main topic - JSON encoding.
Because I can&amp;rsquo;t ask everyone to do this kind of wrapping, I decided to implement a different way of extending the &lt;code&gt;json.encode&lt;/code&gt; function.
Thus, the library now features two more functions: &lt;code&gt;register-encoder&lt;/code&gt; and &lt;code&gt;unregister-encoder&lt;/code&gt;.
The second one is for fixing mistakes, and won&amp;rsquo;t probably be used too much.&lt;/p&gt;
&lt;p&gt;So, let&amp;rsquo;s see how we can add support for custom types.
First, we need a function that will tell if the given object is an instance of something we want to encode:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Array?&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;and &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:table&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;type &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;font-weight:bold&#34;&gt;not= &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; 0))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Array&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;A library may provide a custom predicate to check if the given object is of the same type, like &lt;code&gt;chan?&lt;/code&gt; for asynchronous channels.
However, it can&amp;rsquo;t be used as is, because to register an encoder, such a function needs to return a singleton, that can be compared with &lt;code&gt;=&lt;/code&gt;.
So we return &lt;code&gt;Array&lt;/code&gt; from our example function.&lt;/p&gt;
&lt;p&gt;Next, we can implement the encoder:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;encode-array&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;arr&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;encode&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;[&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;-&amp;gt; &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fcollect&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; 0 (&lt;span style=&#34;font-weight:bold&#34;&gt;- &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;length &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;arr&lt;/span&gt;) 1)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;encode&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;arr&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;table.concat &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;, &amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;]&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Finally, we can register it:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;json.register-encoder&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;object&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;object?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;encode-object&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The first argument is the object itself, and the second one is a function to obtain the object&amp;rsquo;s type.
Internally, &lt;code&gt;register-encoder&lt;/code&gt; calls the &lt;code&gt;object?&lt;/code&gt; function on the first argument to provide a bit more flexibility, in case &lt;code&gt;object?&lt;/code&gt; returns different values for different objects or based on the object&amp;rsquo;s properties.
The third argument is a function that provides the encoding.
It accepts a callback to encode nested values as a second argument.&lt;/p&gt;
&lt;p&gt;With that, we can register the encoder and encode our array as JSON by calling &lt;code&gt;(json (Array 1 2 3))&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;json.register-encoder&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Array&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Array?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;encode-array&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;json&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Array&lt;/span&gt; 1 2 3))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;[1, 2, 3]&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This should provide enough flexibility to support any proxy-based objects.&lt;/p&gt;
&lt;h2 id=&#34;custom-decoders&#34;&gt;Custom decoders&lt;/h2&gt;
&lt;p&gt;I decided not to add custom decoder support to this library, yet.
JSON doesn&amp;rsquo;t have any custom types, so it doesn&amp;rsquo;t make sense to parse its values to anything but default Lua types.&lt;/p&gt;
&lt;p&gt;One could argue, that it would be nice to have a way to parse arrays to zero-based ones, given that we can convert zero-based arrays to JSON.
While true, I think this only adds unnecessary complexity to the parser.&lt;/p&gt;
&lt;p&gt;One reason, registering an encoder requires a singleton as type designator is to ensure that objects can&amp;rsquo;t be mixed up.
If it was allowed to register encoders via string types, it would be possible to register two &lt;code&gt;&amp;quot;Array&amp;quot;&lt;/code&gt; types, making ambiguous what encoder would be used or would require to change the name in case of conflict.&lt;/p&gt;
&lt;p&gt;JSON has a fixed amount of types, so registering a decoder for, say, Array, would mean that all arrays would be parsed to this custom type in all of the project parts.
Meaning, that if you use a different library, that also uses this JSON parser, and internally expects one-based arrays it will break.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m open to changing my mind on this, but for now, I feel that custom encoders are sufficient enough to make this library more usable.
As a part of this change, I&amp;rsquo;m moving this library out from the &lt;code&gt;fnl-http&lt;/code&gt; repo into its own library, making &lt;code&gt;fnl-http&lt;/code&gt; depend on it instead, making it possible for other projects to use this parser more easily.
You can find the code &lt;a href=&#34;https://gitlab.com/andreyorst/json.fnl&#34; target=&#34;_blank&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Thanks for reading, and I hope this library will be useful!&lt;/p&gt;
&lt;h2 id=&#34;foontones&#34;&gt;Foontones&lt;/h2&gt;
&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;
&lt;p&gt;The &lt;a href=&#34;https://www.lua.org/manual/5.3/manual.html#8.2&#34; target=&#34;_blank&#34;&gt;deprecation&lt;/a&gt; of &lt;code&gt;__ipairs&lt;/code&gt; metamethod in Lua 5.3 resulted in an inability to implement custom iteration over custom sequential data structures.
For example, the zero-indexed array example would benefit from &lt;code&gt;__ipairs&lt;/code&gt; because we could specify that the iteration starts from &lt;code&gt;0&lt;/code&gt;.
With the default &lt;code&gt;ipairs&lt;/code&gt; we would always miss the first value.
It&amp;rsquo;s not hard to fix manually, by overriding &lt;code&gt;ipairs&lt;/code&gt; with a custom function that checks for &lt;code&gt;__ipairs&lt;/code&gt; metamethod:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ipairs*&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ipairs&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_G.ipairs&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tbl&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;case&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;getmetatable &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tbl&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:__ipairs&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ip&lt;/span&gt;} (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ip&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tbl&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ipairs*&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tbl&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;However, it&amp;rsquo;s not practical to intrude into Lua&amp;rsquo;s standard library in such a way.&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: Extending JSON encoder with custom types&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Mon, 04 Nov 2024 06:39:00 +0300</pubDate>
    </item><item>
      <title>Streaming and receiving chunked multipart data with fnl-http</title>
      <link>https://andreyor.st/posts/2024-11-02-streaming-and-receiving-chunked-multipart-data-with-fnl-http/</link>
      <guid>https://andreyor.st/posts/2024-11-02-streaming-and-receiving-chunked-multipart-data-with-fnl-http/</guid>
      <description>&lt;p&gt;I&amp;rsquo;ve been absent for a while - you may have noticed that compared to the previous year, I posted a lot less this time.
There are two closely related reasons for that.
First, I felt burned out from programming.
Second, I finally picked up a guitar after five or more years and started recording again.
Thus, now I only do hobby programming when I feel passionate or challenged in an entertaining way.
This works for me, but I have less material to write about.&lt;/p&gt;
&lt;p&gt;One such passionate project for me this year is &lt;a href=&#34;https://gitlab.com/andreyorst/fnl-http&#34; target=&#34;_blank&#34;&gt;fnl-http&lt;/a&gt;.
It&amp;rsquo;s an &lt;code&gt;HTTP/1.1&lt;/code&gt; client and server implementation for Fennel made using &lt;a href=&#34;https://w3.impa.br/~diego/software/luasocket/home.html&#34; target=&#34;_blank&#34;&gt;luasocket&lt;/a&gt; and &lt;a href=&#34;https://gitlab.com/andreyorst/async.fnl&#34; target=&#34;_blank&#34;&gt;async.fnl&lt;/a&gt; - another library of mine.&lt;/p&gt;
&lt;p&gt;Last time I posted, I was mostly talking about &lt;a href=&#34;https://andreyor.st/posts/2024-08-15-fnl-http-testing-with-fennel-test/&#34;&gt;testing&lt;/a&gt;.
And I&amp;rsquo;m glad that I wrote all these tests, because the change I&amp;rsquo;m going to talk about this time broke a lot of them, and I was able to diagnose problems much quicker.
But the main changes are related to the post I made before that: &lt;a href=&#34;https://andreyor.st/posts/2024-08-01-fnl-http-improvements/&#34;&gt;fnl-http Improvements&lt;/a&gt;.
In that post, the most exciting things for me were chunked transfer encoding and support for multipart requests.
I&amp;rsquo;ve implemented support for reading chunked responses (the client already could send chunked requests) and moved onto implementing multipart requests.&lt;/p&gt;
&lt;h2 id=&#34;http-server&#34;&gt;HTTP Server&lt;/h2&gt;
&lt;p&gt;For some time, the implementation was sufficient enough, so I started working on an &lt;abbr title=&#34;Proof Of Concept&#34;&gt;POC&lt;/abbr&gt; asynchronous HTTP server.
The server is pretty much bare-bones right now, though it features everything you need to implement a proper one.
Here&amp;rsquo;s how it can be used:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;server&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:io.gitlab.andreyorst.fnl-http.server&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;json&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:io.gitlab.andreyorst.fnl-http.json&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;handler&lt;/span&gt; [{&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;headers&lt;/span&gt; &amp;amp;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;as&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;request&lt;/span&gt;}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:status&lt;/span&gt; 200
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:headers&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:connection&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;headers.Connection&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:keep-alive&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:content-type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:application/json&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:body&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;json&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;request&lt;/span&gt;)})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;with-open &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;server.start&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;handler&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:port&lt;/span&gt; 3000})]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:wait&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It&amp;rsquo;s a rather simple echo server, that sends back the parsed request as JSON.
Let&amp;rsquo;s try it:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;http&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:io.gitlab.andreyorst.fnl-http.client&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;http.get&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;localhost:3000&amp;#34;&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:as&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:json&lt;/span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:body&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:headers&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Host&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;localhost:3000&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:method&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;GET&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:path&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;/&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:protocol-version&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:major&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:minor&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;HTTP&amp;#34;&lt;/span&gt;}}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:headers&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Connection&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;keep-alive&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Content-Length&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;131&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Content-Type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;application/json&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:http-client&lt;/span&gt; #&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;tcp-client&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x561839afe390&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:length&lt;/span&gt; 131
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:protocol-version&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:major&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:minor&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;HTTP&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:reason-phrase&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;OK&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:request-time&lt;/span&gt; 13
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:status&lt;/span&gt; 200
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:trace-redirects&lt;/span&gt; {}}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now, of course, this won&amp;rsquo;t work as is, because not all Lua values can be encoded as JSON.
Such examples are functions, and custom objects, like Readers.
We can cheat, though, and encode it as a Fennel table and send it back as a string:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;{&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;view&lt;/span&gt;} (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:fennel&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;handler&lt;/span&gt; [{&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;headers&lt;/span&gt; &amp;amp;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;as&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;request&lt;/span&gt;}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:status&lt;/span&gt; 200
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:headers&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:connection&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;headers.Connection&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:keep-alive&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:content-type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:application/json&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:body&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;view&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;request&lt;/span&gt;)})
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now we can try a POST request:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;http.post&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;localhost:3000&amp;#34;&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:body&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Hello HTTP&amp;#34;&lt;/span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:body&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;{:content #&amp;lt;Reader: 0x55eeb3016fc0&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt; :headers {:Content-Length \&amp;#34;10\&amp;#34; :Host \&amp;#34;localhost:3000\&amp;#34;}
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt; :length 10
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt; :method \&amp;#34;POST\&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt; :path \&amp;#34;/\&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt; :protocol-version {:major 1 :minor 1 :name \&amp;#34;HTTP\&amp;#34;}}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:headers&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Connection&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;keep-alive&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Content-Length&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;183&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Content-Type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;application/json&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:http-client&lt;/span&gt; #&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;tcp-client&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x55eeb3059470&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:length&lt;/span&gt; 183
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:protocol-version&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:major&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:minor&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;HTTP&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:reason-phrase&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;OK&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:request-time&lt;/span&gt; 20
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:status&lt;/span&gt; 200
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:trace-redirects&lt;/span&gt; {}}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This should give you an idea of how to implement a proper handler.&lt;/p&gt;
&lt;p&gt;The reason the content is a Reader is simple - we don&amp;rsquo;t want to process any more data than we need when parsing the request.
Once we obtain the HTTP-related data, such as headers, method, path, and version, we wrap the rest of the data in a Reader object, so the handler function can work on it later or even discard it.
In this particular case, it&amp;rsquo;s as simple as doing &lt;code&gt;(request.content:read (tonumber request.headers.Content-Length))&lt;/code&gt; but it may vary depending on what was sent, and what path the client used.
So I&amp;rsquo;m leaving this open.
Using a Reader enables asynchronous and lazy processing of the request&amp;rsquo;s body.&lt;/p&gt;
&lt;h3 id=&#34;multipart-requests&#34;&gt;Multipart requests&lt;/h3&gt;
&lt;p&gt;What&amp;rsquo;s interesting, however, is that there may be multiple bodies, if the request is a multipart one.
We can send a multipart request like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;http.post&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;localhost:3000&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:multipart&lt;/span&gt; [{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;foo&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:content&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;some string&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;file&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:filename&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;some-data.json&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                         &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:content&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;io.open &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;some-data.json&amp;#34;&lt;/span&gt;)}]})
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Ideally, the server should be able to first process the &lt;code&gt;foo&lt;/code&gt; part, and then a &lt;code&gt;file&lt;/code&gt; part.
Additionally, a file can be really big, so we might want to avoid reading it fully into memory.
For example, the JSON module of &lt;code&gt;fnl-http&lt;/code&gt; can parse files without fully reading them into memory, as it is based around readers.&lt;/p&gt;
&lt;p&gt;The question, however, is how do we give this to a handler without reading the request in full first?
We don&amp;rsquo;t know how many parts there will be, and we might not know the sizes of each part.
Let&amp;rsquo;s look at how the handler encodes this request:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;http.post&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;localhost:3000&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:multipart&lt;/span&gt; [{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;foo&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:content&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;some string&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;file&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:filename&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;some-data.json&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                         &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:content&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;io.open &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;some-data.json&amp;#34;&lt;/span&gt;)}]})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:body&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;{:headers {:Content-Type \&amp;#34;multipart/form-data; boundary=------------aaec41d0-1c75-4037-a039-91cc2b31584c\&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;           :Host \&amp;#34;localhost:3000\&amp;#34;}
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt; :method \&amp;#34;POST\&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt; :parts #&amp;lt;function: 0x55eeb28e79c0&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt; :path \&amp;#34;/\&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt; :protocol-version {:major 1 :minor 1 :name \&amp;#34;HTTP\&amp;#34;}}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:headers&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Connection&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;keep-alive&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Content-Length&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;256&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Content-Type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;application/json&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:http-client&lt;/span&gt; #&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;tcp-client&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x55eeb31df9e0&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:length&lt;/span&gt; 256
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:protocol-version&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:major&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:minor&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;HTTP&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:reason-phrase&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;OK&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:request-time&lt;/span&gt; 80
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:status&lt;/span&gt; 200
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:trace-redirects&lt;/span&gt; {}}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You can see, that there&amp;rsquo;s no &lt;code&gt;content&lt;/code&gt; field anymore.
Instead, there&amp;rsquo;s a &lt;code&gt;parts&lt;/code&gt; field, and it is a function.&lt;/p&gt;
&lt;p&gt;This function is a standard Lua iterator, that you can call until it returns &lt;code&gt;nil&lt;/code&gt; or plug it in any of the iteration forms.
Let&amp;rsquo;s change our handler to support both &lt;code&gt;content&lt;/code&gt; and &lt;code&gt;parts&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;handler&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;request&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;request&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;content&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;request.content&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;request.headers.Content-Length&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;content&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;tonumber &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;request.headers.Content-Length&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;font-weight:bold&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;request.headers.Transfer-Encoding&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;chunked&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;content&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:*a&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parts&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;request.parts&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;icollect &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;part&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parts&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold&#34;&gt;doto &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;part&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;tset &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:content&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;part.content&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:*a&lt;/span&gt;))))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:status&lt;/span&gt; 200
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:body&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;json&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;request&lt;/span&gt;)})
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Let&amp;rsquo;s look at this a bit closer.
The &lt;code&gt;case&lt;/code&gt; has two branches - one for &lt;code&gt;content&lt;/code&gt; and one for &lt;code&gt;parts&lt;/code&gt;.
The &lt;code&gt;content&lt;/code&gt; branch is pretty straightforward - we replace request&amp;rsquo;s &lt;code&gt;content&lt;/code&gt; field value with the data obtained from Reader.
If there was a Content-Length header, we used it to determine how much to read.
If not, we (rather crudely) check if the chunked Transfer-Encoding was used, and read all of the data from the Reader.
We can do so, because chunked readers know when to stop, based on the final chunk header.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;parts&lt;/code&gt; branch is similar, except we have to go one level deeper, and it&amp;rsquo;s a bit simpler to work with the part&amp;rsquo;s contents.
First, the main function of &lt;code&gt;icollect&lt;/code&gt; is to produce a sequential table from the iterator values.
We do so by replacing the &lt;code&gt;content&lt;/code&gt; field of each &lt;code&gt;part&lt;/code&gt;.
The &lt;code&gt;content&lt;/code&gt; field is again a Reader, but it&amp;rsquo;s a sized reader, so we can almost always read it in full.
Even if content length was not specified, parts are separated by boundaries, so we always know when to stop.&lt;/p&gt;
&lt;p&gt;Each &lt;code&gt;part&lt;/code&gt; is a table of the following structure:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:content&lt;/span&gt; #&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;Reader&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:headers&lt;/span&gt; {&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:length&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;N&lt;/span&gt; &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; optional field, if headers had a Content-Length specified&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;part name&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:filename&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;name of the uploaded file&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; alternatively :filename* can be present instead&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;part kind&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As much information is given to make working with parts easier.
And because parts are provided by an iterator, we don&amp;rsquo;t have to know in advance how many parts are coming.&lt;/p&gt;
&lt;p&gt;However, there&amp;rsquo;s a caveat - we can&amp;rsquo;t obtain information about each part first, and process the contents later.
Moving to the next part consumes the request body until the next boundary is given, so we can&amp;rsquo;t reverse the Reader back to its content.
Thus, doing this won&amp;rsquo;t work:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;all-parts&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;icollect &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;part&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parts&lt;/span&gt;] &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;part&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;each &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;part&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;ipairs &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;all-parts&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;part.content&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:*a&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You&amp;rsquo;ll have to either copy reader contents into another in-memory Reader, or process parts as they appear.&lt;/p&gt;
&lt;p&gt;Now, we can try our request again:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;http.post&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;localhost:3000&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:multipart&lt;/span&gt; [{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;foo&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:content&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;some string&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                           {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;file&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:filename&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;some-data.json&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:content&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;io.open &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;some-data.json&amp;#34;&lt;/span&gt;)}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:as&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:json&lt;/span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:body&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:headers&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Content-Type&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;multipart/form-data; boundary=------------a03996f2-0d1c-4aa4-97f5-ac90b06cb6ea&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Host&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;localhost:3000&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:method&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;POST&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:parts&lt;/span&gt; [{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:content&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;some string&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:headers&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Content-Disposition&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;form-data; name=\&amp;#34;foo\&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                     &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Content-Length&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;11&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                     &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Content-Transfer-Encoding&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;8bit&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                     &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Content-Type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;text/plain; charset=UTF-8&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:length&lt;/span&gt; 11
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;foo&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;form-data&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:content&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;{\&amp;#34;value\&amp;#34;: \&amp;#34;JSON data\&amp;#34;}\n&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:filename&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;some-data.json&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:headers&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Content-Disposition&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;form-data; name=\&amp;#34;file\&amp;#34;; filename=\&amp;#34;some-data.json\&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                     &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Content-Transfer-Encoding&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;binary&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                     &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Content-Type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;application/octet-stream&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                     &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Transfer-Encoding&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;chunked&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;file&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;form-data&amp;#34;&lt;/span&gt;}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:path&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;/&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:protocol-version&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:major&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:minor&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;HTTP&amp;#34;&lt;/span&gt;}}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:headers&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Connection&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;keep-alive&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Content-Length&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;808&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:http-client&lt;/span&gt; #&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;tcp-client&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x55cf2d942450&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:length&lt;/span&gt; 808
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:protocol-version&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:major&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:minor&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;HTTP&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:reason-phrase&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;OK&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:request-time&lt;/span&gt; 13
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:status&lt;/span&gt; 200
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:trace-redirects&lt;/span&gt; {}}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As you can see, the &lt;code&gt;foo&lt;/code&gt; part had &lt;code&gt;length&lt;/code&gt; of &lt;code&gt;12&lt;/code&gt;, and the &lt;code&gt;file&lt;/code&gt; part had a chunked transfer encoding.&lt;/p&gt;
&lt;p&gt;Before this post, there was no way of sending multipart with chunked encoding, so this is a pretty good change in my opinion.
Definitively expands the possibilities.
Still need to test this with some real HTTP servers, as I don&amp;rsquo;t see this feature used too often though.&lt;/p&gt;
&lt;h3 id=&#34;performance&#34;&gt;Performance&lt;/h3&gt;
&lt;p&gt;Now, let&amp;rsquo;s talk performance.
I used the &lt;a href=&#34;https://github.com/wg/wrk&#34; target=&#34;_blank&#34;&gt;wrk&lt;/a&gt; tool to measure the server&amp;rsquo;s RPS with a simple handler that does 50 millisecond delay on each request:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;async&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:io.gitlab.andreyorst.async&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;handler&lt;/span&gt; [{&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;headers&lt;/span&gt; &amp;amp;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;as&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;request&lt;/span&gt;}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;async.&amp;lt;!&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;async.timeout&lt;/span&gt; 50))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:status&lt;/span&gt; 200
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:headers&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:connection&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;headers.Connection&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;keep-alive&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:content-length&lt;/span&gt; 11
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:content-type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;text/plain&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:body&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;hello world&amp;#34;&lt;/span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;handler&lt;/code&gt; function is always running in an asynchronous context, so we can use parking operations such as &lt;code&gt;&amp;lt;!&lt;/code&gt; inside of it.&lt;/p&gt;
&lt;p&gt;Running it with 12 threads and 400 connections for 30 seconds yields about 2k requests per second:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Running 30s test @ http://localhost:3000
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  12 threads and 400 connections
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  Thread Stats   Avg      Stdev     Max   +/- Stdev
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Latency   146.42ms   94.13ms   2.00s    98.54%
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Req/Sec   205.07     90.83   343.00     62.36%
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  69835 requests in 30.09s, 8.00MB read
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  Socket errors: connect 0, read 0, write 0, timeout 151
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Requests/sec:   2321.21
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Transfer/sec:    272.37KB
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Not bad for a single-threaded Lua runtime, I would say!&lt;/p&gt;
&lt;p&gt;Now, of course, this kind of benchmark is more synthetic than real, so don&amp;rsquo;t expect it to work as well as it says here in all cases.
With a more complex handler, that deals with routing, and data processing this number will go down.
Still, I&amp;rsquo;m pretty satisfied with these results.&lt;/p&gt;
&lt;p&gt;And CPU usage is quite low too.
When idling a single CPU core is sitting at about 5%, and during the benchmark, it rises to 70%.
Removing the asynchronous sleep, raises CPU usage to 100% (single core), peaking at 67MB of RAM and serving about 4k requests per second.
So with an asynchronous sleep, our server process is doing some actual sleeping, leaving some resources to the OS!&lt;/p&gt;
&lt;p&gt;And given how &lt;code&gt;async.fnl&lt;/code&gt; is &lt;a href=&#34;https://andreyor.st/posts/2023-08-02-asyncfnl-enchancements/#hooks--the-less-wrong-way&#34;&gt;implemented&lt;/a&gt;, we can actually replace &lt;code&gt;(async.&amp;lt;! (async.timeout 50))&lt;/code&gt; with a blocking loop, like &lt;code&gt;(for [i 1 1_000_000] nil)&lt;/code&gt; and still get around 400 RPS.
That&amp;rsquo;s a busy loop with one million iterations per handler invocation on each request.
So you shouldn&amp;rsquo;t worry too much when blocking the handler.&lt;/p&gt;
&lt;p&gt;Is it a good result?
You be the judge.&lt;/p&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: Streaming and receiving chunked multipart data with fnl-http&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Sat, 02 Nov 2024 04:46:00 +0300</pubDate>
    </item><item>
      <title>Interactive game development with LÖVE</title>
      <link>https://andreyor.st/posts/2024-09-08-interactive-game-development-with-love/</link>
      <guid>https://andreyor.st/posts/2024-09-08-interactive-game-development-with-love/</guid>
      <description>&lt;p&gt;This is a continuation of the &lt;a href=&#34;https://andreyor.st/posts/2024-09-08-boredom-and-gamedev/&#34;&gt;previous post&lt;/a&gt; on game development with the LÖVE game engine.
I&amp;rsquo;m slowly appreciating the freedom it gives, compared to the TIC-80 experience.
One of such freedoms is the fact, that LÖVE is a well-behaving console application.&lt;/p&gt;
&lt;p&gt;When you launch TIC, it boots up into a console:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2024-09-08-interactive-game-development-with-love/tic.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;If you do so from a terminal emulator, you can see that the same console is there too:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; TIC-80 tiny computer
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; version 1.1.2837 Pro (be42d6f)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; https://tic80.com (C) 2017-2024
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; hello! type help for help
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;gt;ls
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[tic80.com]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mtd.lua
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;However, writing in this prompt doesn&amp;rsquo;t do anything - it&amp;rsquo;s not sent back into TIC.
And unfortunately, there&amp;rsquo;s no way of reading from standard IN, because there&amp;rsquo;s no &lt;code&gt;io&lt;/code&gt; namespace provided.
One could, theoretically, fiddle with sockets, if it is even possible to load them into TIC, which I&amp;rsquo;m not so sure about.&lt;/p&gt;
&lt;p&gt;In LÖVE, however, you get full Lua experience and more!
As you may know, Lua&amp;rsquo;s &lt;code&gt;io.read()&lt;/code&gt; is blocking, and there&amp;rsquo;s no real way of making it non-blocking or checking the input buffer.
However, that&amp;rsquo;s not a problem for LÖVE, as it has threads!
So we can set up a separate thread that reads from the &lt;code&gt;stdin&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Why would we want that?
Well, you see, when it comes to Lua, I usually do my programming in Fennel, and Fennel has a decent &lt;abbr title=&#34;Read Eval Print Loop&#34;&gt;REPL&lt;/abbr&gt; for doing interactive development.
I love the idea of programming with a REPL, I do it a lot for my hobby projects, and at work with Clojure.
Interactive development makes iterations much faster, and, in my experience, minimizes the amount of bugs in the resulting program.
And we can leverage that during game development too.&lt;/p&gt;
&lt;h2 id=&#34;adding-the-repl&#34;&gt;Adding the REPL&lt;/h2&gt;
&lt;p&gt;The way we&amp;rsquo;re going to set this up is as follows:&lt;/p&gt;
&lt;p&gt;We create a new, asynchronous handler for the REPL, and spawn it on the main thread.
Then, we&amp;rsquo;re going to spawn another thread, that will listen on &lt;code&gt;stdin&lt;/code&gt;, and send everything it reads to the main thread.
Finally, once the main thread finishes the evaluation, it sends the data back to the IO thread for printing.
After that, I&amp;rsquo;m going to spice things up by using the Fennel Proto REPL package I made for Emacs for a better REPL experience.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s look at the REPL code:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:love.event&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fennel&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:lib.fennel&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cont?&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;io.write &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cont?&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;..&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;gt;&amp;gt; &amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;io.flush&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;tostring &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;io.read&lt;/span&gt;)) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\n&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;event-type&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;channel&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;while &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;match &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;channel&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:demand&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:write&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;-&amp;gt; &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;channel&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:demand&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;table.concat &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\t&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;io.stdout&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:write&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\n&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:error&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;-&amp;gt; &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;channel&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:demand&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;io.stderr&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:write&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\n&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;-&amp;gt;&amp;gt; &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;channel&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:demand&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.event.push&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;event-type&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chan&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.thread.newChannel&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;repl&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;coroutine.wrap &lt;/span&gt;#(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fennel.repl&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;$...&lt;/span&gt;))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;repl&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:readChunk&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[{&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;stack-size&lt;/span&gt;}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chan&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:push&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chan&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:push&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;&amp;lt; &lt;/span&gt;0 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;stack-size&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;coroutine.yield&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:onValues&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vals&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chan&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:push&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:write&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chan&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:push&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vals&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:onError&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;errtype&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;err&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chan&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:push&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:err&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chan&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:push&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;err&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:moduleName&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;lib.fennel&amp;#34;&lt;/span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;-&amp;gt; &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.filesystem.read&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;lib/repl.fnl&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (#(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fennel.compile-string&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;$&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.filesystem.newFileData&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;repl&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.thread.newThread&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:start&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:eval&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chan&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.handlers.eval&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;repl&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Simply requiring this file would start a REPL.
You may be confused, about how&amp;rsquo;s it going to work, the &lt;code&gt;while true&lt;/code&gt; may look especially concerning.&lt;/p&gt;
&lt;p&gt;When we require this file, the &lt;code&gt;...&lt;/code&gt; is bound to the module name, so the &lt;code&gt;case&lt;/code&gt; doesn&amp;rsquo;t match, as it expects two values an &lt;code&gt;event-type&lt;/code&gt; and the &lt;code&gt;channel&lt;/code&gt;.
Then we fall into the &lt;code&gt;let&lt;/code&gt; block, which defines the channel &lt;code&gt;chan&lt;/code&gt;, the REPL handler &lt;code&gt;repl&lt;/code&gt;, starts the REPL coroutine, which pushes the &lt;code&gt;:read&lt;/code&gt; message to the channel.
Finally, we load this file again, using &lt;code&gt;love.filesystem.read&lt;/code&gt;, compile it to Lua, and start a new thread with &lt;code&gt;:eval&lt;/code&gt; for the &lt;code&gt;event-type&lt;/code&gt;, and &lt;code&gt;chan&lt;/code&gt; for the &lt;code&gt;channel&lt;/code&gt;.
This makes &lt;code&gt;case&lt;/code&gt; match and starts the &lt;code&gt;while&lt;/code&gt; loop, whose sole purpose is to take values off the &lt;code&gt;channel&lt;/code&gt; and act accordingly.&lt;/p&gt;
&lt;p&gt;Finally, we set the &lt;code&gt;love.handlers.eval&lt;/code&gt; handler, matching our &lt;code&gt;:eval&lt;/code&gt; event type to call the &lt;code&gt;repl&lt;/code&gt; as a callback when the event occurs.
The event occurs only when we get the &lt;code&gt;:read&lt;/code&gt; message from the channel, then we use &lt;code&gt;read&lt;/code&gt; to get data from the &lt;code&gt;stdio&lt;/code&gt;, and we push it back to the &lt;code&gt;eval&lt;/code&gt; handler so the &lt;code&gt;repl&lt;/code&gt; callback can be called.&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s pretty much it!
Now, let&amp;rsquo;s put it to the test!&lt;/p&gt;
&lt;h2 id=&#34;changing-code-at-runtime&#34;&gt;Changing code at runtime&lt;/h2&gt;
&lt;p&gt;Here, I have a simple player controller and a bunch of values that correspond to how the player behaves:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fall-vel&lt;/span&gt; 300)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;jump-vel&lt;/span&gt; -300)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;run-vel&lt;/span&gt; 200)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;player&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;player&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:color&lt;/span&gt; [0.3 0.7 0.3 1]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:xvel&lt;/span&gt; 0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:yvel&lt;/span&gt; 0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:x&lt;/span&gt; 50
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:y&lt;/span&gt; 50
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:flip?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;false&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:width&lt;/span&gt; 16
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:height&lt;/span&gt; 24
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:state&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:idle&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:extra-jump&lt;/span&gt; 10
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:draw&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;p&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; omitted&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     )
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:update&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[{&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;xvel&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;yvel&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;extra-jump&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;flip?&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt; &amp;amp;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;as&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;p&lt;/span&gt;} &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dt&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; omitted&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     )})
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We can try and change the &lt;code&gt;run-vel&lt;/code&gt; and see if it is picked up by the game:&lt;/p&gt;
&lt;p&gt;&lt;video autoplay loop muted&gt;&lt;source src=&#34;https://andreyor.st/2024-09-08-interactive-game-development-with-love/repl-doesnt-work.mp4&#34; type=&#34;video/mp4&#34;&gt;
Your browser does not support the &lt;video&gt; tag&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;Seems it&amp;rsquo;s not.
Perhaps, we need to recompile the game module?&lt;/p&gt;
&lt;p&gt;&lt;video autoplay loop muted&gt;&lt;source src=&#34;https://andreyor.st/2024-09-08-interactive-game-development-with-love/error.mp4&#34; type=&#34;video/mp4&#34;&gt;
Your browser does not support the &lt;video&gt; tag&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;Aw, snap!&lt;/p&gt;
&lt;p&gt;By recompiling the entire module, we undefined some variables, and the game crashed!
By the way, the reason changing the run speed value didn&amp;rsquo;t apply is that we were actually defining a completely new speed value, that is not part of the module we&amp;rsquo;re editing.
That&amp;rsquo;s a quirk of how Lua modules work and how Fennel REPL works.
So let&amp;rsquo;s fix this!&lt;/p&gt;
&lt;h3 id=&#34;modules-and-state&#34;&gt;Modules and state&lt;/h3&gt;
&lt;p&gt;While Lua has some lisp characteristics, it is understandably not an actual lisp.
So, unfortunately, we can&amp;rsquo;t expect the same level of interactivity from it.&lt;/p&gt;
&lt;p&gt;In Lua, a module is an ordinary table.
When you write Lua, you return the value at the bottom of the file, usually a table, or sometimes a function.
Any local variables, defined in that module are locals, stored as closures for the functions that reference them in the exported value.&lt;/p&gt;
&lt;p&gt;Because of that, there&amp;rsquo;s no such thing as &lt;em&gt;entering a module&lt;/em&gt; like in many other lisps.
The REPL has its own kind of module space, where all locals, defined in the REPL are stored.
The same goes for any code that we send to the REPL.
So, while we do have a REPL, we can&amp;rsquo;t enter a specific module and change it partially - the only way to do that is to recompile the module and put the updated version in the &lt;code&gt;package.loaded&lt;/code&gt; table.
Which we can do.&lt;/p&gt;
&lt;p&gt;However, there&amp;rsquo;s another problem lurking around - state.
The video above shows that the error message was:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;./game.fnl:68: attempt to index upvalue &amp;#39;world&amp;#39; (a nil value)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;When we&amp;rsquo;ve recompiled the module, &lt;code&gt;world&lt;/code&gt; became &lt;code&gt;nil&lt;/code&gt;, why?
Well, because &lt;code&gt;world&lt;/code&gt; is defined as a &lt;code&gt;nil&lt;/code&gt;, and later set in the &lt;code&gt;love.load&lt;/code&gt; function:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;var &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;world&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; ---- 8&amp;lt; ----&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.load&lt;/span&gt; []
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;world&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bump.newWorld&lt;/span&gt; 64))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;each &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;wall&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;pairs &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;level&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;world&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:add&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;wall&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;wall.x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;wall.y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;wall.width&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;wall.height&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;world&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:add&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;player&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;player.x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;player.y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;player.width&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;player.height&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;However, the &lt;code&gt;love.load&lt;/code&gt; runs only when the game starts, and hence after recompiling the module, &lt;code&gt;world&lt;/code&gt; becomes &lt;code&gt;nil&lt;/code&gt; again, and our game doesn&amp;rsquo;t really expect that.
The same would happen to any other state we&amp;rsquo;re setting up when the game loads.&lt;/p&gt;
&lt;p&gt;Unfortunately, Fennel doesn&amp;rsquo;t have a &lt;code&gt;defonce&lt;/code&gt; or anything like it.
The &lt;code&gt;defonce&lt;/code&gt; macro is available in many lisps, and its purpose is to ensure that when we&amp;rsquo;re redefining something in the REPL or re-evaluating the whole module/namespace/package (whatever you guys call it) the value doesn&amp;rsquo;t get redefined.
Fennel lacks this because there&amp;rsquo;s no way of doing this in Lua, because of how locals are stored (as closed variables).&lt;/p&gt;
&lt;p&gt;But there&amp;rsquo;s a way around this, we can move the definitions to another module, and use &lt;code&gt;require&lt;/code&gt; to load them.
In Lua &lt;code&gt;require&lt;/code&gt; caches everything it loads, so when we run &lt;code&gt;require&lt;/code&gt; again, it doesn&amp;rsquo;t really do anything except get the value from the &lt;code&gt;package.loaded&lt;/code&gt; table.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s how we can define the &lt;code&gt;world&lt;/code&gt; module:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bump&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:lib.bump&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bump.newWorld&lt;/span&gt; 64)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;src-block-caption&#34;&gt;
  &lt;span class=&#34;src-block-number&#34;&gt;Code Snippet 1:&lt;/span&gt;
  &lt;code&gt;state/world.fnl&lt;/code&gt;
&lt;/div&gt;
&lt;p&gt;That&amp;rsquo;s it.
Now, we can bring it to the main game module using &lt;code&gt;require&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;world&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:state.world&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This way, when we recompile the module, we get the same &lt;code&gt;world&lt;/code&gt; as before, unless we were to recompile the &lt;code&gt;world&lt;/code&gt; module.&lt;/p&gt;
&lt;p&gt;I moved most of the game state in such modules, and now we can use our REPL.&lt;/p&gt;
&lt;h2 id=&#34;using-the-repl&#34;&gt;Using the REPL&lt;/h2&gt;
&lt;p&gt;Here&amp;rsquo;s an example of tweaking the player&amp;rsquo;s motion speed again:&lt;/p&gt;
&lt;p&gt;&lt;video autoplay loop muted&gt;&lt;source src=&#34;https://andreyor.st/2024-09-08-interactive-game-development-with-love/repl-work.webm&#34; type=&#34;video/webm&#34;&gt;
Your browser does not support the &lt;video&gt; tag&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m sending the code to the REPL, instead of reloading the module, just because it&amp;rsquo;s a bit more convenient.
This way tweaking the game is much nicer and frictionless, although it doesn&amp;rsquo;t reach the same heights as that one video from &lt;a href=&#34;https://www.youtube.com/watch?v=EGqwXt90ZqA&#34; target=&#34;_blank&#34;&gt;Bret Victor&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s me using a REPL to make an ad-hoc level editor:&lt;/p&gt;
&lt;p&gt;&lt;video autoplay loop muted&gt;&lt;source src=&#34;https://andreyor.st/2024-09-08-interactive-game-development-with-love/level-editor.webm&#34; type=&#34;video/webm&#34;&gt;
Your browser does not support the &lt;video&gt; tag&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;Unfortunately, there&amp;rsquo;s no way of using the REPL on Android, since there&amp;rsquo;s no way of running LÖVE from the same environment as Emacs, without installing X11 and running everything through Termux.
Probably doable, but I don&amp;rsquo;t want to go this route.
Android development is more backup route anyway, since I have access to my PC again.&lt;/p&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: Interactive game development with LÖVE&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Sun, 08 Sep 2024 21:00:00 +0300</pubDate>
    </item><item>
      <title>Boredom and gamedev</title>
      <link>https://andreyor.st/posts/2024-09-08-boredom-and-gamedev/</link>
      <guid>https://andreyor.st/posts/2024-09-08-boredom-and-gamedev/</guid>
      <description>&lt;p&gt;I spent the previous ten days on vacation.
Usually, I try to go off once or twice a year to somewhere where I can just passively relax - usually, it is some sea resort.
This year I decided to go to the Republic of Türkiye and spend my time at the beach without any major attractions.
The problem is - I get bored pretty quickly and my brain wants to do something.&lt;/p&gt;
&lt;p&gt;I took with me my trusty Nintendo 2DS in case I have an urge to spend some time looking at the screen and to get myself occupied on the plane, and a phone with some books to read while I&amp;rsquo;m lying on the beach.
However, my phone is also my computer, and I do a lot of coding on it in my spare time, usually when I don&amp;rsquo;t have access to a proper PC.&lt;/p&gt;
&lt;p&gt;The last time I went on such a vacation I got so bored, that I decided that I wanted to do some game dev, and started a &lt;a href=&#34;https://andreyor.st/posts/2023-06-09-gamedev-plans/&#34;&gt;personal game dev marathon&lt;/a&gt;.
Originally, I planned to start once I got back from vacation, but I was so eager that I &lt;a href=&#34;https://andreyor.st/posts/2023-06-30-game1/&#34;&gt;started early&lt;/a&gt;, while I was still at the beach.
The marathon was a crunch, and I had mixed feelings about it in the end, which ultimately led to burnout, and I put the idea of making games on the shelf for a while.
And while the last time I started doing this I only drew some sprites, the only reason for that was that I couldn&amp;rsquo;t get any game engine on my phone.
This time around, I got so bored that I started programming a game while gradually getting sunburns and taking breaks to go and actually swim in the sea.&lt;/p&gt;
&lt;h2 id=&#34;making-games-on-android&#34;&gt;Making games on Android&lt;/h2&gt;
&lt;p&gt;Basically, if the only thing you have is a phone you have two main options - &lt;a href=&#34;https://tic80.com/&#34; target=&#34;_blank&#34;&gt;TIC-80&lt;/a&gt; and &lt;a href=&#34;https://love2d.org/&#34; target=&#34;_blank&#34;&gt;löve2d&lt;/a&gt;.
tic has everything you need - an integrated code editor, a sprite editor, a map editor, and even a sound editor if you&amp;rsquo;re that versatile.
however, the experience of using TIC for doing everything is not great, especially on the phone.
I mean, that&amp;rsquo;s what you have to deal with:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2024-09-08-boredom-and-gamedev/TIC-80.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;Not a lot of screen space to view the code, the keyboard is abysmal, and the editor experience itself has a lot to be desired.
Yes, it is authentic, I get it, it&amp;rsquo;s just not what I&amp;rsquo;m personally after.&lt;/p&gt;
&lt;p&gt;On PC you can actually get a PRO version of TIC-80, which allows you to write a game in an external editor, and load it into the engine.
Technically, you could do the same on Android, but there&amp;rsquo;s a problem - I use Android 14, which has storage restrictions for apps.
And TIC-80 can&amp;rsquo;t access anything except files in its directory stored at &lt;code&gt;/sdcard/Android/data/com.nesbox.tic80/&lt;/code&gt;.
Which can&amp;rsquo;t be accessed directly on the phone either - you need a PC to access it.
So even if you have a separate text editor, you can&amp;rsquo;t do your game development with TIC on Android.
Moreover, you can&amp;rsquo;t even get your game out of the engine unless you have a PC at hand.&lt;/p&gt;
&lt;p&gt;The other option, as I said, is LÖVE2D.
It has the same problem as TIC, as you can&amp;rsquo;t launch the game from anywhere but &lt;code&gt;/sdcard/Android/data/org.love2d.android/&lt;/code&gt;, however, newer versions have a separate dedicated launcher, that can load &lt;code&gt;.love&lt;/code&gt; files from anywhere on the filesystem, which is good enough.
Alternatively, an older version, like 11.3 can be installed that bypasses the sandboxing restrictions.
So that was the route I took.&lt;/p&gt;
&lt;h3 id=&#34;making-games-on-android-with-löve&#34;&gt;Making games on Android with LÖVE&lt;/h3&gt;
&lt;p&gt;I have little experience with LÖVE2D.
Previously, I did a bunch of tests with it and made a few demos like the one described in my &lt;a href=&#34;https://andreyor.st/posts/2020-10-15-raymarching-with-fennel-and-love/&#34;&gt;raymarching post&lt;/a&gt;, or the &lt;a href=&#34;https://gitlab.com/andreyorst/love-fabrik&#34; target=&#34;_blank&#34;&gt;F.A.B.R.I.K.&lt;/a&gt; algorithm I implemented back in the day.
So nothing major.
The raymarching demo barely runs on a PC, and there&amp;rsquo;s no way to control it on the phone without connecting a gamepad.
Unfortunately, I had no gamepad with me this time, so if I wanted to make a game on the phone I had to implement one myself.
Fortunately, I have a lot of experience playing games with the on-screen gamepad, so I&amp;rsquo;m at least well accustomed to the idea.&lt;/p&gt;
&lt;p&gt;I had no idea how to interact with the touch screen though, so I found a drop-in gamepad implementation for LÖVE2D in the &lt;a href=&#34;https://github.com/DeybisMelendez/game-tools/blob/90690b864e3d3b0ffeec66d04c1956198e383abf/lovepad.lua&#34; target=&#34;_blank&#34;&gt;game-tools repository&lt;/a&gt;:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2024-09-08-boredom-and-gamedev/lovepad.png&#34;
         alt=&#34;Figure 1: lovepad.lua&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 1: &lt;/span&gt;&lt;code&gt;lovepad.lua&lt;/code&gt;&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Still, I wanted this gamepad to be a bit more advanced, with analog stick imitation, and more buttons, so I ported it to Fennel first and then extended it with more features:&lt;/p&gt;
&lt;p&gt;&lt;video autoplay loop muted class=&#34;uninvertable&#34;&gt;&lt;source src=&#34;https://andreyor.st/2024-09-08-boredom-and-gamedev/gamepad.mp4&#34; type=&#34;video/mp4&#34;&gt;
&lt;img src=&#34;https://andreyor.st/2024-09-08-boredom-and-gamedev/gamepad.png&#34; title=&#34;Your browser does not support the &lt;video&gt; tag&#34;/&gt;&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;It has all of the buttons of a modern controller, so I could share the control scheme between the on-screen gamepad and a real gamepad.
I do understand that the on-screen gamepad should, ideally, be tailored around a game, but this will suffice for now.
It was fun to implement this too, and I found a small bug in the &lt;code&gt;lovepad.lua&lt;/code&gt; file, while I was porting it.&lt;/p&gt;
&lt;p&gt;Next, I added the &lt;a href=&#34;https://github.com/kikito/bump.lua&#34; target=&#34;_blank&#34;&gt;bump.lua&lt;/a&gt; library for basic physics (because I don&amp;rsquo;t want to deal with box2d yet), and made a simple player controller:&lt;/p&gt;
&lt;figure class=&#34;uninvertable&#34;&gt;&lt;img src=&#34;https://andreyor.st/2024-09-08-boredom-and-gamedev/player-controller.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;As you can see, I&amp;rsquo;m using Emacs on the phone, with the Google Keyboard set to PC QWERTY layout - a neat feature.
This is my phone setup for programming, and I&amp;rsquo;m actually using the same configuration as on my regular PC.&lt;/p&gt;
&lt;p&gt;After adding a &lt;a href=&#34;https://github.com/kikito/gamera&#34; target=&#34;_blank&#34;&gt;camera library&lt;/a&gt; from the author of &lt;code&gt;bump.lua&lt;/code&gt;, here&amp;rsquo;s what the player controller looks like at the moment:&lt;/p&gt;
&lt;p&gt;&lt;video autoplay loop muted class=&#34;uninvertable&#34;&gt;&lt;source src=&#34;https://andreyor.st/2024-09-08-boredom-and-gamedev/player-controller.mp4&#34; type=&#34;video/mp4&#34;&gt;
Your browser does not support the &lt;video&gt; tag&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;I want to tweak this player-controller a bit further, making it more fleshed out, but as you can see it already handles a few things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Direction facing is tracked based on horizontal velocity&lt;/li&gt;
&lt;li&gt;Jumping
&lt;ul&gt;
&lt;li&gt;Holding the jump button longer increases the jump height&lt;/li&gt;
&lt;li&gt;Bumping against a ceiling resets the vertical velocity&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Crouching and crawling
&lt;ul&gt;
&lt;li&gt;When crouched, the player&amp;rsquo;s height is reduced, and when crawling the width is increased&lt;/li&gt;
&lt;li&gt;When crawling into a narrow space, the player changes to the crouched state if no direction input is given.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;The camera follows the player
&lt;ul&gt;
&lt;li&gt;Camera pans in the direction of movement, showing more of the upcoming level&lt;/li&gt;
&lt;li&gt;Vertical position only changes when the player is grounded, or when the vertical position is lower than the original camera position&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I still need to tweak various speed values and add more movement options like dashing, sliding, etc., but it already feels &lt;em&gt;gameish&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Writing a player controller was the most challenging thing before when I &lt;a href=&#34;https://andreyor.st/posts/2023-07-17-game1-w34/&#34;&gt;made the first demo game&lt;/a&gt; in the marathon.
I made this one similar to the previous one, as can be seen in &lt;a href=&#34;http://andreyor.st/posts/2023-07-22-game1-w34-again/%20&#34; target=&#34;_blank&#34;&gt;further GAME1 demos&lt;/a&gt;, but it&amp;rsquo;s a complete rewrite, as I wanted to make it differently this time.
We&amp;rsquo;ll see how it evolves over time.&lt;/p&gt;
&lt;h3 id=&#34;drawing&#34;&gt;Drawing&lt;/h3&gt;
&lt;p&gt;While I didn&amp;rsquo;t draw anything for this game, I have a few updates on how I approach drawing on the phone.
In short, I ditched the &lt;a href=&#34;https://play.google.com/store/apps/details?id=com.PixelStudio&#34; target=&#34;_blank&#34;&gt;PixelStudio&lt;/a&gt; I&amp;rsquo;ve talked about in the &lt;a href=&#34;https://andreyor.st/posts/2023-06-30-game1/&#34;&gt;first post&lt;/a&gt; about GAME1 mainly because its UX doesn&amp;rsquo;t work for me personally.
It&amp;rsquo;s still a good app for pixel art, I just don&amp;rsquo;t like how it works, and it lacks some features I&amp;rsquo;d like to have.&lt;/p&gt;
&lt;p&gt;Fortunately, there exists a better option - &lt;a href=&#34;https://krita.org/en/&#34; target=&#34;_blank&#34;&gt;Krita&lt;/a&gt; which has a &lt;a href=&#34;https://play.google.com/store/apps/details?id=org.krita&amp;amp;hl=en_US&#34; target=&#34;_blank&#34;&gt;port for Android&lt;/a&gt; that doesn&amp;rsquo;t compromise any features, so you get a full Krita experience.
It&amp;rsquo;s probably better suited for Android tablets, but works well enough for me on the phone.
I&amp;rsquo;m slowly learning pixel art, and here&amp;rsquo;s a timelapse of me drawing a tree on my phone:&lt;/p&gt;
&lt;p&gt;&lt;video autoplay loop muted width=&#34;50%&#34;&gt;&lt;source src=&#34;https://andreyor.st/2024-09-08-boredom-and-gamedev/krita.mp4&#34; type=&#34;video/mp4&#34;&gt;
Your browser does not support the &lt;video&gt; tag&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;I made a few mistakes when using various tools, as I was not well accustomed to Krita&amp;rsquo;s toolset back then.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s the final result after a bit of refinement:&lt;/p&gt;
&lt;figure class=&#34;pixelart&#34;&gt;&lt;img src=&#34;https://andreyor.st/2024-09-08-boredom-and-gamedev/pixelart.png&#34; width=&#34;100%&#34; height=&#34;auto&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;This isn&amp;rsquo;t a drawing for the game I&amp;rsquo;m making, just a sketch, following the principles outlined in this &lt;a href=&#34;https://www.youtube.com/watch?v=uFnL5X_GrmE&#34; target=&#34;_blank&#34;&gt;amazing video&lt;/a&gt; by Brandon James Greer.
But one thing that makes a difference when making games for LÖVE2D and not for TIC-80 is the unrestricted palette.
It&amp;rsquo;s still better to restrict the palette when making pixel art, but using only 16 colors for the entirety of game graphics is too restrictive for me.
Especially right now.&lt;/p&gt;
&lt;p&gt;One thing I haven&amp;rsquo;t tried yet is animating.
PixelStudio had a decent animation pipeline, and it was possible to export the animation as a sprite-sheet.
Still need to experience this in Krita - I know it has animation capabilities, but I&amp;rsquo;m not sure if they&amp;rsquo;ll be comfortable to use on the phone or not.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ll be making more pixel art for this game I&amp;rsquo;m making in the future, so I&amp;rsquo;ll post actual images once I have anything more to share!&lt;/p&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: Boredom and gamedev&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Sun, 08 Sep 2024 00:34:00 +0300</pubDate>
    </item><item>
      <title>fnl-http - testing with fennel-test</title>
      <link>https://andreyor.st/posts/2024-08-15-fnl-http-testing-with-fennel-test/</link>
      <guid>https://andreyor.st/posts/2024-08-15-fnl-http-testing-with-fennel-test/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://gitlab.com/andreyorst/fnl-http&#34; target=&#34;_blank&#34;&gt;fnl-http&lt;/a&gt; is my current passion project - I spend a lot of free time tinkering with it, and the last week was spent on testing and fixing bugs.&lt;/p&gt;
&lt;p&gt;As you may know, I made a testing framework, called &lt;a href=&#34;https://gitlab.com/andreyorst/fennel-test&#34; target=&#34;_blank&#34;&gt;fennel-test&lt;/a&gt;, which has a dedicated test runner, and a set of macros for writing tests.
I use it in all of my projects, and oftentimes, some project requires more features that are currently available in the framework, so I extend it as needed.
I think it&amp;rsquo;s a great way of designing something - you use it, and enhance it as you encounter new needs.&lt;/p&gt;
&lt;p&gt;I want programming to be exciting, so I spent a lot of time making my test report nice to look at.
Here&amp;rsquo;s how the report looks by default:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Test run at Tue Aug  6 23:20:41 2024, seed: 1722975641242
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(....)(......)(.)(.....)(.)(........)(...)(...)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The default reporter is called &lt;code&gt;dots&lt;/code&gt;.
Each test namespace is encoded with parentheses &lt;code&gt;()&lt;/code&gt;, each successful test is encoded as a dot &lt;code&gt;.&lt;/code&gt;, and failed tests are encoded as &lt;code&gt;F&lt;/code&gt;.
The runner randomizes the order of tests each time, so if we run it again, the result would be different:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Test run at Tue Aug  6 23:24:10 2024, seed: 1722975850235
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(......)(........)(.)(...)(...)(....)(.....)(.)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;However, this is all you get with a reporter like this.
If a test fails, information about the error is printed after all tests have finished, so you know what test did fail.&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s another inbuilt reporter, called &lt;code&gt;namespaces&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Test run at Tue Aug  6 23:27:33 2024, seed: 1722976053226
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;test.http-parser-test: PASS
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;test.client-test: PASS
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;test.json-test: PASS
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;test.httpbin-test: PASS
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;test.body-test: PASS
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;test.headers-test: PASS
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;test.readers-test: PASS
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;test.url-test: PASS
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As you can see, it prints each namespace that is currently being tested, followed by the namespace-wide status.
If a test fails, you again see its error message, but only after all tests have finished, which isn&amp;rsquo;t ideal because tests in the &lt;code&gt;fnl-http&lt;/code&gt; project take about two minutes to complete.&lt;/p&gt;
&lt;p&gt;Fortunately enough, you can create reporters in the &lt;code&gt;.fennel-test&lt;/code&gt; configuration file!&lt;/p&gt;
&lt;h2 id=&#34;reporters&#34;&gt;Reporters&lt;/h2&gt;
&lt;p&gt;A reporter is just a table with a set of functions.
Each one is called when the respecting stage of testing is being run.
The methods are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;ns-start&lt;/code&gt; - called when entering a new test namespace.&lt;/p&gt;
&lt;p&gt;Used to print the information about the namespace, such as its name.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;ns-report&lt;/code&gt; - called when exiting a test namespace.&lt;/p&gt;
&lt;p&gt;Used to print the overall status of the namespace.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;test-start&lt;/code&gt; - called when running a single test from a namespace.&lt;/p&gt;
&lt;p&gt;Used to print the information about the test, such as the test&amp;rsquo;s name.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;test-report&lt;/code&gt; - called after the test is finished.&lt;/p&gt;
&lt;p&gt;Used to print the status of the test.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;stats-report&lt;/code&gt; - called after running all tests in all namespaces.&lt;/p&gt;
&lt;p&gt;Used to print overall statistics of tests - how many tests were executed, how many errors were encountered, were there any warnings, etc.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This was enough for me to implement other kind of reporters, like the one in the &lt;a href=&#34;https://gitlab.com/andreyorst/fennel-test#custom-reporters&#34; target=&#34;_blank&#34;&gt;project&amp;rsquo;s readme&lt;/a&gt;.
However, I wanted a bit more for this project - first, I wanted the report to be fun to look at, and second, I wanted some statistics.
And third, actually, I noticed the need to skip tests in case something is not available on the machine.&lt;/p&gt;
&lt;p&gt;After a bit of work, here&amp;rsquo;s what I&amp;rsquo;ve got:&lt;/p&gt;
&lt;figure class=&#34;invertable&#34;&gt;&lt;img src=&#34;https://andreyor.st/2024-08-15-fnl-http-testing-with-fennel-test/new-reporter.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;With this reporter, if a specific test fails, I can immediately see it, without waiting for all tests to pass.
In the end, you can see some statistics on the longest tests, and average test time of the namespace.
For example, the &lt;code&gt;test.httpbin-test&lt;/code&gt; namespace took 90 seconds to complete, but on average each test only takes 11 seconds.
I&amp;rsquo;m not entirely sure why this metric would be necessary, but I&amp;rsquo;ve seen it in another test runner, so I implemented it in my reporter.&lt;/p&gt;
&lt;p&gt;Now, here&amp;rsquo;s a problem - one of the tests takes a whopping 90 seconds.
I don&amp;rsquo;t want to run this test all the time, especially, when I&amp;rsquo;m fixing a bug found by some other test.
So I introduced a &lt;code&gt;skip-test&lt;/code&gt; function as a first step.&lt;/p&gt;
&lt;p&gt;Originally, this function had two modes - terminating and non-terminating, but I later removed the second mode.
The reason for that is the &lt;code&gt;with-open&lt;/code&gt; macro.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s an example of one of the fixtures I use in the &lt;code&gt;fnl-http&lt;/code&gt; project:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;use-fixtures&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:once&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   (&lt;span style=&#34;font-weight:bold&#34;&gt;with-open &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proc&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;io.popen &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;podman run  -p &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;port&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;:80 kennethreitz/httpbin &amp;gt;/dev/null 2&amp;gt;&amp;amp;1 &amp;amp; echo $!&amp;#34;&lt;/span&gt;))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pid&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proc&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:*l&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;attempts&lt;/span&gt; 10]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;wait-for-server&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;attempts&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;font-weight:bold&#34;&gt;do &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;kill&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pid&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;font-weight:bold&#34;&gt;do &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;kill&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pid&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;skip-test&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;coudln&amp;#39;t connect to httpbin server after &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;attempts&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; attempts&amp;#34;&lt;/span&gt;))))))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;with-open&lt;/code&gt; macro ensures that the resource is closed no matter what.
Closing the process, however, doesn&amp;rsquo;t kill the program running in the background, so I had to get its PID with sketchy &lt;code&gt;echo $!&lt;/code&gt; part and kill it later.
Killing the process doesn&amp;rsquo;t release the file descriptor created by &lt;code&gt;popen&lt;/code&gt;, so &lt;code&gt;with-open&lt;/code&gt; is only responsible for releasing the file handle here.&lt;/p&gt;
&lt;h3 id=&#34;a-sudden-bug&#34;&gt;A sudden bug&lt;/h3&gt;
&lt;p&gt;What &lt;code&gt;with-open&lt;/code&gt; also does is catching, and re-throwing errors.
It&amp;rsquo;s something akin to trying with resources in Java, and other languages that support this kind of abstraction.
You can think about it as &lt;code&gt;try&lt;/code&gt;/&lt;code&gt;finally&lt;/code&gt; without the &lt;code&gt;catch&lt;/code&gt; part.&lt;/p&gt;
&lt;p&gt;Lua, however, doesn&amp;rsquo;t really have well-defined exceptions.
Instead, functions usually throw string messages about the error and that&amp;rsquo;s it.
Sometimes, however, it&amp;rsquo;s useful to throw a table instead.
Tables are like objects, so you can embed some additional information in those, making it easier to match a particular error.
It&amp;rsquo;s better to convert this table to a string if it ever reaches the user uncaught though.&lt;/p&gt;
&lt;p&gt;What makes things harder is that in Lua it&amp;rsquo;s not possible to re-throw an error without losing its previous stack trace.
While it is a common practice to use &lt;code&gt;pcall&lt;/code&gt; to catch any errors and to re-throw them if you can&amp;rsquo;t do anything about the error, this is what causes losing the precious stack trace.
More precisely, if the error message comes with the stack trace, and you would just re-throw it with &lt;code&gt;error&lt;/code&gt;, you wouldn&amp;rsquo;t add your stack trace to the trace.
Sounds convoluted, yeah?&lt;/p&gt;
&lt;p&gt;So Lua gives you another option: &lt;code&gt;xpcall&lt;/code&gt;.
The &lt;a href=&#34;https://www.lua.org/manual/5.4/manual.html#pdf-xpcall&#34; target=&#34;_blank&#34;&gt;Lua manual&lt;/a&gt; doesn&amp;rsquo;t have a thorough explanation of it though:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;xpcall (f, msgh [, arg1, ···])&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;This function is similar to &lt;code&gt;pcall&lt;/code&gt;, except that it sets a new message handler &lt;code&gt;msgh&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It works the same as &lt;code&gt;pcall&lt;/code&gt;, except, it accepts an additional argument - a function that would append a stack trace to the error.
Usually it&amp;rsquo;s the &lt;code&gt;debug.traceback&lt;/code&gt; &lt;a href=&#34;https://www.lua.org/manual/5.4/manual.html#pdf-debug.traceback&#34; target=&#34;_blank&#34;&gt;function&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;debug.traceback ([thread,] [message [, level]])&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;If message is present but is neither a string nor &lt;strong&gt;nil&lt;/strong&gt;, this function returns message without further processing.
Otherwise, it returns a string with a traceback of the call stack.
The optional message string is appended at the beginning of the traceback.
An optional &lt;code&gt;level&lt;/code&gt; number tells at which level to start the traceback (default is 1, the function calling &lt;code&gt;traceback&lt;/code&gt;).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Knowing all that, let&amp;rsquo;s look at how I&amp;rsquo;ve implemented the &lt;code&gt;skip-test&lt;/code&gt; function:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Skip&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;setmetatable&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   {}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:__tostring&lt;/span&gt; #&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Skip&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:__fennelview&lt;/span&gt; #&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Skip&lt;/span&gt;}))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;skip-test&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;reason&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Calling this function inside a test or a fixture will stop the test
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;early and mark it as skipped. The optional `reason` argument is a
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;message to display in the log if the reporter is configured to do so.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;error &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Skip&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;reason&lt;/span&gt;]))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Right, &lt;code&gt;skip-test&lt;/code&gt; throws an array with a special table object, defined as a singleton, so the test runner could distinguish between ordinary test errors and skipped tests.
In theory, everything should have worked, but for some reason, some of the tests were skipped correctly, but others didn&amp;rsquo;t.&lt;/p&gt;
&lt;p&gt;The culprit?
It&amp;rsquo;s &lt;code&gt;with-open&lt;/code&gt;, obviously, otherwise, why would I take such a tangent about it?&lt;/p&gt;
&lt;p&gt;Internally, &lt;code&gt;with-open&lt;/code&gt; uses the &lt;code&gt;xpcall&lt;/code&gt; function to do its job.
And theoretically, it should work just fine, however, it doesn&amp;rsquo;t use &lt;code&gt;debug.traceback&lt;/code&gt; if Fennel&amp;rsquo;s own &lt;code&gt;compiler.traceback&lt;/code&gt; is available.&lt;/p&gt;
&lt;p&gt;Originally, I thought that&amp;rsquo;s just how it is, and implemented two modes in &lt;code&gt;skip-test&lt;/code&gt;.
After a bit of digging and consulting the manual, I found out that &lt;code&gt;compiler.traceback&lt;/code&gt; mistakenly converted &lt;strong&gt;every&lt;/strong&gt; message to a string.
&lt;a href=&#34;https://lists.sr.ht/~technomancy/fennel/patches/54416&#34; target=&#34;_blank&#34;&gt;Fixing that&lt;/a&gt; made the &lt;code&gt;skip-test&lt;/code&gt; function work in all cases.&lt;/p&gt;
&lt;h3 id=&#34;another-sudden-bug&#34;&gt;Another sudden bug!&lt;/h3&gt;
&lt;p&gt;After the patch landed, and I updated Fennel to the newest commit, something else broke.
Now, the JSON parsing test no longer succeeded, complaining that some number has no integer representation.
The number in question is &lt;code&gt;23456789012000000000000000000000000000000000000000000000000000000000000000000&lt;/code&gt; or, as it is written in the JSON test file that I use, &lt;code&gt;2.3456789012e+76&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Before the update, everything worked fine, so I started digging again.
Turns out, recently, the way numbers are compiled by Fennel has changed:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-diff&#34; data-lang=&#34;diff&#34;&gt;&lt;span style=&#34;font-weight:bold;display:flex;&#34;&gt;&lt;span&gt;@@ -534,8 +534,9 @@ (fn compile-sym
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;color:gray;display:flex;&#34;&gt;&lt;span&gt; ;; We do gsub transformation because some locales use , for
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;color:gray;display:flex;&#34;&gt;&lt;span&gt; ;; decimal separators, which will not be accepted by Lua.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;color:gray;display:flex;&#34;&gt;&lt;span&gt; (fn serialize-number [n]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;diff-removed&#34; style=&#34;display:flex;&#34;&gt;&lt;span&gt;-  (pick-values 1 (-&amp;gt; (tostring n)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;diff-removed&#34; style=&#34;display:flex;&#34;&gt;&lt;span&gt;-                     (string.gsub &#34;,&#34; &#34;.&#34;))))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;diff-added&#34; style=&#34;display:flex;&#34;&gt;&lt;span&gt;+  (if (= (math.floor n) n)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;diff-added&#34; style=&#34;display:flex;&#34;&gt;&lt;span&gt;+      (string.format &#34;%d&#34; n)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;diff-added&#34; style=&#34;display:flex;&#34;&gt;&lt;span&gt;+      (string.gsub (tostring n) &#34;,&#34; &#34;.&#34;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And now it is failing, because indeed, you can&amp;rsquo;t convert &lt;code&gt;2.3456789012e+76&lt;/code&gt; to a string using &lt;code&gt;%d&lt;/code&gt;.
Except, you can if you&amp;rsquo;re using LuaJIT - it happily converts this number to &lt;code&gt;&amp;quot;-9223372036854775808&amp;quot;&lt;/code&gt;, which is even worse.&lt;/p&gt;
&lt;p&gt;After a bit of searching, I found that the safest way to format &lt;strong&gt;integers&lt;/strong&gt; as stings is by using &lt;code&gt;&amp;quot;%.f&lt;/code&gt; format specifier.
Strangely enough, the Lua manual doesn&amp;rsquo;t have any information on most number formatting patterns.
A tiny bit of information was found on the lua-users.org &lt;a href=&#34;https://www.lua-users.org/wiki/IntegerDomain&#34; target=&#34;_blank&#34;&gt;page&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;To make sure integer numbers are properly converted into string (without scientific notation), rather than using &lt;code&gt;tostring(x)&lt;/code&gt;, use &lt;code&gt;format.string(&amp;quot;%.0f&amp;quot;,x)&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I don&amp;rsquo;t really get why &lt;code&gt;%.f&lt;/code&gt; would format a number as an integer given that &lt;code&gt;%f&lt;/code&gt; formats floats.
And, even though it works the same way in C, I have never seen this in my life.
But OK, we could just replace &lt;code&gt;%d&lt;/code&gt; with &lt;code&gt;%.f&lt;/code&gt;, and be done with that, however, the number above is then would appear as &lt;code&gt;&amp;quot;23456789012000000697746671432670411048021854502345623879537911769302235611136&amp;quot;&lt;/code&gt;.
I get it, it&amp;rsquo;s a big number, and Lua has limited precision for integers, but the main problem is that this number is much harder to read than its e-notation brother &lt;code&gt;2.3456789012e+76&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;So I settled on finding a way to fix this bug so that both PUC Lua and LuaJIT would format this number in the same way.
The result is a &lt;a href=&#34;https://lists.sr.ht/~technomancy/fennel/patches/54443&#34; target=&#34;_blank&#34;&gt;patch&lt;/a&gt;, that changes the compiler and pretty-printer parts of the language.
The function that does that, looks horrifying:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;serialize-number&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;val&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;= &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;math.floor &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s1&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;string.format &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;%.f&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s1&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;tostring &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;)) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                      (&lt;span style=&#34;font-weight:bold&#34;&gt;or &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;faccumulate&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; 0 99 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:until&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;string.format &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;%.&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;e&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                  &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n*&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;tonumber &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                              (&lt;span style=&#34;font-weight:bold&#34;&gt;when &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n*&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;exp&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:match&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;e%+?(%d+)$&amp;#34;&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                  &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; Lua stops transforming numbers from&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                  &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; e-notation to integers at e+14&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                  (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;and &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;exp&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;&amp;gt; &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;tonumber &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;exp&lt;/span&gt;) 14))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                      &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                      &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s1&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                              &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s1&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;tostring &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold&#34;&gt;pick-values &lt;/span&gt;1 (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;string.gsub &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;val&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;,&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;.&amp;#34;&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We start by checking if &lt;code&gt;(tostring n)&lt;/code&gt; and &lt;code&gt;(string.format &amp;quot;%.f&amp;quot; n)&lt;/code&gt; give the same string.
If they are, we just return the string.
If not, we try the scientific notation for each power from &lt;code&gt;0&lt;/code&gt; to &lt;code&gt;99&lt;/code&gt;.
I probably should&amp;rsquo;ve tested for more powers than that, but it&amp;rsquo;s OK for now.&lt;/p&gt;
&lt;p&gt;We&amp;rsquo;re converting the number to a string using the e-notation and parse it back, comparing it with the original number.
What this does, is that if the power is less than the original, we would lose precision, and comparison would fail.
If we can&amp;rsquo;t find the exponent up to 99, we bail out and return the &lt;code&gt;%.f&lt;/code&gt; representation.
Otherwise, if the numbers match, we check if the exponent is greater than &lt;code&gt;14&lt;/code&gt; as it is the exponent where PUC Lua starts using the e-notation.
Otherwise, we again return the &lt;code&gt;%.f&lt;/code&gt; representation.&lt;/p&gt;
&lt;p&gt;Phew!&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://www.youtube.com/watch?v=aM8YOBvq-jc&#34; target=&#34;_blank&#34;&gt;But I&amp;rsquo;m not done yet!&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s try to compile a really huge number:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; 1&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;e+99999&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;What?&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s do it in an expression then, maybe that&amp;rsquo;s just the pretty printer freaking out:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;1&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;e+309&lt;/span&gt; 1)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;attempt&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;to&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;perform&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;arithmetic&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;on&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;global &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;inf&lt;/span&gt;&amp;#39;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;del&gt;&lt;b&gt;What?&lt;/b&gt;&lt;/del&gt; I, of course, jest, but the reason this happens is pretty peculiar.&lt;/p&gt;
&lt;p&gt;You see - when we do &lt;code&gt;(tostring &amp;quot;%.f&amp;quot; n)&lt;/code&gt; on a huge number like &lt;code&gt;1e+309&lt;/code&gt; it returns the string &lt;code&gt;&amp;quot;inf&amp;quot;&lt;/code&gt;.
The compiler then happily includes it in the output Lua code, which is then run by the Lua VM.
In Lua, however, &lt;code&gt;inf&lt;/code&gt; is not a reserved identifier or a number, so it treats &lt;code&gt;inf&lt;/code&gt; like a variable name.
The &lt;code&gt;inf&lt;/code&gt; variable is unbound, hence the &lt;code&gt;nil&lt;/code&gt; in the first example, and an error in the second.&lt;/p&gt;
&lt;p&gt;So we need to account for that:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;serialize-number&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;val&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;= &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;math.floor &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s1&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;string.format &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;%.f&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s1&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;inf&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;(1/0)&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;; portable inf&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                      (&lt;span style=&#34;font-weight:bold&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s1&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;-inf&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;(-1/0)&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                      (&lt;span style=&#34;font-weight:bold&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s1&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;tostring &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;)) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s1&lt;/span&gt; &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;; no precision loss&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                      (&lt;span style=&#34;font-weight:bold&#34;&gt;or &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;faccumulate&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; 0 308 &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;; beyond 308 every number turns to inf&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                        &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:until&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;string.format &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;%.&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;e&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                              (&lt;span style=&#34;font-weight:bold&#34;&gt;when &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;tonumber &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;exp&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:match&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;e%+?(%d+)$&amp;#34;&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                  &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; Lua keeps numbers in standard notation up to e+14&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                  (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;and &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;exp&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;&amp;gt; &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;tonumber &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;exp&lt;/span&gt;) 14))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                      &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                      &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s1&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                          &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s1&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;tostring &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;pick-values &lt;/span&gt;1 (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;string.gsub &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;val&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;,&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;.&amp;#34;&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I also brought the exponent limit up to the last number representable in this notation without becoming &lt;code&gt;inf&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Now we can go back to testing!&lt;/p&gt;
&lt;h2 id=&#34;counting-skipped-tests-and-assertions&#34;&gt;Counting skipped tests and assertions&lt;/h2&gt;
&lt;p&gt;The other thing I added to &lt;code&gt;fennel-test&lt;/code&gt; was more counters.
Counting skipped tests required some tinkering, like counting tests in the whole namespace if the tests were skipped from the &lt;code&gt;:once&lt;/code&gt; fixture.&lt;/p&gt;
&lt;p&gt;Counting assertions was even harder, because tests in &lt;code&gt;fennel-test&lt;/code&gt; are implemented through macros, and assertions are macros too.
I had to inject some runner state, conditionally, and modify it at runtime from each assertion.
A bit shady but it works.&lt;/p&gt;
&lt;p&gt;What is much more shady is the coverage reports for this project.&lt;/p&gt;
&lt;h2 id=&#34;coverage-report&#34;&gt;Coverage report&lt;/h2&gt;
&lt;p&gt;I have a firm belief that &lt;a href=&#34;https://andreyor.st/posts/2022-03-29-100-is-the-only-acceptable-test-coverage/&#34;&gt;100% is the only acceptable coverage&lt;/a&gt;.
However, and this is a big &lt;span style=&#34;font-size: 1.33em&#34;&gt;however&lt;/span&gt;, it&amp;rsquo;s important that such coverage comes from public API tests only.
Achieving 100% coverage this way means that your program doesn&amp;rsquo;t have any dead code and that your public API test at least touches all of our code at least once.
It doesn&amp;rsquo;t speak about test quality, of course, and it doesn&amp;rsquo;t guarantee that the program is bug-free, but those other points alone make a huge difference.&lt;/p&gt;
&lt;p&gt;Lua has one and only &lt;a href=&#34;https://lunarmodules.github.io/luacov/&#34; target=&#34;_blank&#34;&gt;luacov&lt;/a&gt; that you can use to test your code.
I&amp;rsquo;ve used it in some other Fennel projects in the past, but it comes with some nuances you have to deal with.&lt;/p&gt;
&lt;p&gt;First, luacov itself is imprecise.
In the post about 100% coverage I talk about it in more detail, but basically, I often see situations where the side effects happened, but the coverage report showed code responsible for the side effects as untouched.
Other times, the coverage percentage is bigger than its actual value due to code formatting.&lt;/p&gt;
&lt;p&gt;With the &lt;code&gt;fnl-http&lt;/code&gt; project I hit a different problem.
Two, actually.&lt;/p&gt;
&lt;p&gt;The first one is related to the &lt;code&gt;--correlate&lt;/code&gt; option of the Fennel compiler.
I had an idea, that if I used &lt;code&gt;--correlate&lt;/code&gt; I could substitute Lua sources used to produce the coverage with Fennel sources.
And since the line numbers are matched by specifying the &lt;code&gt;--correlate&lt;/code&gt; option, the coverage report would be so much easier to read.&lt;/p&gt;
&lt;p&gt;Didn&amp;rsquo;t work out.&lt;/p&gt;
&lt;p&gt;Unfortunately, &lt;code&gt;--coverage&lt;/code&gt; is imprecise.
Many parts of Fennel AST don&amp;rsquo;t contain any line information.
Here&amp;rsquo;s an example:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;
&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;1
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;2
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;3
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;4
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;5
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;6
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;{&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:c&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;And here&amp;rsquo;s the corresponding Lua code:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;
&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;1
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;2
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;3
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;4
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;5
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;6
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; _local_1_ = require(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;c&amp;#34;&lt;/span&gt;) &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; a = _local_1_[&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;a&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; b = _local_1_[&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;b&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- empty line&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- empty line&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; {a = a, b = b}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- empty line&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;As you can see, the overall amount of lines is the same, but many lines that are not empty in the Fennel example are empty in Lua.
It&amp;rsquo;s not a problem, as long as you&amp;rsquo;re measuring the coverage and viewing the report with Lua, but if we replace the Lua code with its Fennel counterpart, the report becomes invalid.
I guess, when the report is constructed, luacov checks if the line is empty or not, and if it isn&amp;rsquo;t, and there were no hits registered, it counts it as a miss.
I&amp;rsquo;m using &lt;code&gt;luacov-console&lt;/code&gt; to view the report, maybe it&amp;rsquo;s a bug from there, I don&amp;rsquo;t know.&lt;/p&gt;
&lt;p&gt;The only way to fix this is to write the code accounting for these nuances of &lt;code&gt;--correlate&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;{&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt;                &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;; local _local_1_ = require(&amp;#34;c&amp;#34;) local a = _local_1_[&amp;#34;a&amp;#34;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt;} (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:c&lt;/span&gt;)) &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;; local b = _local_1_[&amp;#34;b&amp;#34;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                           &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;; &amp;lt;empty line&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt;}                  &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;; return {a = a, b = b}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;There are more examples like that in the project&amp;rsquo;s code.&lt;/p&gt;
&lt;p&gt;The other problem is more peculiar.
Luacov uses &lt;code&gt;debug.sethook&lt;/code&gt; to build its report.
And I use the &lt;code&gt;async.fnl&lt;/code&gt; library in this project, which also uses &lt;code&gt;debug.sethook&lt;/code&gt; to schedule tasks.
So every time anything happens asynchronously, and trust me, there&amp;rsquo;s a lot of that in &lt;code&gt;fnl-http&lt;/code&gt;, the Luacov report is no longer properly calculated.&lt;/p&gt;
&lt;p&gt;So, Luacov has a lot of problems, but I understand why it is like that.
You can&amp;rsquo;t really instrument the Lua code in some other way.&lt;/p&gt;
&lt;p&gt;Fennel, on the other hand, isn&amp;rsquo;t like that.
Being a language where everything is an expression, we can probably make some compiler plugin that injects some side-effecting code that writes the report for every expression in the code.
It would be difficult to do with things like tables and destructuring, but it should be doable.
Maybe I&amp;rsquo;ll try to tackle this problem in the future, who knows?&lt;/p&gt;
&lt;p&gt;Anyway, that&amp;rsquo;s all from me for now!
As usual, you can check out the &lt;a href=&#34;https://gitlab.com/andreyorst/fnl-http&#34; target=&#34;_blank&#34;&gt;project&lt;/a&gt;, which contains all of the stuff mentioned above regarding &lt;code&gt;fennel-test&lt;/code&gt; and &lt;code&gt;luacov&lt;/code&gt;.
Thanks for reading!&lt;/p&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: fnl-http - testing with fennel-test&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Thu, 15 Aug 2024 23:01:00 +0300</pubDate>
    </item><item>
      <title>fnl-http Improvements</title>
      <link>https://andreyor.st/posts/2024-08-01-fnl-http-improvements/</link>
      <guid>https://andreyor.st/posts/2024-08-01-fnl-http-improvements/</guid>
      <description>&lt;p&gt;In the &lt;a href=&#34;https://andreyor.st/posts/2024-07-15-asynchronous-http-client-for-fennel/&#34;&gt;last post&lt;/a&gt; two weeks ago I described the process of making an asynchronous HTTP/1.1 client from scratch (minus the socket part).
At the end, I mentioned that there&amp;rsquo;s a lot more to implement:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Now, of course, that&amp;rsquo;s not all that needs to be implemented.
In its current state, this client doesn&amp;rsquo;t support responses that do not specify the Content-Length or produce a response body in chunked encoding.
HTTPS is out of the question for now too.
Most of the code just takes a &amp;ldquo;happy path&amp;rdquo; without much thought given to errors or more complicated scenarios.
But it&amp;rsquo;s fine, I can always make it better down the line.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;HTTPS is still out of the question - to be honest, I don&amp;rsquo;t want to deal with binary protocols that much, and get myself involved with implementing SSL in Lua.
I could, of course use a library, but I feel that Luasocket alone is already big enough dependency.&lt;/p&gt;
&lt;p&gt;So here are improvements so far.&lt;/p&gt;
&lt;h2 id=&#34;chunked-transfer-encoding&#34;&gt;Chunked transfer-encoding&lt;/h2&gt;
&lt;p&gt;As previously mentioned, the client didn&amp;rsquo;t understand chunked responses, so I had to fix it with a chunked body reader:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-chunk-size&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:private&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;true&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; TODO: needs to process chunk extensions&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;case&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:*l&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-chunk-size&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;case&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:match&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;%s*([0-9a-fA-F]+)&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;size&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;tonumber &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;0x&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;size&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;error &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;format&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;line missing chunk size: %q&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chunked-body-reader&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;initial-chunk&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Reads body in chunks, buffering each fully, and requesting the next
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;chunk, once the buffer is empty.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:private&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;true&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;var &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chunk-size&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;initial-chunk&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;var &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;or &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chunk-size&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;var &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;more?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;true&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-more&lt;/span&gt; []
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; TODO: needs to process entity headers after the last chunk.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;when &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;more?&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chunk-size&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-chunk-size&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;&amp;gt; &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chunk-size&lt;/span&gt; 0)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;font-weight:bold&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;or &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chunk-size&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;font-weight:bold&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;more?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;false&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;values &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;&amp;gt; &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chunk-size&lt;/span&gt; 0) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;string-reader&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;make-reader&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read-bytes&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pattern&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;string-reader&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pattern&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;where&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:number&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;type &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                      (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer-content&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pattern&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;len&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer-content&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;length &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer-content&lt;/span&gt;) 0)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-more?&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;&amp;lt; &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;len&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        (&lt;span style=&#34;font-weight:bold&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:sub&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;len&lt;/span&gt; 1)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-more?&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-more&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                              (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer-content&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                  (&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer-content&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;or &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;- &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;len&lt;/span&gt;)) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;- &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;len&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer-content&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;where&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:*l&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:l&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                      (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer-content&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:*l&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-more?&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold&#34;&gt;not &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:find&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\n&amp;#34;&lt;/span&gt;))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        (&lt;span style=&#34;font-weight:bold&#34;&gt;when &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer-content&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                          (&lt;span style=&#34;font-weight:bold&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:sub&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;length &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer-content&lt;/span&gt;) 2))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-more?&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-more&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                              (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer-content&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                  (&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer-content&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;or &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:*l&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:*l&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer-content&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;where&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:*a&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:a&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                      (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer-content&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:*a&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        (&lt;span style=&#34;font-weight:bold&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        (&lt;span style=&#34;font-weight:bold&#34;&gt;while &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-more&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;string-reader&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                          (&lt;span style=&#34;font-weight:bold&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;case&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:*a&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;when &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer-content&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                  &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer-content&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer-content&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                      &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;error &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;tostring &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pattern&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read-line&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;string-reader&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                       &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer-content&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:*l&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                       &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-more?&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;not &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:find&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\n&amp;#34;&lt;/span&gt;))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   (&lt;span style=&#34;font-weight:bold&#34;&gt;when &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer-content&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                     (&lt;span style=&#34;font-weight:bold&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:sub&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;length &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer-content&lt;/span&gt;) 2))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-more?&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                       (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer-content&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                           (&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer-content&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;or &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:*l&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                           (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:*l&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                       &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer-content&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:close&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt;] (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:close&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:peek&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bytes&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;assert &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:number&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;type &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bytes&lt;/span&gt;)) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;expected number of bytes to peek&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;string-reader&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;content&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;or &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bytes&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;len&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;length &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;content&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bytes&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;len&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;content&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-more&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;- &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bytes&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;len&lt;/span&gt;))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                      (&lt;span style=&#34;font-weight:bold&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                      &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer&lt;/span&gt;)))))}))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It&amp;rsquo;s a mess, but it works.
Please, refer to the &lt;a href=&#34;https://andreyor.st/posts/2024-07-15-asynchronous-http-client-for-fennel/#reader&#34;&gt;previous post&lt;/a&gt; for the explanation of what a reader is.&lt;/p&gt;
&lt;p&gt;The main idea here is that, when the chunked transfer encoding is detected, we create a reader with &lt;code&gt;chunked-body-reader&lt;/code&gt; instead of a regular &lt;code&gt;body-reader&lt;/code&gt;, and set up an internal string buffer.
We then process all reading operations in terms of this buffer, until it depletes, or when we request more data than left in the buffer.
After that, we download the next chunk.&lt;/p&gt;
&lt;p&gt;We still get a stream-like behavior out of this, although it has a somewhat big issue - if the server responds with a chunk of enormous size, we can fill up all available memory.
I&amp;rsquo;ve thought of reworking this function to fill the buffer with smaller chunks, but it complicates the code even further, so I decided not to.
For now, at least.&lt;/p&gt;
&lt;p&gt;And this now works both ways!
We can send a chunked body to the server if we&amp;rsquo;ve didn&amp;rsquo;t specify the &lt;code&gt;Content-Length&lt;/code&gt; header, and the body is not a string.
This happens automatically for files, other readers, and channels.
Yes, with this library, you can stream data to a server from a channel:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ch&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chan&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;go&lt;/span&gt; #(&lt;span style=&#34;font-weight:bold&#34;&gt;with-open &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;body&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;io.open &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;some-file&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:r&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         (&lt;span style=&#34;font-weight:bold&#34;&gt;each &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;body&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:lines&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;!&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;timeout&lt;/span&gt; 300))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ch&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\n&amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;close!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ch&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;http.post&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;http://some-server.org&amp;#34;&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:body&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ch&lt;/span&gt;}))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This will stream the file line by line, sending each line every 300 milliseconds.
The server will receive each line as a separate chunk.&lt;/p&gt;
&lt;p&gt;I won&amp;rsquo;t go into much detail on how this is implemented, as I would need to go through &lt;strong&gt;a lot&lt;/strong&gt; of code.&lt;/p&gt;
&lt;h2 id=&#34;multipart-requests&#34;&gt;Multipart requests&lt;/h2&gt;
&lt;p&gt;After I finished with chunked requests, I turned my eyes on &lt;code&gt;multipart/form-data&lt;/code&gt;.
It&amp;rsquo;s an interesting part of HTTP, and after a closer look at it, I realized that email is just a multipart request with weird headers.
I&amp;rsquo;ve been editing emails in Emacs for quite some time but never noticed that the head of the mail is exactly like the head of an HTTP request.
&lt;em&gt;What a revelation!&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;That aside, implementing multipart came with a challenge.
I don&amp;rsquo;t know if it&amp;rsquo;s just me, but I couldn&amp;rsquo;t find anywhere if the total &lt;code&gt;Content-Length&lt;/code&gt; header is &lt;strong&gt;required&lt;/strong&gt; for a multipart request or not.
Logically speaking, since every part is separated by a boundary, a server should be able to read a request&amp;rsquo;s body until the final boundary.
So theoretically, it doesn&amp;rsquo;t have to know the total content length of the request.&lt;/p&gt;
&lt;p&gt;However, I&amp;rsquo;ve been testing my client with the &lt;a href=&#34;http://httpbin.org/&#34; target=&#34;_blank&#34;&gt;httpbin.org&lt;/a&gt; service and, for some reason, it doesn&amp;rsquo;t parse the multipart request unless the &lt;code&gt;Content-Length&lt;/code&gt; header is present.
And it&amp;rsquo;s not just the sum of part lengths, it&amp;rsquo;s also their headers, empty lines that separate the header part from content, and so forth.&lt;/p&gt;
&lt;p&gt;So I had to implement a set of functions to format multipart parts, and count their lengths:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;format-multipart-part&lt;/span&gt; [{&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;filename&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;filename*&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;content&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:length&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;content-length&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;headers&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mime-type&lt;/span&gt;} &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;boundary&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Format a single multipart entry.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;The part starts with the `boundary`, followed by headers, created from
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;`name`, optional `filename` or `filename*` for files, `mime-type`, and
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;`content-length` which is either calculated from `content` or provided
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;explicitly.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;Default headers include `content-disposition`, `content-length`,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;`content-type`, and `content-transfer-encoding`. Provide `headers` for
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;additional or to change the default ones.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:private&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;true&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;content&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;wrap-body&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;content&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;format&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;--%s\r\n%s\r\n&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;boundary&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;headers-&amp;gt;string&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;collect &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;k&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;v&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;pairs &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;headers&lt;/span&gt; {}))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:into&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:content-disposition&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;format&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;form-data; name=%q%s%s&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                                    (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;filename&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                                        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;format&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;; filename=%q&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;filename&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                                        &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                                    (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;filename*&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                                        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;format&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;; filename*=%s&amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;urlencode-string&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;filename*&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                                        &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                       &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:content-length&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:string&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;type &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;content&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                           (&lt;span style=&#34;font-weight:bold&#34;&gt;length &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;content&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                           (&lt;span style=&#34;font-weight:bold&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;content-length&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;content&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:length&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                       &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:content-type&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mime-type&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;guess-content-type&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;content&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                       &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:content-transfer-encoding&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;guess-transfer-encoding&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;content&lt;/span&gt;)}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;k&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;v&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This function just formats a single multipart header, i.e. it doesn&amp;rsquo;t include the content.
The content is streamed later, so we don&amp;rsquo;t need it here.&lt;/p&gt;
&lt;p&gt;But with this function, we can now calculate the total length of our request:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;multipart-content-length&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;multipart&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;boundary&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Calculate the total length of `multipart` body.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;Needs to know the `boundary`.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;accumulate &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;total&lt;/span&gt; 0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:length&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;content-length&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                     &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                     &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;content&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                     &amp;amp;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;as&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;part&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;ipairs &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;multipart&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;content&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;wrap-body&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;content&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;total&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;font-weight:bold&#34;&gt;length &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;format-multipart-part&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;part&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;boundary&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:string&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;type &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;content&lt;/span&gt;)) (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;length &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;content&lt;/span&gt;) 2)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;reader?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;content&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;2 (&lt;span style=&#34;font-weight:bold&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;content-length&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                         (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;content&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:length&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                         (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;error &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;format&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;can&amp;#39;t determine length for multipart content %q&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt;) 2)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                (&lt;span style=&#34;font-weight:bold&#34;&gt;not= &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;content-length&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;content-length&lt;/span&gt; 2)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;error &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;format&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;missing length field on non-string multipart content %q&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt;) 2)))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;font-weight:bold&#34;&gt;length &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;format&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;--%s--\r\n&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;boundary&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This function doesn&amp;rsquo;t construct the whole body either - it only calculates the length based on headers, and the length of content fields that it can reasonably calculate.
There&amp;rsquo;s a small bug in the &lt;code&gt;format-multipart-part&lt;/code&gt; function though.
We can override any header, including &lt;code&gt;content-length&lt;/code&gt;, meaning we can break the request, if we send a string, and provide a different content-length for it either by mistake or deliberately.
This can be fixed, of course, by either not allowing to change content length for strings, or by wrapping string bodies in a string reader.
I&amp;rsquo;ll have to think about what method is better here.&lt;/p&gt;
&lt;p&gt;That aside, we can now stream the multipart request:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;stream-multipart&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dst&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;multipart&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;boundary&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Write `multipart` entries to `dst` separated with the `boundary`.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;each &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; {&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;filename&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;content&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:length&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;content-length&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mime-type&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &amp;amp;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;as&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;part&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;ipairs &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;multipart&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;assert &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;not= &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;content&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Multipart content cannot be nil&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;assert &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Multipart body must contain at least content and name&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;content&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;wrap-body&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;content&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;-&amp;gt;&amp;gt; &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:string&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;type &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;content&lt;/span&gt;)) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;content&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;format-multipart-part&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;part&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;boundary&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dst&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:write&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;when &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;not= &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:string&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;type &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;content&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;stream-body&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dst&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;content&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:content-length&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;content-length&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;content&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:length&lt;/span&gt;))})))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dst&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:write&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\r\n&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dst&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:write&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;format&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;--%s--\r\n&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;boundary&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Again, I&amp;rsquo;m not going to dive too deep here.
If you&amp;rsquo;re interested in the code, you can find and read it &lt;a href=&#34;https://gitlab.com/andreyorst/fnl-http&#34; target=&#34;_blank&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s an example of a multipart request body:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;--a25537b6-51d6-491f-b18b-a33d197ae4c6\r
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Content-Disposition: form-data; name=&amp;#34;json-test&amp;#34;; filename=&amp;#34;test.json&amp;#34;\r
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Content-Length: 1438\r
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Content-Transfer-Encoding: binary\r
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Content-Type: application/octet-stream\r
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;\r
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &amp;#34;JSON Test Pattern pass1&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {&amp;#34;object with 1 member&amp;#34;:[&amp;#34;array with 1 element&amp;#34;]},
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {},
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    [],
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    -42,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    true,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    false,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    null,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &amp;#34;integer&amp;#34;: 1234567890,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &amp;#34;real&amp;#34;: -9876.543210,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &amp;#34;e&amp;#34;: 0.123456789e-12,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &amp;#34;E&amp;#34;: 1.234567890E+34,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &amp;#34;&amp;#34;:  23456789012E66,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &amp;#34;zero&amp;#34;: 0,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &amp;#34;one&amp;#34;: 1,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &amp;#34;space&amp;#34;: &amp;#34; &amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &amp;#34;quote&amp;#34;: &amp;#34;\&amp;#34;&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &amp;#34;backslash&amp;#34;: &amp;#34;\\&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &amp;#34;controls&amp;#34;: &amp;#34;\b\f\n\r\t&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &amp;#34;slash&amp;#34;: &amp;#34;/ &amp;amp; /&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &amp;#34;alpha&amp;#34;: &amp;#34;abcdefghijklmnopqrstuvwyz&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &amp;#34;ALPHA&amp;#34;: &amp;#34;ABCDEFGHIJKLMNOPQRSTUVWYZ&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &amp;#34;digit&amp;#34;: &amp;#34;0123456789&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &amp;#34;0123456789&amp;#34;: &amp;#34;digit&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &amp;#34;special&amp;#34;: &amp;#34;`1~!@#$%^&amp;amp;*()_+-={&amp;#39;:[,]}|;.&amp;lt;/&amp;gt;?&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &amp;#34;hex&amp;#34;: &amp;#34;\u0123\u4567\u89AB\uCDEF\uabcd\uef4A&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &amp;#34;true&amp;#34;: true,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &amp;#34;false&amp;#34;: false,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &amp;#34;null&amp;#34;: null,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &amp;#34;array&amp;#34;:[  ],
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &amp;#34;object&amp;#34;:{  },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &amp;#34;address&amp;#34;: &amp;#34;50 St. James Street&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &amp;#34;url&amp;#34;: &amp;#34;http://www.JSON.org/&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &amp;#34;comment&amp;#34;: &amp;#34;// /* &amp;lt;!-- --&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &amp;#34;# -- --&amp;gt; */&amp;#34;: &amp;#34; &amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &amp;#34; s p a c e d &amp;#34; :[1,2 , 3
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;4 , 5	   ,  		        6           ,7        ],&amp;#34;compact&amp;#34;:[1,2,3,4,5,6,7],
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &amp;#34;jsontext&amp;#34;: &amp;#34;{\&amp;#34;object with 1 member\&amp;#34;:[\&amp;#34;array with 1 element\&amp;#34;]}&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &amp;#34;quotes&amp;#34;: &amp;#34;&amp;amp;#34; \u0022 %22 0x22 034 &amp;amp;#x22;&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &amp;#34;/\\\&amp;#34;\uCAFE\uBABE\uAB98\uFCDE\ubcda\uef4A\b\f\n\r\t`1~!@#$%^&amp;amp;*()_+-=[]{}|;:&amp;#39;,./&amp;lt;&amp;gt;?&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;: &amp;#34;A key can be any string&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    0.5 ,98.6
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;99.44
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;1066,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;1e1,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;0.1e1,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;1e-1,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;1e00,2e+00,2e-00
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;,&amp;#34;rosebud&amp;#34;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;\r
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;--a25537b6-51d6-491f-b18b-a33d197ae4c6\r
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Content-Disposition: form-data; name=&amp;#34;description&amp;#34;\r
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Content-Length: 27\r
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Content-Transfer-Encoding: 8bit\r
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Content-Type: text/plain; charset=UTF-8\r
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;\r
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;a JSON file to test parsers\r
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;--a25537b6-51d6-491f-b18b-a33d197ae4c6--\r
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And here&amp;rsquo;s this request issued with the client library:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;http.post&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;http://httpbin.org/post&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:multipart&lt;/span&gt; [{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;json-test&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:content&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;io.open &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;test/data/valid.json&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:filename&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;test.json&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                           {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;description&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:content&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;a JSON file to test parsers&amp;#34;&lt;/span&gt;}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:as&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:json&lt;/span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:body&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:args&lt;/span&gt; {}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:data&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:files&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:json-test&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;...&amp;#34;&lt;/span&gt;} &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; contents were excluded to save some vertical space&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:form&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:description&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;a JSON file to test parsers&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:headers&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Content-Length&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;1946&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Content-Type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;multipart/form-data; boundary=------------5af9b616-6e9d-4c19-8aa5-cc0c5f52ca11&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Host&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;httpbin.org&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:X-Amzn-Trace-Id&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Root=1-66aad04d-5155e53a4023b5726bdd134e&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:url&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;http://httpbin.org/post&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:headers&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Access-Control-Allow-Credentials&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;true&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Access-Control-Allow-Origin&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;*&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Connection&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;keep-alive&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Content-Length&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;2118&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Content-Type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;application/json&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Date&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Thu, 01 Aug 2024 00:01:18 GMT&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Server&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;gunicorn/19.9.0&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:http-client&lt;/span&gt; #&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;SocketChannel&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x559596d0e200&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:length&lt;/span&gt; 2118
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:protocol-version&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:major&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:minor&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;HTTP&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:reason-phrase&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;OK&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:request-time&lt;/span&gt; 388
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:status&lt;/span&gt; 200}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As you can see, the JSON got into the &lt;code&gt;files&lt;/code&gt; field, and the description into the &lt;code&gt;form&lt;/code&gt; field.&lt;/p&gt;
&lt;h2 id=&#34;redirects-and-query-params&#34;&gt;Redirects and query-params&lt;/h2&gt;
&lt;p&gt;Honestly, implementing redirection was a pain in the butt.
But I&amp;rsquo;m glad that I did!&lt;/p&gt;
&lt;p&gt;First, I now finally understand how redirection works.
Second, I had to do a major code refactoring for it, which made some parts more approachable, and robust.
That was a lot of changes, though.&lt;/p&gt;
&lt;p&gt;Alongside redirects, I improved the URL parser and implemented a query builder, that can merge multiple queries into one.
Here&amp;rsquo;s an example, again with httpbin.org:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;http.get&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;http://httpbin.org/redirect-to?status_code=302&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:query-params&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:url&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;http://httpbin.org/get&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:as&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:json&lt;/span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:body&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:args&lt;/span&gt; {}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:headers&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Host&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;httpbin.org&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:X-Amzn-Trace-Id&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Root=1-66aad21a-4c52d9316b88f5d862a4b535&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:url&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;http://httpbin.org/get&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:headers&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Access-Control-Allow-Credentials&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;true&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Access-Control-Allow-Origin&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;*&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Connection&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;keep-alive&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Content-Length&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;199&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Content-Type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;application/json&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Date&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Thu, 01 Aug 2024 00:08:58 GMT&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Server&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;gunicorn/19.9.0&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:http-client&lt;/span&gt; #&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;SocketChannel&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x559596734da0&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:length&lt;/span&gt; 199
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:protocol-version&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:major&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:minor&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;HTTP&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:reason-phrase&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;OK&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:request-time&lt;/span&gt; 394
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:status&lt;/span&gt; 200}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As can be seen, the query params in the URL string and the &lt;code&gt;query-params&lt;/code&gt; field in the options table were merged.
During the merge, all values are URL-encoded, so you can pass in URLs that are not entirely correct, and it should work.&lt;/p&gt;
&lt;p&gt;Of course, we can change how we deal with redirects, limiting the total amounts of redirects:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;http.get&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;http://httpbin.org/absolute-redirect/4&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:max-redirects&lt;/span&gt; 3
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:as&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:json&lt;/span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;too&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;many&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;redirecs&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Or, we can choose not to follow redirects altogether:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;http.get&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;http://httpbin.org/absolute-redirect/4&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:follow-redirects?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;false&lt;/span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:body&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;lt;!DOCTYPE HTML PUBLIC \&amp;#34;-//W3C//DTD HTML 3.2 Final//EN\&amp;#34;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;lt;title&amp;gt;Redirecting...&amp;lt;/title&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;lt;h1&amp;gt;Redirecting...&amp;lt;/h1&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;lt;p&amp;gt;You should be redirected automatically to target URL: &amp;lt;a href=\&amp;#34;http://httpbin.org/absolute-redirect/3\&amp;#34;&amp;gt;http://httpbin.org/absolute-redirect/3&amp;lt;/a&amp;gt;.  If not click the link.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:headers&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Access-Control-Allow-Credentials&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;true&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Access-Control-Allow-Origin&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;*&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Connection&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;keep-alive&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Content-Length&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;283&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Content-Type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;text/html; charset=utf-8&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Date&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Thu, 01 Aug 2024 00:24:48 GMT&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Location&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;http://httpbin.org/absolute-redirect/3&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Server&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;gunicorn/19.9.0&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:http-client&lt;/span&gt; #&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;SocketChannel&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x5589fcb69530&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:length&lt;/span&gt; 283
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:protocol-version&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:major&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:minor&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;HTTP&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:reason-phrase&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;FOUND&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:request-time&lt;/span&gt; 228
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:status&lt;/span&gt; 302}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;changes-in-the-asynchronous-api&#34;&gt;Changes in the asynchronous API&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;ve decided to make it easier for users of this library to work with the client&amp;rsquo;s asynchronous API, and you should no longer be required to use &lt;code&gt;async.fnl&lt;/code&gt; directly.
Instead, every request function now accepts callbacks for processing responses, and exceptions:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;http.get&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;https://lua-users.org&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:async?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;true&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;on-response&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;resp&lt;/span&gt;] (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;print &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;resp.body&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;on-raise&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;err&lt;/span&gt;] (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;print &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;err.status&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This means, that the only need for &lt;code&gt;async.fnl&lt;/code&gt; is if you need to wait for certain requests to complete.
It also means, that the &lt;code&gt;http.METHOD&lt;/code&gt; functions will no longer return a promise channel, as I promised in the previous post.&lt;/p&gt;
&lt;p&gt;In addition to that, it is now possible to read the response body, returned as a stream on the main thread, even if the request was asynchronous.
This is possible because I&amp;rsquo;ve cheated:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;!?&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;port&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Takes a value from `port`.  Will return `nil` if closed.  Will block,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;if nothing is available and used on the main thread.  Will park if
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;used in the `(go ...)` block.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;main-thread?&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;!!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;port&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;port&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;!?&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;port&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;val&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Puts a `val` into `port`.  `nil` values are not allowed.  Will block,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;if no buffer space or consumer are available and used on the main
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;thread.  Will park if used inside a `(go ...)` block.  Returns `true`
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;unless `port` is already closed.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;main-thread?&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;!!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;port&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;val&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;port&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;val&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now try to do something like that in Clojure!
You can read why this works in my post on &lt;a href=&#34;https://andreyor.st/posts/2023-05-15-clojures-coreasync-port-for-the-fennel-language/&#34;&gt;async.fnl&lt;/a&gt;, or watch my &lt;a href=&#34;https://conf.fennel-lang.org/2023&#34; target=&#34;_blank&#34;&gt;talk at Fennelconf 2023&lt;/a&gt; where I explain this with some more examples.&lt;/p&gt;
&lt;h2 id=&#34;performance-check&#34;&gt;Performance check&lt;/h2&gt;
&lt;p&gt;Since the client got bigger and more complicated, let&amp;rsquo;s check the performance!
In the previous post, the client couldn&amp;rsquo;t accept a &lt;code&gt;chunked&lt;/code&gt; response, but now it can, meaning we can compare it with Luasocket&amp;rsquo;s HTTP client:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lhttp&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:socket.http&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;= &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lhttp.request&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;http://lua-users.org/wiki/FiltersSourcesAndSinks&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;. &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;http.get&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;http://lua-users.org/wiki/FiltersSourcesAndSinks&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:body&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Let&amp;rsquo;s measure the time again:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;time&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;do &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;http.get&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;http://lua-users.org/wiki/FiltersSourcesAndSinks&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Elapsed&lt;/span&gt; 501.31988525391 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ms&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;time&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;do &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lhttp.request&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;http://lua-users.org/wiki/FiltersSourcesAndSinks&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Elapsed&lt;/span&gt; 630.47289848328 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ms&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It&amp;rsquo;s about the same.
However, we can be slightly faster, if the user doesn&amp;rsquo;t need to process the body immediately:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;time&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;do &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;http.get&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;http://lua-users.org/wiki/FiltersSourcesAndSinks&amp;#34;&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:as&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:stream&lt;/span&gt;}) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Elapsed&lt;/span&gt; 317.51012802124 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ms&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Of course, the time is saved by not reading the body of the response, which shows that reading the body alone is about 200ms.
But Luasocket&amp;rsquo;s HTTP client can&amp;rsquo;t do that at all - it always processes the body, even if the generic form is used and a sink is supplied.
That&amp;rsquo;s an advantage, I would say!&lt;/p&gt;
&lt;p&gt;And, thanks to the asynchronous processing of requests, we can actually issue multiple requests at the same time:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n-requests&lt;/span&gt; 10
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ch&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chan&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;print &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;;;; luasocket&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;time&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;start&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;gettime&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold&#34;&gt;for &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n-requests&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; issuing a synchronous request&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lhttp.request&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;http://lua-users.org/wiki/FiltersSourcesAndSinks&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;io.write &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; response processed in &amp;#34;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;- &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;gettime&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;start&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; ms since the first request\n&amp;#34;&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;print &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;;;; fnl-http&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;time&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;start&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;gettime&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold&#34;&gt;for &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n-requests&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; issuing multiple requests. The on-success handler&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; will put the request number into the channel `ch`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; on completion.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;http.get&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;http://lua-users.org/wiki/FiltersSourcesAndSinks&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:async?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;true&lt;/span&gt;} #(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ch&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;- &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;gettime&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;start&lt;/span&gt;)]) #&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold&#34;&gt;for &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n-requests&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; avaiting each response&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ms&lt;/span&gt;] (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;!!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ch&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;io.write &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; response processed in &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ms&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                      &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; ms since the first request\n&amp;#34;&lt;/span&gt;))))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;;; luasocket&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;1 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;response&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;processed&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;in&lt;/span&gt; 0.55836296081543 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ms&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;since&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;the&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;first&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;request&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;2 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;response&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;processed&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;in&lt;/span&gt; 1.0487260818481 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ms&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;since&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;the&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;first&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;request&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;3 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;response&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;processed&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;in&lt;/span&gt; 1.4974920749664 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ms&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;since&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;the&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;first&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;request&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;4 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;response&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;processed&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;in&lt;/span&gt; 1.9714229106903 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ms&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;since&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;the&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;first&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;request&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;5 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;response&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;processed&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;in&lt;/span&gt; 2.4879760742188 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ms&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;since&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;the&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;first&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;request&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;6 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;response&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;processed&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;in&lt;/span&gt; 3.010272026062 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ms&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;since&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;the&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;first&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;request&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;7 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;response&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;processed&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;in&lt;/span&gt; 3.6146268844604 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ms&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;since&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;the&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;first&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;request&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;8 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;response&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;processed&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;in&lt;/span&gt; 4.1402359008789 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ms&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;since&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;the&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;first&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;request&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;9 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;response&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;processed&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;in&lt;/span&gt; 4.6472299098969 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ms&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;since&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;the&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;first&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;request&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;10 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;response&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;processed&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;in&lt;/span&gt; 5.1433019638062 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ms&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;since&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;the&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;first&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;request&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Elapsed&lt;/span&gt; 5143.6059474945 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ms&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;;; fnl-http&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;5 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;response&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;processed&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;in&lt;/span&gt; 1.3388519287109 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ms&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;since&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;the&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;first&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;request&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;7 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;response&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;processed&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;in&lt;/span&gt; 1.4401869773865 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ms&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;since&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;the&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;first&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;request&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;9 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;response&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;processed&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;in&lt;/span&gt; 1.5485229492188 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ms&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;since&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;the&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;first&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;request&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;4 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;response&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;processed&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;in&lt;/span&gt; 1.6689200401306 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ms&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;since&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;the&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;first&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;request&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;8 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;response&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;processed&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;in&lt;/span&gt; 1.7789130210876 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ms&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;since&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;the&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;first&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;request&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;6 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;response&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;processed&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;in&lt;/span&gt; 1.9086010456085 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ms&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;since&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;the&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;first&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;request&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;1 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;response&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;processed&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;in&lt;/span&gt; 2.0185270309448 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ms&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;since&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;the&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;first&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;request&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;10 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;response&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;processed&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;in&lt;/span&gt; 2.1092948913574 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ms&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;since&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;the&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;first&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;request&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;2 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;response&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;processed&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;in&lt;/span&gt; 2.2185280323029 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ms&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;since&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;the&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;first&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;request&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;3 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;response&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;processed&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;in&lt;/span&gt; 2.3184778690338 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ms&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;since&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;the&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;first&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;request&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Elapsed&lt;/span&gt; 2318.8180923462 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ms&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Still &amp;lsquo;bout twice as fast!&lt;/p&gt;
&lt;p&gt;And, as you can see, the order of request completion in the asynchronous case is different, since multiple requests were processed &lt;em&gt;in parallel&lt;/em&gt;.
Well, it&amp;rsquo;s not really parallel execution, since the Lua runtime only has one thread, and all response reading is synchronous, but the moment we&amp;rsquo;ve written the request into the socket, the operating system, and networking hardware could act independently.
Thus, the response was sent, and the server on the other side received a series of requests, and probably processed them in parallel, resulting in a faster overall response.
While we wait for the data to come back to our socket, other tasks can be executed, such as making another request or processing a part of the response.
Of course, when we process the response, we do it asynchronously as well, creating opportunities for other asynchronous threads to collaborate.&lt;/p&gt;
&lt;p&gt;Neat stuff!&lt;/p&gt;
&lt;h2 id=&#34;even-further-development-i-guess&#34;&gt;Even further development, I guess?&lt;/h2&gt;
&lt;p&gt;When I started this project, I just wanted to use &lt;a href=&#34;https://gitlab.com/andreyorst/async.fnl&#34; target=&#34;_blank&#34;&gt;async.fnl&lt;/a&gt; for something more real and see if it works.
After working on it for about a month, and reading the source code of the &lt;a href=&#34;https://github.com/dakrone/clj-http&#34; target=&#34;_blank&#34;&gt;clj-http&lt;/a&gt; client, this project gradually became something like a re-implementation of &lt;code&gt;clj-http&lt;/code&gt; in Fennel.
So I changed the project name to &lt;a href=&#34;https://gitlab.com/andreyorst/fnl-http&#34; target=&#34;_blank&#34;&gt;fnl-http&lt;/a&gt;.
It&amp;rsquo;s not a one-to-one port like &lt;code&gt;async.fnl&lt;/code&gt; where I studied the source code - here all code is written from scratch without looking at other clients, but still, I tried to make it faithful.&lt;/p&gt;
&lt;p&gt;There are still a lot of parts of HTTP/1.1 that I haven&amp;rsquo;t processed, and I still have some refactoring ideas and TODOs, so stay tuned!&lt;/p&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: fnl-http Improvements&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Thu, 01 Aug 2024 22:57:00 +0300</pubDate>
    </item><item>
      <title>Asynchronous HTTP client for Fennel</title>
      <link>https://andreyor.st/posts/2024-07-15-asynchronous-http-client-for-fennel/</link>
      <guid>https://andreyor.st/posts/2024-07-15-asynchronous-http-client-for-fennel/</guid>
      <description>&lt;p&gt;A while ago, I made a library for asynchronous programming in Fennel.
It&amp;rsquo;s based on Clojure&amp;rsquo;s &lt;code&gt;core.async&lt;/code&gt; vision of asynchronous programming using only channels.
As an experiment, I&amp;rsquo;ve added a TCP support layer in that library, allowing one to create a TCP channel, and use it in the same way as a regular channel.
My original plan was to implement a small asynchronous HTTP client using that, and I&amp;rsquo;ve tried it a bunch of times in the last year.&lt;/p&gt;
&lt;p&gt;A bit later, I felt unusually burned out from programming as a hobby.
In April, I made a &lt;a href=&#34;https://andreyor.st/posts/2024-04-02-hobbies/&#34;&gt;post&lt;/a&gt; about hobbies, saying that I&amp;rsquo;d like to switch my hobbies from computers for some time.
Truth be told, I&amp;rsquo;ve been in this stance since February, and only now do I once again feel some interest in programming as a hobby.&lt;/p&gt;
&lt;p&gt;So today, I&amp;rsquo;ll walk you through why I decided to write an HTTP client almost from scratch, and why Luasocket&amp;rsquo;s HTTP client didn&amp;rsquo;t work out.&lt;/p&gt;
&lt;h2 id=&#34;luasocket-s-http-client&#34;&gt;Luasocket&amp;rsquo;s HTTP client&lt;/h2&gt;
&lt;p&gt;So, there&amp;rsquo;s an HTTP client in the &lt;a href=&#34;https://lunarmodules.github.io/luasocket/index.html&#34; target=&#34;_blank&#34;&gt;luasocket&lt;/a&gt; library.
And while it does support streaming the body through the &lt;a href=&#34;https://lunarmodules.github.io/luasocket/ltn12.html&#34; target=&#34;_blank&#34;&gt;LTN12&lt;/a&gt; module, the responses are always synchronous.
Which means, that if you have a big enough body, that you&amp;rsquo;d like to process on demand, you only get the convenience of a stream that you&amp;rsquo;ve provided as a &lt;code&gt;sink&lt;/code&gt;.
I&amp;rsquo;d like the body to be returned as some kind of stream that you can process later, reading data from the client, not from some kind of buffer.&lt;/p&gt;
&lt;p&gt;The first thing I tried was patching &lt;code&gt;http.open&lt;/code&gt; function at runtime.
Then we can open the connection and change the &lt;code&gt;close&lt;/code&gt; method on the socket, to work with our intentions.
Here&amp;rsquo;s a piece of code that does this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[{&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;open&lt;/span&gt; &lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;request&lt;/span&gt; &amp;amp;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;as&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;http&lt;/span&gt;} (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;require&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:socket.http&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;http.open&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;] &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; replacing `open` with our version&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;h&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;open&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;) &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; using the original `open` inside&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;close&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;. &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;getmetatable&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;h&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:__index&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:close&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;close-handler&lt;/span&gt; #(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;close&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;h&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;h.close&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;not &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;got-body&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;close-handler&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            1))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;h&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ok?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;code&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;resp&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;request&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;opts&lt;/span&gt;)] &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; &amp;#34;thankfully&amp;#34; `http.request`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                        &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; resolves `http.open`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                        &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; dynamically&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;http.open&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;open&lt;/span&gt;) &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; restoring the original `http.open`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ok?&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:status&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;code&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:headers&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;resp&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:body&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;out&lt;/span&gt;} &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; the body is now a channel&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;error&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;code&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;There are a lot of missing details, for example, the &lt;code&gt;out&lt;/code&gt; is an ordinary channel, however, there&amp;rsquo;s a &lt;code&gt;sink&lt;/code&gt; that passed via the &lt;code&gt;opts&lt;/code&gt; table that pumps everything to it on demand.
Once the &lt;code&gt;sink&lt;/code&gt; is drained the connection is closed.&lt;/p&gt;
&lt;p&gt;All in all, this is a very stateful and shaky approach, so I didn&amp;rsquo;t want to rely on that.
Furthermore, the &lt;code&gt;sink&lt;/code&gt; is being pumped in chunks that can&amp;rsquo;t be controlled very well, making it harder to work with the data in a meaningful way.
So I knew I should do something else.&lt;/p&gt;
&lt;p&gt;I decided to write my own HTTP client based on Luasocket sockets, and streams.
Also, I wanted a bit more familiar calling interface, because Luasocket&amp;rsquo;s HTTP client is not pleasant to use in my opinion.
So let&amp;rsquo;s start with the HTTP parser!&lt;/p&gt;
&lt;h2 id=&#34;reader&#34;&gt;Reader&lt;/h2&gt;
&lt;p&gt;Actually, before parsing HTTP, we need to be able to read data from a stream.
Sockets are kinda like streams already, but we&amp;rsquo;re not there yet, so let&amp;rsquo;s create a string reader:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;string-reader&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;foo\nbar\nbaz&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;Reader&lt;/span&gt;&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; 0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x55f6ca3475b0&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;string-reader&lt;/code&gt; function accepts a string, and returns a Reader object that provides the following methods:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;read&lt;/code&gt; - returns a specified amount of bytes, determined either by the number of bytes or by a supported read pattern.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;lines&lt;/code&gt; - returns a function that when called will return the next logical line.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;peek&lt;/code&gt; - returns a specified amount of bytes, without moving the caret.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;close&lt;/code&gt; - closes the Reader.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here&amp;rsquo;s the implementation of &lt;code&gt;string-reader&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;string-reader&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;string&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;var &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;closed&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;values&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;false&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;len&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;length&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;string&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;try-read-line&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pattern&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;case&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:find&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pattern&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;start&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;end&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                          (&lt;span style=&#34;font-weight:bold&#34;&gt;do &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;end&lt;/span&gt; 1)) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;read-line &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;when &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;len&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;try-read-line&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;(.-)\r?\n&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;try-read-line&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;(.-)\r?$&amp;#34;&lt;/span&gt;))))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;make-reader&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;string&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:close&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;when &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;not &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;closed&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;len&lt;/span&gt; 1))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;closed&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;true&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;closed&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read-bytes&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pattern&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;when &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;len&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pattern&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;where&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:*l&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:l&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;read-line &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;where&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:*a&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:a&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:sub&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;where&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bytes&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:number&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bytes&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:sub&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bytes&lt;/span&gt; -1))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                          (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bytes&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                          &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read-line&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-line&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:peek&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pattern&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;when &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;len&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pattern&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;where&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bytes&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:number&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bytes&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:sub&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bytes&lt;/span&gt; -1))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;error&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;expected number of bytes to peek&amp;#34;&lt;/span&gt;))))})))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It&amp;rsquo;s a bit big, but there&amp;rsquo;s a reason for that - strings in Lua are immutable, and we have to maintain the state when reading.
What makes this more complicated is the &lt;code&gt;peek&lt;/code&gt; method, but we&amp;rsquo;ll get to that later.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;make-reader&lt;/code&gt; function is a generic Reader constructor, that accepts a table of optional methods:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ok?&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ok?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;] (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;when &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ok?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;make-reader&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;source&lt;/span&gt; {&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-bytes&lt;/span&gt; &lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;read-line &lt;/span&gt;&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;close&lt;/span&gt; &lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;peek&lt;/span&gt;}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;close&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;close&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ok?&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pcall&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;close&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;source&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  #&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;-&amp;gt; &lt;/span&gt;{&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;close&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-bytes&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pattern&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ok?&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pcall&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-bytes&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;source&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pattern&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;))) #&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:lines&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-line&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                      (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ok?&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pcall&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;read-line &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;source&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[] #&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:peek&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;peek&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pattern&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ok?&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pcall&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;peek &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;source&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pattern&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   #&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;)}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;setmetatable&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:__close&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;close&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:__name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Reader&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:__fennelview&lt;/span&gt; #(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;#&amp;lt;&amp;#34;&lt;/span&gt; (&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tostring&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;$&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:gsub&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;table:&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Reader:&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;gt;&amp;#34;&lt;/span&gt;)}))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As you can see, it just wraps everything with &lt;code&gt;pcall&lt;/code&gt; and passes the specified &lt;code&gt;source&lt;/code&gt; to the methods.
Perhaps, there&amp;rsquo;s a more clear way of doing this, but it&amp;rsquo;s fine for now.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s a &lt;code&gt;file-reader&lt;/code&gt;, for example:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;file-reader&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;file&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;file&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;case&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;file&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:string&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;io.open&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;file&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:r&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;file&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;make-reader&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;file&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:close&lt;/span&gt; #(&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;$&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:close&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read-bytes&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pattern&lt;/span&gt;] (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pattern&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read-line&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;file&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:lines&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:peek&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pattern&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;assert &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:number&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pattern&lt;/span&gt;)) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;expected number of bytes to peek&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pattern&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                              (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:seek&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:cur&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;- &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pattern&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                              &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt;))})))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It accepts either a file handle or a string that is treated as a path to open the file.
It&amp;rsquo;s much shorter than the &lt;code&gt;string-reader&lt;/code&gt; since files can be seek&amp;rsquo;d and the file object is already stateful.&lt;/p&gt;
&lt;p&gt;In the end, we can do this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;reader.string-reader&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;foo\nbar\nbaz\nqux&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; 2)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;fo&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:*l&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;o&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:*l&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;bar&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:*a&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;baz
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;qux&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We&amp;rsquo;ll be implementing a socket Reader soon, but before that, let&amp;rsquo;s start implementing a set of functions to generate HTTP messages.&lt;/p&gt;
&lt;h2 id=&#34;http-generation&#34;&gt;HTTP generation&lt;/h2&gt;
&lt;p&gt;We start with the &lt;code&gt;build-http-request&lt;/code&gt; function:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;HTTP-VERSION&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;HTTP/1.1&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;build-http-request&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;method&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;request-target&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;?headers&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;?content&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Formaths the HTTP request string as per the HTTP/1.1 spec.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;string.format&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;%s %s %s\r\n%s\r\n%s&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;string.upper&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;method&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;request-target&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;HTTP-VERSION&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;headers-&amp;gt;string&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;?headers&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;?content&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As can be seen, it&amp;rsquo;s just a &lt;code&gt;string.format&lt;/code&gt; call, which we fill in with specific parts.
The &lt;code&gt;method&lt;/code&gt; and &lt;code&gt;request-target&lt;/code&gt; are mandatory arguments, as nothing will work without them.
&lt;code&gt;?headers&lt;/code&gt; and &lt;code&gt;?content&lt;/code&gt; on the other hand are optional.
Let&amp;rsquo;s implement the &lt;code&gt;headers-&amp;gt;string&lt;/code&gt; function now:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;header-&amp;gt;string&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;header&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Converts `header` and `value` arguments into a valid HTTP header
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;string.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;.. &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;utils.capitalize-header&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;header&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;: &amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tostring&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\r\n&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;headers-&amp;gt;string&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;headers&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Converts a `headers` table into a multiline string of HTTP headers.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;when &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;and &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;headers&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;next &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;headers&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;-&amp;gt; &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;icollect&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;header&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pairs&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;headers&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;header-&amp;gt;string&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;header&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;table.concat&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We simply check whether &lt;code&gt;headers&lt;/code&gt; is not &lt;code&gt;nil&lt;/code&gt;, and if it has any keys.
If so, we iterate over the headers table, and convert each pair to a string, then concatenating the resulting table:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;headers-&amp;gt;string&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:connection&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;close&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:content-type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;application/json&amp;#34;&lt;/span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Content-Type: application/json\r
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;Connection: close\r
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;utils.capitalize-header&lt;/code&gt; function accepts a string in any case, and transforms it to an HTTP case, meaning each word is capitalized and separated with a dash:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;utils.capitalize-header&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;foo_bar&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Foo-Bar&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;utils.capitalize-header&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;FooBar&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Foo-Bar&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;utils.capitalize-header&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;FOO BAR&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Foo-Bar&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I&amp;rsquo;ll let you think about implementation, as I&amp;rsquo;m not particularly fond of my own :)&lt;/p&gt;
&lt;p&gt;With that, we can generate a request:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;build-http-request&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:get&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;/&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:host&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;localhost:1234&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:connection&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;close&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:content-type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;text/plain&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;foobar&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;GET / HTTP/1.1\r
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;Content-Type: text/plain\r
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;Host: localhost:1234\r
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;Connection: close\r
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;\r
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;foobar&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;While we&amp;rsquo;re at it, let&amp;rsquo;s make the &lt;code&gt;build-http-response&lt;/code&gt; function too:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;build-http-response&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;status&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;reason&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;?headers&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;?content&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Formats the HTTP response string as per the HTTP/1.1 spec.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;string.format&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;%s %s %s\r\n%s\r\n%s&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;HTTP-VERSION&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tostring&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;status&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;reason&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;headers-&amp;gt;string&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;?headers&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;?content&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Same as before, &lt;code&gt;string.format&lt;/code&gt;, filling missing parts, no new functions used:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;build-http-response&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    200 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;OK&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:connection&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;close&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:content-type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;application/json&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;{\&amp;#34;foo\&amp;#34;: \&amp;#34;bar\&amp;#34;}&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;HTTP/1.1 200 OK\r
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;Content-Type: application/json\r
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;Connection: close\r
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;\r
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;{\&amp;#34;foo\&amp;#34;: \&amp;#34;bar\&amp;#34;}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now, we can parse these using our Reader objects.&lt;/p&gt;
&lt;h2 id=&#34;http-parsing&#34;&gt;HTTP Parsing&lt;/h2&gt;
&lt;p&gt;Let&amp;rsquo;s start with &lt;code&gt;parse-http-response&lt;/code&gt;, as we&amp;rsquo;re more likely to parse responses, rather than requests, as this library is mainly a client.
We&amp;rsquo;ll write &lt;code&gt;parse-http-request&lt;/code&gt; as well, but just for fun.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parse-http-response&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-fn&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;status&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-response-status-line&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-fn&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;headers&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-headers&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-fn&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;doto &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;status&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tset&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:headers&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;headers&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tset&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:body&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Obviously, this isn&amp;rsquo;t all we really need, but it&amp;rsquo;s a good start.
First, let&amp;rsquo;s parse the status line, i.e. the first line of the response: &lt;code&gt;HTTP/1.1 200 OK&lt;/code&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parse-response-status-line&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;status&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ((&lt;span style=&#34;font-weight:bold&#34;&gt;fn loop &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;reader&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fields&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fields&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;field&lt;/span&gt; &amp;amp; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fields&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;part&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;reader&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         (&lt;span style=&#34;font-weight:bold&#34;&gt;loop &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;reader&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fields&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;field&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:protocol-version&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;name &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;major&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;minor&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;part&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:match&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;([^/]+)/(%d).(%d)&amp;#34;&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;doto &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tset&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;field&lt;/span&gt; {&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;name &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:major&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tonumber&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;major&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:minor&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tonumber&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;minor&lt;/span&gt;)})))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;doto &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tset&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;field&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;utils.as-data&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;part&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               ))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;reason&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;-&amp;gt; &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;%s/%s.%s +%s +&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;string.format&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                         &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res.protocol-version.name&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                         &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res.protocol-version.major&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                         &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res.protocol-version.minor&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                         &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res.status&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;status&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:gsub&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;doto &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tset&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:reason-phrase&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;reason&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;status&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:gmatch&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;([^ ]+)&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:protocol-version&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:status&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   {}))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-response-status-line&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-fn&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parse-response-status-line&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-fn&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:*l&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You may be wondering, why these functions accept &lt;code&gt;read-fn&lt;/code&gt;.
Well, this is something we need to do because we&amp;rsquo;ll later pass in a socket-channel as a stream.&lt;/p&gt;
&lt;p&gt;With these functions, we can read and parse the status line:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-response-status-line&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;reader.string-reader&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;HTTP/1.1 200 OK\r\n&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pattern&lt;/span&gt;] (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pattern&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:protocol-version&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:major&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:minor&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;HTTP&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:reason-phrase&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;OK&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:status&lt;/span&gt; 200}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You may also wonder, why the loop doesn&amp;rsquo;t just continue to read the &lt;code&gt;reason-phrase&lt;/code&gt;, instead relying on &lt;code&gt;status:gsub&lt;/code&gt;.
Well, reason can include spaces:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-response-status-line&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;reader.string-reader&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;HTTP/1.1 404 NOT FOUND\r\n&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pattern&lt;/span&gt;] (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pattern&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:protocol-version&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:major&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:minor&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;HTTP&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:reason-phrase&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;NOT FOUND&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:status&lt;/span&gt; 404}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Onto headers:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parse-header&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;case&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:match&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; *([^:]+) *: *(.*)&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;header&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;values&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;header&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-headers&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-fn&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;?headers&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;headers&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;?headers&lt;/span&gt; {})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-fn&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:*l&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;where&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\r&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;headers&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-headers&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-fn&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;case&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parse-header&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;header&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;doto &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;headers&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tset&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;header&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt;)))))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This one is tail-recursive, accumulating parsed headers in the &lt;code&gt;?headers&lt;/code&gt; table:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-headers&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;reader.string-reader&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Content-Type: application/json\r\nConnection: close\r\n\n\r&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pattern&lt;/span&gt;] (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pattern&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Connection&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;close&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Content-Type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;application/json&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Finally, for the body, we just return the reader as it is, as we&amp;rsquo;ve already read from it all the necessary data, and the rest are the contents of the request.
Together, we get a fully parsed response:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parse-http-response&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;reader.string-reader&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;HTTP/1.1 200 OK\r
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;Content-Type: application/json\r
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;Connection: close\r
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;\r
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;{\&amp;#34;foo\&amp;#34;: \&amp;#34;bar\&amp;#34;}&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pattern&lt;/span&gt;] (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pattern&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    )
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:body&lt;/span&gt; #&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;Reader&lt;/span&gt;&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; 0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x55a54832b810&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:headers&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Connection&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;close&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Content-Type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;application/json&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:protocol-version&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:major&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:minor&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;HTTP&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:reason-phrase&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;OK&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:status&lt;/span&gt; 200}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We can ensure that the parsed response can be encoded back:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;req&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;build-http-response&lt;/span&gt; 200 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;OK&amp;#34;&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:connection&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:close&lt;/span&gt;} &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;foobar&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;reader.string-reader&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;req&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         {&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;body&lt;/span&gt; &lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;headers&lt;/span&gt; &lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;reason-phrase&lt;/span&gt; &lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;status&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parse-http-response&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pattern&lt;/span&gt;] (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pattern&lt;/span&gt;)) {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:as&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:raw&lt;/span&gt;})]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;req&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;build-http-response&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;status&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;reason-phrase&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;headers&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;body&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now, let&amp;rsquo;s parse the request for completeness:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parse-request-status-line&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;status&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ((&lt;span style=&#34;font-weight:bold&#34;&gt;fn loop &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;reader&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fields&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fields&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;field&lt;/span&gt; &amp;amp; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fields&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;part&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;reader&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         (&lt;span style=&#34;font-weight:bold&#34;&gt;loop &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;reader&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fields&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;doto &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tset&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;field&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;utils.as-data&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;part&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;status&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:gmatch&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;([^ ]+)&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:method&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:path&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:http-version&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   {}))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-request-status-line&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-fn&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parse-request-status-line&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-fn&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:*l&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parse-http-request&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-fn&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;status&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-request-status-line&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-fn&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;headers&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-headers&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-fn&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;doto &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;status&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tset&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:headers&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;headers&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tset&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:content&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-fn&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:*a&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It&amp;rsquo;s similar, but we need to parse the status line a bit differently.
Same as before, let&amp;rsquo;s ensure that we can do both:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;req&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;build-http-request&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:get&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;/&amp;#34;&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:connection&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:close&lt;/span&gt;} &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;foobar&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;reader.string-reader&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;req&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       {&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;headers&lt;/span&gt; &lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;method&lt;/span&gt; &lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;path &lt;/span&gt;&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;content&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parse-http-request&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pattern&lt;/span&gt;] (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pattern&lt;/span&gt;)) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;req&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;build-http-request&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;method&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;path &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;headers&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;content&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now, we can start implementing the client itself!&lt;/p&gt;
&lt;h2 id=&#34;async-dot-fnl&#34;&gt;Async.fnl&lt;/h2&gt;
&lt;p&gt;For communication, we&amp;rsquo;ll use already existing TCP channels, that enclose socket objects.
Although, we&amp;rsquo;ll need a small modification to the &lt;code&gt;async.fnl&lt;/code&gt; library, as currently it always reads data in chunks of fixed size.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s the function that returns a socket channel:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;set-chunk-size&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pattern-or-size&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self.chunk-size&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pattern-or-size&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;socket-channel&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;client&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;xform&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;err-handler&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;recv&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chan&lt;/span&gt; 1024 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;xform&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;err-handler&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;resp&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chan&lt;/span&gt; 1024 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;xform&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;err-handler&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ready&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chan&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;close&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self&lt;/span&gt;] (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;recv&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:close!&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;resp&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:close!&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self.closed&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;true&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;-&amp;gt; &lt;/span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:puts&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;recv.puts&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:takes&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;resp.takes&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:put!&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;val &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;handler&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;enqueue?&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                       (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;recv&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:put!&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;val &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;handler&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;enqueue?&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:take!&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;handler&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;enqueue?&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;offer!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ready&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:ready&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;resp&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:take!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;handler&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;enqueue?&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:close!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;close&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:close&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;close&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:chunk-size&lt;/span&gt; 1024
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:set-chunk-size&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;set-chunk-size&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;setmetatable&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:__index&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Channel&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:__name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;SocketChannel&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:__fennelview&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                #(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;#&amp;lt;&amp;#34;&lt;/span&gt; (&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tostring&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;$&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:gsub&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;table:&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;SocketChannel:&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;gt;&amp;#34;&lt;/span&gt;)}))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;go-loop&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;recv&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; 0]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;when &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;not= &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;case&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;socket.select&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;client&lt;/span&gt;] 0)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;case&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:send&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:timeout&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;j&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;font-weight:bold&#34;&gt;do &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;!&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;timeout&lt;/span&gt; 10)) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;recur&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;j&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:closed&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;font-weight:bold&#34;&gt;do &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:close&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;close!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;recur&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;recv&lt;/span&gt;) 0))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;do &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;!&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;timeout&lt;/span&gt; 10))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;recur&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;go-loop&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;wait?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;true&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;when &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;wait?&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ready&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;case&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;client&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:receive&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c.chunk-size&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold&#34;&gt;do &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;resp&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;recur&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;true&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:closed&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold&#34;&gt;do &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;client&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:close&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;close!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:closed&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold&#34;&gt;do &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;client&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:close&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;resp&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;close!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:timeout&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold&#34;&gt;do &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;!&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;timeout&lt;/span&gt; 10)) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;recur&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;false&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:timeout&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold&#34;&gt;do &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;resp&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;!&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;timeout&lt;/span&gt; 10)) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;recur&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;true&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It&amp;rsquo;s a lot of code, but in reality, it isn&amp;rsquo;t that complicated.
The &lt;code&gt;socket-channel&lt;/code&gt; function is responsible for three things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Creating a channel, that has separate queues for puts and takes, such that when we put something to a channel, we won&amp;rsquo;t be able to read it back immediately.&lt;/li&gt;
&lt;li&gt;Creating an asynchronous loop that waits for data from the socket, and puts it into the receive queue&lt;/li&gt;
&lt;li&gt;Creating another asynchronous loop, that waits data on the channel, and puts it into the socket.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These loops account for timeouts, as we&amp;rsquo;re going to set the socket timeout to &lt;code&gt;0&lt;/code&gt;, to ensure non-blocking behavior.
Both asynchronous loops employ their own timeout handling.&lt;/p&gt;
&lt;p&gt;The resulting object is a channel, but with some custom methods to account for its duplex nature.
And, there are also other properties, such as &lt;code&gt;chunk-size&lt;/code&gt; and &lt;code&gt;set-chunk-size&lt;/code&gt; which we&amp;rsquo;re going to use with our streams.&lt;/p&gt;
&lt;p&gt;Notice, how the second &lt;code&gt;go-loop&lt;/code&gt; has a &lt;code&gt;wait?&lt;/code&gt; argument.
Because the channel is buffered, it will happily read everything until the buffer is full, which is not ideal, since we may want to change the &lt;code&gt;chunk-size&lt;/code&gt; later.
So we need to delay the actual read, which we do in the &lt;code&gt;take!&lt;/code&gt; method using &lt;code&gt;offer!&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Finally, the &lt;code&gt;tcp.chan&lt;/code&gt; function acts as a constructor for TCP channels:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tcp.chan&lt;/span&gt; [{&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;host&lt;/span&gt; &lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;port&lt;/span&gt;} &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;xform&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;err-handler&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Creates a channel that connects to a socket via `host` and `port`.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;Optionally accepts a transducer `xform`, and an error handler.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;`err-handler` must be a fn of one argument - if an exception occurs
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;during transformation it will be called with the thrown value as an
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;argument, and any non-nil return value will be placed in the channel.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;The read pattern f a socket can be controlled with the
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;`set-chunk-size` method.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;assert &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;socket&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;tcp module requires luasocket&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;host&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;host&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:localhost&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;match-try&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;socket.connect&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;host&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;port&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;client&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;client&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:settimeout&lt;/span&gt; 0)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;socket-channel&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;client&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;xform&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;err-handler&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;catch&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;err&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;error&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;err&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This is all we need on the &lt;code&gt;async.fnl&lt;/code&gt; side of things.
No more patching Luasocket&amp;rsquo;s HTTP client.&lt;/p&gt;
&lt;p&gt;Now we can start implementing our own client.&lt;/p&gt;
&lt;h2 id=&#34;http-client&#34;&gt;HTTP client&lt;/h2&gt;
&lt;p&gt;We already have most of the things we need, but we need to change the &lt;code&gt;parse-http-response&lt;/code&gt; a bit.
Remember, our function returns the body as the Reader, but our source is actually a channel.
We can account for that by passing in an appropriate &lt;code&gt;read-fn&lt;/code&gt; function but our users shouldn&amp;rsquo;t deal with that.
Instead, the body should provide proper Reader methods, so let&amp;rsquo;s create a &lt;code&gt;body-reader&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;body-reader&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-fn&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;var &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;make-reader&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read-bytes&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pattern&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;reader.string-reader&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer-content&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pattern&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pattern&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;where&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:number&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                      (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;len&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer-content&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;length&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer-content&lt;/span&gt;) 0)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-more?&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;&amp;lt; &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;len&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;string.sub&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;len&lt;/span&gt; 1)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-more?&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer-content&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer-content&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-fn&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;- &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;len&lt;/span&gt;)) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-fn&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;- &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;len&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer-content&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;where&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:*l&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:l&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                      (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-more?&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;not &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:find&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\n&amp;#34;&lt;/span&gt;))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;when &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer-content&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                          (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;string.sub&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;+ &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;length&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer-content&lt;/span&gt;) 2))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-more?&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer-content&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer-content&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-fn&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pattern&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-fn&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pattern&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer-content&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;where&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:*a&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:a&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                      (&lt;span style=&#34;font-weight:bold&#34;&gt;do &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;case&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-fn&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pattern&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;when &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer-content&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                  &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer-content&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;.. &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer-content&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                      &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;error&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tostring&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pattern&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read-line&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;reader.string-reader&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                       &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer-content&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:*l&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                       &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-more?&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;not &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:find&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\n&amp;#34;&lt;/span&gt;))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;when &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer-content&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                     (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;string.sub&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;+ &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;length&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer-content&lt;/span&gt;) 2))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-more?&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                       (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer-content&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                           (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer-content&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-fn&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:*l&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                           (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-fn&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:*l&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                       &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer-content&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:close&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt;] (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:close&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:peek&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bytes&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;assert &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:number&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bytes&lt;/span&gt;)) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;expected number of bytes to peek&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;reader.string-reader&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;content&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bytes&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;len&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;length&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;content&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bytes&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;len&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;content&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-fn&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;- &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bytes&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;len&lt;/span&gt;))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer&lt;/span&gt;))))}))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now, that&amp;rsquo;s a lot of code again.
The reason for that is the &lt;code&gt;peek&lt;/code&gt; method - same as for strings, we need to implement a way to peek at data without modifying the reader, or at least hide the modification from the user.
This is essentially what this function does - it creates a string buffer that we can act upon, accounting for possible data in it before actually reading from the channel itself.&lt;/p&gt;
&lt;p&gt;With that function, we can update &lt;code&gt;parse-http-response&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parse-http-response&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-fn&lt;/span&gt; {&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;as&lt;/span&gt;}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;status&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-response-status-line&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-fn&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;headers&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-headers&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-fn&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;stream&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;body-reader&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-fn&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;doto &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;status&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tset&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:headers&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;headers&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tset&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:body&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;as&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:raw&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;stream&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;headers.Content-Length&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:*a&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:stream&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;stream&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;error&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;string.format&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;unsupported coersion method &amp;#39;%s&amp;#39;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;as&lt;/span&gt;)))))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As you can see, I&amp;rsquo;ve added another parameter with options.
Right now, there&amp;rsquo;s only one option &lt;code&gt;as&lt;/code&gt; that will choose how to return the body.
Specifying &lt;code&gt;{:as :raw}&lt;/code&gt; to this function will return the contents of the reader.
And &lt;code&gt;{:as :stream}&lt;/code&gt; will return the stream itself.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Now&lt;/strong&gt;, we can write the &lt;code&gt;request&lt;/code&gt; function:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;http&lt;/span&gt; {})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;http.request&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;method&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;url&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;?opts&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Makes a `method` request to the `url`, returns the parsed response,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;containing a stream data of the response. The `method` is a string,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;describing the HTTP method per the HTTP/1.1 spec. The `opts` is a
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;table containing the following keys:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;- `:async?` - a boolean, whether the request should be asynchronous.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;  The result is an instance of a `promise-chan`, and the body must
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;  be read inside of a `go` block.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;- `:headers` - a table with the HTTP headers for the request
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;- `:body` - an optional string body.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;- `:as` - how to coerce the output.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;Several options available for the `as` key:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;- `:stream` - the body will be a stream object with a `read` method.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;- `:raw` - the body will be a string.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;  This is the default value for `as`.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;When supplying a non-string body, headers should contain a
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;\&amp;#34;content-length\&amp;#34; key. For a string body, if the \&amp;#34;content-length\&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;header is missing it is automatically determined by calling the
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;`length` function, ohterwise no attempts at detecting content-length
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;are made.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[{&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;host&lt;/span&gt; &lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;port&lt;/span&gt; &amp;amp;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;as&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parsed&lt;/span&gt;} (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;http-parser.parse-url&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;url&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;opts&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;collect&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;k&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;v&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pairs&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;?opts&lt;/span&gt; {}))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                       &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:into&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:as&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:raw&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                              &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:async?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;false&lt;/span&gt;}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;k&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;v&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;headers&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;collect&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;k&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;v&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pairs&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;opts.headers&lt;/span&gt; {}))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                          &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:into&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:host&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                 (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;host&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;port&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;:&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;port&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:content-length&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                 (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;opts.body&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                   (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;where&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;body&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:string&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;body&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                   (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;length&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;body&lt;/span&gt;))}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;k&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;v&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;path &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;utils.format-path&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parsed&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;req&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;build-http-request&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;method&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;path &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;headers&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;opts.body&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chan&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tcp.chan&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parsed&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;opts.async?&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;promise-chan&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;go&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chan&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;req&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;http-parser.parse-http-response&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                       &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chan&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                       (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;make-read-fn&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;!&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                       &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;opts&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold&#34;&gt;do &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;!!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chan&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;req&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;http-parser.parse-http-response&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chan&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;make-read-fn&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;!!&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;opts&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We&amp;rsquo;re still missing some important parts, but we&amp;rsquo;ll get to those in a bit.
This function is long, but it&amp;rsquo;s not that complicated.&lt;/p&gt;
&lt;p&gt;First, we parse the given &lt;code&gt;url&lt;/code&gt; into its components, mainly the &lt;code&gt;host&lt;/code&gt; and &lt;code&gt;port&lt;/code&gt;.
Then, we prepare the default &lt;code&gt;opts&lt;/code&gt; table to include &lt;code&gt;as&lt;/code&gt; key and &lt;code&gt;async?&lt;/code&gt; key if none were passed.&lt;/p&gt;
&lt;p&gt;Next, we prepare headers.
The HTTP spec requires the &lt;code&gt;Host&lt;/code&gt; header, so we put it in based on the parsed URL.
The &lt;code&gt;path&lt;/code&gt; part of the request is then formatted from the rest data from the parsed URL.&lt;/p&gt;
&lt;p&gt;Finally, we &lt;code&gt;build-http-request&lt;/code&gt;, using the &lt;code&gt;method&lt;/code&gt;, &lt;code&gt;path&lt;/code&gt;, &lt;code&gt;headers&lt;/code&gt; and &lt;code&gt;body&lt;/code&gt; if supplied.
And create the &lt;code&gt;tcp.chan&lt;/code&gt; using the &lt;code&gt;parsed&lt;/code&gt; object that contains &lt;code&gt;host&lt;/code&gt; and &lt;code&gt;port&lt;/code&gt; needed for the constructor.&lt;/p&gt;
&lt;p&gt;Then, if &lt;code&gt;opts.async?&lt;/code&gt; is &lt;code&gt;true&lt;/code&gt;, we create a &lt;code&gt;promise-chan&lt;/code&gt;, which is like Clojure&amp;rsquo;s &lt;code&gt;promise&lt;/code&gt;, which is only computed once, and then returns the same result over and over.
We start the &lt;code&gt;go&lt;/code&gt; thread, in which we asynchronously put the request into the socket channel, and then we asynchronously parse the response supplying our &lt;code&gt;read-fn&lt;/code&gt; with the &lt;code&gt;&amp;lt;!&lt;/code&gt; function to take from the channel asynchronously.
And we return &lt;code&gt;res&lt;/code&gt; - the promise channel I mentioned earlier.&lt;/p&gt;
&lt;p&gt;If the &lt;code&gt;opts.async?&lt;/code&gt; wasn&amp;rsquo;t true, we do all the same thing, but in a blocking way, using &lt;code&gt;&amp;gt;!!&lt;/code&gt; and &lt;code&gt;&amp;lt;!!&lt;/code&gt; to work with the channel.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s look at &lt;code&gt;parse-url&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parse-authority&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;authority&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;userinfo&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;authority&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:match&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;([^@]+)@&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;port&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;authority&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:match&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;:(%d+)&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;host&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;userinfo&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;authority&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:match&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;@([^:]+)&amp;#34;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;port&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;:&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;authority&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:match&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;([^:]+)&amp;#34;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;port&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;:&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;))))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;userinfo&lt;/span&gt; &lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;port&lt;/span&gt; &lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;host&lt;/span&gt;}))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parse-url&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;url&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;scheme&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;url&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:match&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;^([^:]+)://&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;host&lt;/span&gt; &lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;port&lt;/span&gt; &lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;userinfo&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parse-authority&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;scheme&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;url&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:match&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;//([^/]+)/&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;url&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:match&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;^([^/]+)/&amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;scheme&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;scheme&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;http&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;port&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;port&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;scheme&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:https&lt;/span&gt; 443 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:http&lt;/span&gt; 80))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;path &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;url&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:match&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;//[^/]+/([^?#]+)&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;query&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;url&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:match&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;%?([^#]+)#?&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fragment&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;url&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:match&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;#([^?]+)%??&amp;#34;&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;scheme&lt;/span&gt; &lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;host&lt;/span&gt; &lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;port&lt;/span&gt; &lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;userinfo&lt;/span&gt; &lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;path &lt;/span&gt;&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;query&lt;/span&gt; &lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fragment&lt;/span&gt;}))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Nothing special, just some patterns to match components of the URL:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parse-url&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;https://lua-users.org/?some-query-param=some-value&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:host&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;lua-users.org&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:port&lt;/span&gt; 443
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:query&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;some-query-param=some-value&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:scheme&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;https&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And the &lt;code&gt;format-path&lt;/code&gt; function constructs the path back:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;format-path&lt;/span&gt; [{&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;path &lt;/span&gt;&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;query&lt;/span&gt; &lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fragment&lt;/span&gt;}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;/&amp;#34;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or path &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;query&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;?&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;query&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fragment&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;?&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fragment&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Here&amp;rsquo;s what it does on the previously parsed URL:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;format-path&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:host&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;lua-users.org&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:port&lt;/span&gt; 443
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:query&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;some-query-param=some-value&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:scheme&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;https&amp;#34;&lt;/span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;/?some-query-param=some-value&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Finally, the mysterious &lt;code&gt;make-read-fn&lt;/code&gt; function creates a function that will work with our socket-channel:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;make-read-fn&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;receive&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Returns a function that receives data from a socket by a given
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;`pattern`.  The `pattern` can be either `\&amp;#34;*l\&amp;#34;`, `\&amp;#34;*a\&amp;#34;`, or a
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;number of bytes to read.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pattern&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:set-chunk-size&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pattern&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;receive&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Since our channel does reading on demand, we can&amp;rsquo;t pass the chunk-size/pattern in, so we use the &lt;code&gt;set-chunk-size&lt;/code&gt; method instead.
Paired with delayed read, I&amp;rsquo;ve explained earlier, this works really well.&lt;/p&gt;
&lt;p&gt;With all of that, we&amp;rsquo;re ready to do some requests!&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;http.request&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:get&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;http://lua-users.org/&amp;#34;&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:headers&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:connection&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;close&amp;#34;&lt;/span&gt;} &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:as&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:raw&lt;/span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:body&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;lt;!DOCTYPE html PUBLIC \&amp;#34;-//W3C//DTD HTML 4.01 Transitional//EN\&amp;#34;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;lt;html&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;lt;head&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;lt;title&amp;gt;lua-users.org&amp;lt;/title&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;lt;meta http-equiv=\&amp;#34;content-type\&amp;#34; content=\&amp;#34;text/html; charset=ISO-8859-1\&amp;#34;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;lt;LINK TYPE=\&amp;#34;text/css\&amp;#34; REL=\&amp;#34;stylesheet\&amp;#34; HREF=\&amp;#34;/styles/main.css\&amp;#34;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;lt;/head&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;lt;body&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;lt;img src=\&amp;#34;/images/lua-users-org.png\&amp;#34; alt=\&amp;#34;lua-users.org logo\&amp;#34;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;lt;br clear=all&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;lt;p&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;lt;b&amp;gt;lua-users.org&amp;lt;/b&amp;gt; is an internet site for and by users of the programming language Lua.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;lt;/p&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;lt;p&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;To find out what Lua is and for documentation, downloads, mailing list info, etc. please visit the &amp;lt;a href=\&amp;#34;http://www.lua.org/\&amp;#34;&amp;gt;official Lua web site&amp;lt;/a&amp;gt;.  The &amp;lt;b&amp;gt;lua-users.org&amp;lt;/b&amp;gt; web is not affiliated with Tecgraf.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;lt;/p&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;lt;p&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;Currently available resources:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;lt;/p&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;lt;ul&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;    &amp;lt;li&amp;gt; &amp;lt;a href=\&amp;#34;/wiki/\&amp;#34;&amp;gt;lua-users wiki&amp;lt;/a&amp;gt; - collaborative web site
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;    &amp;lt;li&amp;gt; &amp;lt;a href=\&amp;#34;/lists/lua-l/\&amp;#34;&amp;gt;lua-l archive&amp;lt;/a&amp;gt; - searchable web archive of
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;        the official Lua mailing list
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;    &amp;lt;li&amp;gt; &amp;lt;a href=\&amp;#34;MiniCharter.html\&amp;#34;&amp;gt;lua-users.org mini charter&amp;lt;/a&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;    &amp;lt;li&amp;gt; &amp;lt;a href=\&amp;#34;Acknowledgements.html\&amp;#34;&amp;gt;acknowledgements&amp;lt;/a&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;lt;/ul&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;lt;/body&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;lt;/html&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:headers&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Accept-Ranges&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;bytes&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Connection&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;close&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Content-Length&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;1055&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Content-Type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;text/html&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Date&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Mon, 15 Jul 2024 12:03:00 GMT&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:ETag&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\&amp;#34;61acad05-41f\&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Last-Modified&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Sun, 05 Dec 2021 12:13:57 GMT&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Server&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;nginx/1.20.1&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Strict-Transport-Security&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;max-age=0;&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:protocol-version&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:major&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:minor&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;HTTP&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:reason-phrase&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;OK&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:status&lt;/span&gt; 200}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Or, we can use &lt;code&gt;:as :stream&lt;/code&gt;, and process the stream later:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;resp&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;http.request&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:get&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;http://lua-users.org/&amp;#34;&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:headers&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:connection&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;close&amp;#34;&lt;/span&gt;} &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:as&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:stream&lt;/span&gt;}))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;resp&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:body&lt;/span&gt; #&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;Reader&lt;/span&gt;&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; 0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x55d7090707c0&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:headers&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Accept-Ranges&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;bytes&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Connection&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;close&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Content-Length&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;1055&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Content-Type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;text/html&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Date&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Mon, 15 Jul 2024 12:03:47 GMT&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:ETag&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\&amp;#34;61acad05-41f\&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Last-Modified&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Sun, 05 Dec 2021 12:13:57 GMT&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Server&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;nginx/1.20.1&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Strict-Transport-Security&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;max-age=0;&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:protocol-version&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:major&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:minor&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;HTTP&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:reason-phrase&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;OK&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:status&lt;/span&gt; 200}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;resp.body&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:*l&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;lt;!DOCTYPE html PUBLIC \&amp;#34;-//W3C//DTD HTML 4.01 Transitional//EN\&amp;#34;&amp;gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;However, writing &lt;code&gt;(http.request :get ...)&lt;/code&gt; all the time, is a bit tedious.
Let&amp;rsquo;s instead define functions for each HTTP method.
And, to do so, we&amp;rsquo;ll use macros, because I&amp;rsquo;m too lazy, and I don&amp;rsquo;t want to write documentation for each function:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;macro&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;define-http-method&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;method&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Defines an HTTP method for the given `method`.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  `(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;,(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sym&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:http.&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tostring&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;method&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;url#&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;opts#&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:fnl/arglist&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;url&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;opts&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:fnl/docstring&lt;/span&gt; ,(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Makes a `&amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;string.upper&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tostring&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;method&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                          &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;` request to the `url`, returns the parsed response,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;containing a stream data of the response. The `method` is a string,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;describing the HTTP method per the HTTP/1.1 spec. The `opts` is a
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;table containing the following keys:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;- `:async?` - a boolean, whether the request should be asynchronous.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;  The result is an instance of a `promise-chan`, and the body must
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;  be read inside of a `go` block.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;- `:headers` - a table with the HTTP headers for the request
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;- `:body` - an optional string body.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;- `:as` - how to coerce the output.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;Several options available for the `as` key:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;- `:stream` - the body will be a stream object with a `read` method.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;- `:raw` - the body will be a string.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;  This is the default value for `as`.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;When supplying a non-string body, headers should contain a
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;\&amp;#34;content-length\&amp;#34; key. For a string body, if the \&amp;#34;content-length\&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;header is missing it is automatically determined by calling the
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;`length` function, ohterwise no attempts at detecting content-length
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;are made.&amp;#34;&lt;/span&gt;)}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;http.request&lt;/span&gt; ,(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tostring&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;method&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;url#&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;opts#&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;define-http-method&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;get&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;define-http-method&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;post&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;define-http-method&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;put&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;define-http-method&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;patch&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;define-http-method&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;options&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;define-http-method&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;trace&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;define-http-method&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;head&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;define-http-method&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;delete&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;define-http-method&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;connect&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now, we can call any HTTP method by just writing &lt;code&gt;(http.method-name ...)&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;http.get&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;http://lua-users.org/&amp;#34;&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:headers&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:connection&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;close&amp;#34;&lt;/span&gt;} &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:as&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:stream&lt;/span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:body&lt;/span&gt; #&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;Reader&lt;/span&gt;&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; 0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x55d7095dbb20&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:headers&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Accept-Ranges&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;bytes&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Connection&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;close&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Content-Length&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;1055&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Content-Type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;text/html&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Date&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Mon, 15 Jul 2024 12:08:28 GMT&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:ETag&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\&amp;#34;61acad05-41f\&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Last-Modified&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Sun, 05 Dec 2021 12:13:57 GMT&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Server&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;nginx/1.20.1&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Strict-Transport-Security&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;max-age=0;&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:protocol-version&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:major&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:minor&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;HTTP&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:reason-phrase&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;OK&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:status&lt;/span&gt; 200}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And we can even see the documentation for each method in our editor:&lt;/p&gt;
&lt;figure class=&#34;invertable&#34;&gt;&lt;img src=&#34;https://andreyor.st/2024-07-15-asynchronous-http-client-for-fennel/docs.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;Now, that &lt;code&gt;body-reader&lt;/code&gt;, with a custom buffer, seemed a bit out of the way, so let&amp;rsquo;s use it for good.&lt;/p&gt;
&lt;h2 id=&#34;json-parsing&#34;&gt;JSON parsing&lt;/h2&gt;
&lt;p&gt;Let&amp;rsquo;s extend our &lt;code&gt;parse-http-response&lt;/code&gt; function with another &lt;code&gt;as&lt;/code&gt; method:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; ---- 8&amp;lt; ----&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tset&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:body&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;as&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:raw&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;stream&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parsed-headers.Content-Length&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:*a&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:json&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;json.parse&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;stream&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:stream&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;stream&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;error&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;string.format&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;unsupported coersion method &amp;#39;%s&amp;#39;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;as&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; ---- 8&amp;lt; ----&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now, we can implement a simple JSON parser:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;parse &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Accepts a reader object `rdr`, that supports `peek`, and `read`
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;methods.  Parses the contents to a Lua table.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ((&lt;span style=&#34;font-weight:bold&#34;&gt;fn loop &lt;/span&gt;[]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;case&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:peek&lt;/span&gt; 1)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;{&amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parse-obj&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;loop&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;[&amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parse-arr&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;loop&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\&amp;#34;&amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parse-string&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;where&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;t&amp;#34;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;true&amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:peek&lt;/span&gt; 4))) (&lt;span style=&#34;font-weight:bold&#34;&gt;do &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; 4) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;true&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;where&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;f&amp;#34;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;false&amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:peek&lt;/span&gt; 5))) (&lt;span style=&#34;font-weight:bold&#34;&gt;do &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; 5) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;false&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;where&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;n&amp;#34;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;null&amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:peek&lt;/span&gt; 4))) (&lt;span style=&#34;font-weight:bold&#34;&gt;do &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; 4) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;where&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:match&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;[ \t\n]&amp;#34;&lt;/span&gt;)) (&lt;span style=&#34;font-weight:bold&#34;&gt;loop &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;skip-space&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;where&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:match&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;[-0-9]&amp;#34;&lt;/span&gt;)) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parse-num&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;error&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;JSON parse error: end of stream&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;error&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;string.format&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;JSON parse error: unexpected token (&amp;#39;%s&amp;#39; (code %d))&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:byte&lt;/span&gt;)))))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;First, let&amp;rsquo;s look at &lt;code&gt;parse-string&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parse-string&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; 1)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ((&lt;span style=&#34;font-weight:bold&#34;&gt;fn loop &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chars&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;escaped?&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;case&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; 1)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\\&amp;#34;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;loop &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chars&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;not &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;escaped?&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\&amp;#34;&amp;#34;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;escaped?&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                (&lt;span style=&#34;font-weight:bold&#34;&gt;loop &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chars&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\&amp;#34;&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;false&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chars&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;loop &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chars&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;false&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       ))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;false&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This function handles strings, and escaped patterns withing set strings, like nested strings:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;parse &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;reader.string-reader&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\&amp;#34;foo \\\&amp;#34;bar\\\&amp;#34;\&amp;#34;&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;foo \&amp;#34;bar\&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now, let&amp;rsquo;s look at the &lt;code&gt;parse-arr&lt;/code&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parse-arr&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parse&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; 1)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ((&lt;span style=&#34;font-weight:bold&#34;&gt;fn loop &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;arr&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;skip-space&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;case&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:peek&lt;/span&gt; 1)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;]&amp;#34;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;do &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; 1) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;arr&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;val &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parse&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tset&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;arr&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;+ &lt;/span&gt;1 (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;length&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;arr&lt;/span&gt;)) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;val&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;skip-space&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;case&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:peek&lt;/span&gt; 1)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;,&amp;#34;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;do &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; 1) (&lt;span style=&#34;font-weight:bold&#34;&gt;loop &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;arr&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;]&amp;#34;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;do &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; 1) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;arr&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;error&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;JSON parse error: expected &amp;#39;,&amp;#39; or &amp;#39;]&amp;#39; after the value: &amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;json&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;val&lt;/span&gt;)))))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   []))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This function accepts the &lt;code&gt;parse&lt;/code&gt; callback to parse nested values, so if we try to parse an array of strings, we&amp;rsquo;ll call &lt;code&gt;parse&lt;/code&gt; on each value, and then expect either a colon or the closing bracket to mark the end of the array.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;parse &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;reader.string-reader&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;[\&amp;#34;a\&amp;#34;, \&amp;#34;b\&amp;#34;]&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;a&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;b&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;parse-obj&lt;/code&gt; works for objects in a similar way:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parse-obj&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parse&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; 1)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ((&lt;span style=&#34;font-weight:bold&#34;&gt;fn loop &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;obj&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;skip-space&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;case&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:peek&lt;/span&gt; 1)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;}&amp;#34;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;do &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; 1) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;obj&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;key &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parse&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;skip-space&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;case&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:peek&lt;/span&gt; 1)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;:&amp;#34;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; 1)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                       &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parse&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tset&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;obj&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;key &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;skip-space&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;case&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:peek&lt;/span&gt; 1)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                     &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;,&amp;#34;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;do &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; 1) (&lt;span style=&#34;font-weight:bold&#34;&gt;loop &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;obj&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                     &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;}&amp;#34;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;do &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; 1) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;obj&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                     &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;error&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;JSON parse error: expected &amp;#39;,&amp;#39; or &amp;#39;}&amp;#39; after the value: &amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;json&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;error&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;JSON parse error: expected colon after the key: &amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;json&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;key&lt;/span&gt;)))))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   {}))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Except, it waits for the &lt;code&gt;:&lt;/code&gt; after each key, and then the value:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;parse &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;reader.string-reader&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;{\&amp;#34;arr\&amp;#34;: [\&amp;#34;a\&amp;#34;, \&amp;#34;b\&amp;#34;]}&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:arr&lt;/span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;a&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;b&amp;#34;&lt;/span&gt;]}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Finally, there&amp;rsquo;s the &lt;code&gt;parse-num&lt;/code&gt; and code to parse Booleans, and &lt;code&gt;null&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parse-num&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ((&lt;span style=&#34;font-weight:bold&#34;&gt;fn loop &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;numbers&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;case&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:peek&lt;/span&gt; 1)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;where&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:match&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;[-0-9.eE+]&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;font-weight:bold&#34;&gt;do &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; 1) (&lt;span style=&#34;font-weight:bold&#34;&gt;loop &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;numbers&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tonumber&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;numbers&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; 1)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With that, we can call &lt;code&gt;http.get&lt;/code&gt; passing it &lt;code&gt;{:as :json}&lt;/code&gt; as opts:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;http.get&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;http://httpbin.org/get&amp;#34;&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:as&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:json&lt;/span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:body&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:args&lt;/span&gt; {}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:headers&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Host&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;httpbin.org&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:X-Amzn-Trace-Id&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Root=1-6695183d-27c59aff535ae9f11df8c98d&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:origin&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;185.169.167.87&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:url&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;http://httpbin.org/get&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:headers&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Access-Control-Allow-Credentials&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;true&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Access-Control-Allow-Origin&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;*&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Connection&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;keep-alive&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Content-Length&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;199&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Content-Type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;application/json&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Date&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Mon, 15 Jul 2024 12:38:21 GMT&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Server&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;gunicorn/19.9.0&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:protocol-version&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:major&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:minor&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;HTTP&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:reason-phrase&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;OK&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:status&lt;/span&gt; 200}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And our body was successfully parsed.&lt;/p&gt;
&lt;h2 id=&#34;asynchronous-http-calls&#34;&gt;Asynchronous HTTP calls&lt;/h2&gt;
&lt;p&gt;Now, this client is asynchronous, meaning we can download lots of resources simultaneously.
I&amp;rsquo;m not saying &lt;em&gt;in parallel&lt;/em&gt;, because there are no threads in Lua, but still, we can process several requests at once using our asynchronous library.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s define a simple &lt;code&gt;time&lt;/code&gt; macro first:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;macro&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;time &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;expr&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  `(&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clock#&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;socket.gettime&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;start#&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clock#&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res#&lt;/span&gt; ,&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;expr&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;end#&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clock#&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;print &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Elapsed &amp;#34;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;* &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;- &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;end#&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;start#&lt;/span&gt;) 1000) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; ms&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res#&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With it, we can measure the execution time of a body.
Let&amp;rsquo;s make three asynchronous requests, that upon completion will count the lengths of the body for each, and return their sum:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;time&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;headers&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:connection&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;close&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;http.get&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;http://httpbin.org/get&amp;#34;&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:headers&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;headers&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:as&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:raw&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:async?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;true&lt;/span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;http.get&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;http://httpbin.org/get&amp;#34;&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:headers&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;headers&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:as&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:raw&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:async?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;true&lt;/span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;http.get&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;http://httpbin.org/get&amp;#34;&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:headers&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;headers&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:as&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:raw&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:async?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;true&lt;/span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lengths&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chan&lt;/span&gt; 3)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;go&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;resp&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lengths&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;length&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;resp.body&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;go&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;resp&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lengths&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;length&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;resp.body&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;go&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;resp&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lengths&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;length&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;resp.body&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;+ &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;!!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lengths&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;!!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lengths&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;!!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lengths&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Elapsed&lt;/span&gt; 530.24077415466 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ms&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;597
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In comparison, three synchronous requests, take almost twice as much time:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;time&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;headers&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:connection&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;close&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;http.get&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;http://httpbin.org/get&amp;#34;&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:headers&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;headers&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:as&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:raw&lt;/span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;http.get&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;http://httpbin.org/get&amp;#34;&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:headers&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;headers&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:as&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:raw&lt;/span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;http.get&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;http://httpbin.org/get&amp;#34;&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:headers&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;headers&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:as&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:raw&lt;/span&gt;})]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;+ &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;length&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a.body&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;length&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b.body&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;length&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c.body&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Elapsed&lt;/span&gt; 1047.5831031799 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ms&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;597
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;For the reference, here&amp;rsquo;s Luasocket&amp;rsquo;s HTTP client:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lhttp&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;require&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:socket.http&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;time&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lhttp.request&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;http://httpbin.org/get&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lhttp.request&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;http://httpbin.org/get&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lhttp.request&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;http://httpbin.org/get&amp;#34;&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;+ &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;length&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;length&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;length&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Elapsed&lt;/span&gt; 1919.6438789368 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ms&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;717
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;(Note, the resulting length is different, because Luasocket specifies its user-agent, and httpbin includes it in the answer.)&lt;/p&gt;
&lt;h2 id=&#34;further-development&#34;&gt;Further development&lt;/h2&gt;
&lt;p&gt;Now, of course, that&amp;rsquo;s not all that needs to be implemented.
In its current state, this client doesn&amp;rsquo;t support responses that do not specify the Content-Length or produce a response body in chunked encoding.
HTTPS is out of the question for now too.
Most of the code just takes a &amp;ldquo;happy path&amp;rdquo; without much thought given to errors or more complicated scenarios.
But it&amp;rsquo;s fine, I can always make it better down the line.&lt;/p&gt;
&lt;p&gt;But all in all, it was a fun experiment, and I&amp;rsquo;m feeling better, as I finally have some use for &lt;code&gt;async.fnl&lt;/code&gt;.
You can find the source code for this project on my GitLab profile.
And by the way, even though it is written in Fennel and uses some Fennel libraries, like &lt;code&gt;async.fnl&lt;/code&gt;, this library works with ordinary Lua:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Lua 5.4.4  Copyright (C) 1994-2022 Lua.org, PUC-Rio
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;gt; http = require &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;http&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;gt; http.get(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;http://httpbin.org/get&amp;#34;&lt;/span&gt;, {headers = {connection = &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;close&amp;#34;&lt;/span&gt;}}).body
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;args&amp;#34;&lt;/span&gt;: {},
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;headers&amp;#34;&lt;/span&gt;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Host&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;httpbin.org&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;X-Amzn-Trace-Id&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Root=1-6695424f-01e0510f2ab49b9f46bd51dc&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;origin&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;185.165.163.78&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;url&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;http://httpbin.org/get&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;gt; http.get(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;http://httpbin.org/get&amp;#34;&lt;/span&gt;, {headers = {connection = &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;close&amp;#34;&lt;/span&gt;}, as = &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;stream&amp;#34;&lt;/span&gt;}).body
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Reader: 0x55a6c0eff710
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So if you like what you see, but you don&amp;rsquo;t use Fennel, you can still try out this library.
It just needs to be compiled first.&lt;/p&gt;
&lt;p&gt;Anyway, that&amp;rsquo;s all from me, so… thanks for reading!&lt;/p&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: Asynchronous HTTP client for Fennel&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Mon, 15 Jul 2024 20:08:00 +0300</pubDate>
    </item><item>
      <title>Game4 and Autumn Lisp Game Jam</title>
      <link>https://andreyor.st/posts/2023-10-19-game4-and-autumn-lisp-game-jam/</link>
      <guid>https://andreyor.st/posts/2023-10-19-game4-and-autumn-lisp-game-jam/</guid>
      <description>&lt;p&gt;You might be wondering why there were no posts on the game development marathon I&amp;rsquo;ve been doing.
Maybe you&amp;rsquo;d thought that I gave up after the admittedly underwhelming game3 having no actual game just some basic movement.
And yeah, I felt burned up a lot, and considered skipping a month maybe - but then &lt;a href=&#34;https://itch.io/jam/autumn-lisp-game-jam-2023&#34; target=&#34;_blank&#34;&gt;this happened&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;So I thought - well, I just make the game during the game jam instead, and rest up until the jam begins.
Yes, it means I will technically have less time to do this, but I did spend even less time on game dev last month, so it&amp;rsquo;s fine.
I also got an unplanned vacation, so I guess I&amp;rsquo;ll actually have free time too.&lt;/p&gt;
&lt;p&gt;Though, I lied a bit.
The other reason I didn&amp;rsquo;t do anything is also because the next genre I wanted to work in is a puzzle platformer.
And honestly, I don&amp;rsquo;t know what kind of puzzles to make.
None seem appealing.&lt;/p&gt;
&lt;p&gt;So after a bit of consideration, I&amp;rsquo;ve decided that can try to make something like a &lt;a href=&#34;https://en.wikipedia.org/wiki/Lode_Runner&#34; target=&#34;_blank&#34;&gt;Lode Runner&lt;/a&gt; type of game.
I already have the platformer engine from the very first game in this series, and originally I&amp;rsquo;ve planned that I would make a really simple 2D platformer, then in the subsequent game I will refine and improve it.
Similarly, with the top-down games - first make a simple dungeon crawler, then take the blueprint and make an adventure with it.
Unfortunately, the second game was a flop, and thus if I am to make the fifth game I&amp;rsquo;ll have to do everything from scratch.&lt;/p&gt;
&lt;p&gt;So I&amp;rsquo;ve been thinking how I should handle the game.
I guess I&amp;rsquo;m going to ditch the camera here, so the level fits the screen.
It will make it a bit easier to reason about, and I guess I can always add camera back later if I really need to.&lt;/p&gt;
&lt;p&gt;AI would be an issue though - I&amp;rsquo;ll need to implement some kind of path-finding for the 2D grid with gravity in mind.
In other words, enemies should understand that they can jump down from cliffs if it will bring them on the same elevation with the player.
Additionally, enemies shouldn&amp;rsquo;t just follow the shortest path to the player, as it will make them very predictable.&lt;/p&gt;
&lt;p&gt;And if I have time, I can try putting on a twist to the formula.
Not sure what kind of twist yet, but we&amp;rsquo;ll see I guess.&lt;/p&gt;
&lt;p&gt;The jam starts in ~12 hours, which unfortunately means that it will begin while my work week isn&amp;rsquo;t yet ended.
So I will have one day less already.
Additionally, right now I&amp;rsquo;m in another city, and will lose another day on train to get back home.
So this leaves me with 8 days instead of 10.&lt;/p&gt;
&lt;p&gt;Hopefully it will not be an issue.
Wish me luck!&lt;/p&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: Game4 and Autumn Lisp Game Jam&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Thu, 19 Oct 2023 18:42:00 +0300</pubDate>
    </item><item>
      <title>Game3 - Results</title>
      <link>https://andreyor.st/posts/2023-10-01-game3-results/</link>
      <guid>https://andreyor.st/posts/2023-10-01-game3-results/</guid>
      <description>&lt;p&gt;I gave myself 1 extra day on this game because in total I was only able to work on this game for 5 days, two of which were on the train.
So this game is now done, although I couldn&amp;rsquo;t make any sounds for it.
Designing explosion and blaster sounds that sound good is hard.
The game isn&amp;rsquo;t really complete, and you get practically invincible once you get 3 power-ups.
As wasn&amp;rsquo;t able to do much this time, so a lot of sprites are left unused.
Anyhow, here&amp;rsquo;s the game:&lt;/p&gt;
&lt;iframe src=&#34;https://itch.io/embed-upload/8798744?color=3e3c57&#34;
        allowfullscreen=&#34;&#34;
        width=&#34;600&#34;
        height=&#34;320&#34;
        frameborder=&#34;0&#34;
        style=&#34;margin-left: auto; margin-right: auto; display: block;&#34;&gt;
  &lt;a href=&#34;https://andreyorst.itch.io/game3-shoot-em-up&#34;&gt;Play Game3 - Shoot &#39;Em Up on itch.io&lt;/a&gt;
&lt;/iframe&gt;
&lt;p&gt;Since the last post, I changed a lot.
First, &lt;code&gt;bump&lt;/code&gt; is back and all collisions are handled through it again.&lt;/p&gt;
&lt;p&gt;I made some more weapons, the default one has a rapid-fire rate, but low damage:&lt;/p&gt;
&lt;p&gt;&lt;video autoplay loop muted class=&#34;pixelart&#34;&gt;&lt;source src=&#34;https://andreyor.st/2023-10-01-game3-results/game.webm&#34; type=&#34;video/webm&#34;&gt;
Your browser does not support the video tag.&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;There are three more weapons - laser gun, magic gun, and rocket gun.
Each of these has different damage values.
Originally I planned to implement the overheat mechanic, but ran out of time and passion to do that.&lt;/p&gt;
&lt;p&gt;It was fun implementing the flame that appears when the ship is taken down.
It is done as a particle effect, as the ship simply constantly emits flame particles when burning, and they get removed once their animation ends.
Similar to how the bullets interact with enemies.&lt;/p&gt;
&lt;p&gt;If you want to download this game, here&amp;rsquo;s the cartridge:&lt;/p&gt;
&lt;figure class=&#34;pixelart&#34;&gt;&lt;img src=&#34;https://andreyor.st/2023-10-01-game3-results/cart.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;The next game on my list is a puzzle platformer.
For now, I&amp;rsquo;m not sure if I will have time or passion to do it, and I honestly don&amp;rsquo;t know what types of puzzles should it have.
We&amp;rsquo;ll see.
I already have a pretty decent engine for a platforming game, so it&amp;rsquo;s a good time to refine it.&lt;/p&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: Game3 - Results&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Sun, 01 Oct 2023 17:12:00 +0300</pubDate>
    </item><item>
      <title>Game3 w2/3</title>
      <link>https://andreyor.st/posts/2023-09-24-game3-w23/</link>
      <guid>https://andreyor.st/posts/2023-09-24-game3-w23/</guid>
      <description>&lt;p&gt;Another week passed, but I didn&amp;rsquo;t manage to squeeze out much spare time to make any significant progress with the game.
Not like I didn&amp;rsquo;t do anything, but the game is far from being playable.
This week I, unfortunately, could spend only a single day working on a game, because every day after work I had some personal stuff to take care of, which took all of my after-work hours.
But it doesn&amp;rsquo;t matter, the challenge is a challenge!
Hopefully, the next week will be a bit less busy.
Although the stuff happening right now is very exciting and very important, so if the next week is busy again - so be it.&lt;/p&gt;
&lt;p&gt;Anyway, here&amp;rsquo;s the progress so far:&lt;/p&gt;
&lt;p&gt;&lt;video autoplay loop muted class=&#34;pixelart&#34;&gt;&lt;source src=&#34;https://andreyor.st/2023-09-24-game3-w23/game.webm&#34; type=&#34;video/webm&#34;&gt;
Your browser does not support the video tag.&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s a prototype.
I&amp;rsquo;m experimenting with enemy patterns, like a simple sine wave, or tracking enemies.
No collision has been implemented yet.
This is my plan for the next and final week.
As well as doing more animation, as the ship is just a cardboard right now, making weapons work, and not just fly with you, and implementing a scoring system.
Probably that&amp;rsquo;s the most I&amp;rsquo;ll be able to do.&lt;/p&gt;
&lt;p&gt;Another thing I want to look into is rotating sprites, as I want to spawn meteorites semi-randomly after some time passes in the game, so the game becomes harder.
These meteorites will shatter, and smaller parts will also damage the player, making it harder to maneuver.
But that&amp;rsquo;s probably the least prioritized thing as of this moment.&lt;/p&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: Game3 w2/3&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Sun, 24 Sep 2023 20:55:00 +0300</pubDate>
    </item><item>
      <title>Game3 W?/4</title>
      <link>https://andreyor.st/posts/2023-09-16-game3-w4/</link>
      <guid>https://andreyor.st/posts/2023-09-16-game3-w4/</guid>
      <description>&lt;p&gt;I&amp;rsquo;m working on the next game, although I gave myself an extended period of rest.
After failing to complete the last one I needed to distract myself a bit from this activity, so I worked a bit on Fennel stuff, played some games, and I think I&amp;rsquo;m back in business by now.
I have an interesting thing going on with my productivity - it comes in waves.
What I mean is that I can go onto programming frenzy for several months, and then once I feel burned out, I can just play games for another full month straight.
Though I get tired of games too, and if by that time I feel that I&amp;rsquo;m not ready for programming yet, I can read some technical books, or even just some manga if I still feel too tired to be productive.&lt;/p&gt;
&lt;p&gt;So this five month marathon is a bit hard for me, as I basically have to give up on long periods of rest, and juggle my free time to actually have some time to work on these projects.
While these games are nothing special, I feel like I&amp;rsquo;m still learning new stuff, and thus this is beneficial for me still.
Though, at some I actually thought of dropping the whole idea, and starting a more complex project that I was thinking about for a lot of time already.
But I decided to leave it for the next year, as I still need a lot to learn.
But, back on the topic.&lt;/p&gt;
&lt;p&gt;This post actually marks the end of only the second week of the current game.
How come, you might ask?
To put it simply, I miscalculated a bit, and in reality I had another week on the previous game by the time I dropped it.
So, technically, I could probably finish that game, but the burnout got me, so that&amp;rsquo;s that.&lt;/p&gt;
&lt;p&gt;As for this game, I have a little to show.
As it is a side-scrolling shooter, I designed a basic ship with some shooting modules, and some powerup icons.
I considered to not making any graphics for this one, and doing everything with just primitives, like triangles, circles and so on, but after trying to draw a ship like this I dropped the idea and returned to Pixel Studio.
Here are the results so far:&lt;/p&gt;
&lt;figure class=&#34;pixelart&#34;&gt;&lt;img src=&#34;https://andreyor.st/2023-09-16-game3-w4/sprites.png&#34; width=&#34;100%&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;The ship turned out to be a bit too big, but I decided that I can make a game with larger assets for a change.
So the enemy also uses 4 sprites, instead of just one, as in my previous games.&lt;/p&gt;
&lt;p&gt;And here are the enemies animated:&lt;/p&gt;
&lt;div class=&#34;grid-gallery&#34;&gt;
  &lt;div class=&#34;grid-gallery-row&#34; style=&#34;display: flex&#34;&gt;
&lt;figure class=&#34;pixelart&#34;&gt;&lt;img src=&#34;https://andreyor.st/2023-09-16-game3-w4/roaming.gif&#34; width=&#34;40%&#34; height=&#34;auto&#34;/&gt;
&lt;/figure&gt;

&lt;figure class=&#34;pixelart&#34;&gt;&lt;img src=&#34;https://andreyor.st/2023-09-16-game3-w4/roaming-2.gif&#34; width=&#34;40%&#34; height=&#34;auto&#34;/&gt;
&lt;/figure&gt;

&lt;/div&gt;
&lt;figcaption&gt;
  &lt;p&gt;Movement animations&lt;/p&gt;
&lt;/figcaption&gt;
&lt;div class=&#34;grid-gallery-row&#34; style=&#34;display: flex&#34;&gt;
&lt;figure class=&#34;pixelart&#34;&gt;&lt;img src=&#34;https://andreyor.st/2023-09-16-game3-w4/exploding.gif&#34; width=&#34;40%&#34; height=&#34;auto&#34;/&gt;
&lt;/figure&gt;

&lt;figure class=&#34;pixelart&#34;&gt;&lt;img src=&#34;https://andreyor.st/2023-09-16-game3-w4/explosion-2.gif&#34; width=&#34;40%&#34; height=&#34;auto&#34;/&gt;
&lt;/figure&gt;

&lt;/div&gt;
&lt;figcaption&gt;
  &lt;p&gt;Explosion animations&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/div&gt;
&lt;p&gt;Obviously, I need to add more enemy variety, with different patterns, but designing enemies is hard.
BTW, if you&amp;rsquo;re curious how I draw things on the phone, here&amp;rsquo;s a time-lapse:&lt;/p&gt;
&lt;p&gt;&lt;video autoplay loop&gt;&lt;source src=&#34;https://andreyor.st/2023-09-16-game3-w4/timelapse.webm&#34; type=&#34;video/webm&#34;&gt;
Your browser does not support the video tag.&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;Though, I usually don&amp;rsquo;t do it in the landscape mode, portrait mode works better for me, especially with a stylus.
This process was recorded in landscape just for viewing convenience.&lt;/p&gt;
&lt;p&gt;On the technical side of things, I already implemented a basic movement with linear interpolation for the flying modules, and implemented some enemy patterns, but there&amp;rsquo;s no actual interactions yet.
I&amp;rsquo;m kinda torn on the idea of including &lt;code&gt;bump.lua&lt;/code&gt; again, as I feel like that this game can be done without any collision library.
At the same time, having a collision library may make things much simpler, so I&amp;rsquo;m still thinking how to approach this game.&lt;/p&gt;
&lt;p&gt;For the &lt;em&gt;record&lt;/em&gt;, I basically dropped the idea of making &lt;em&gt;any&lt;/em&gt; kind of music for these games because I just can&amp;rsquo;t get myself to work on it.
I do plan to take some courses on music composition for future projects, though.
Sound effects are challenging enough already by themselves.&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s all for this week!
Hopefully, I&amp;rsquo;ll manage to finish the game this time, though I already lost one week.
Let&amp;rsquo;s say, this is week 1/3 instead of 2/4 shall we?
Feels less demotivating this way.&lt;/p&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: Game3 W?/4&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Sat, 16 Sep 2023 01:59:00 +0300</pubDate>
    </item><item>
      <title>Fennel libraries as single files</title>
      <link>https://andreyor.st/posts/2023-08-27-fennel-libraries-as-single-files/</link>
      <guid>https://andreyor.st/posts/2023-08-27-fennel-libraries-as-single-files/</guid>
      <description>&lt;p&gt;I&amp;rsquo;m pleased to announce that most of my libraries for fennel are now shipped as single files!
It was a long-standing issue with Fennel for me, as there was no clear way to ship both macros and functions in the same file, but after some experimentation, I figured out a way.
After a bit of testing with my new library for &lt;a href=&#34;https://gitlab.com/andreyorst/async.fnl&#34; target=&#34;_blank&#34;&gt;asynchronous programming&lt;/a&gt; I can say that it works well enough to be used in most other libraries.
Although the implementation is a bit rough and manual, that&amp;rsquo;s what I&amp;rsquo;ll try to describe here today.&lt;/p&gt;
&lt;p&gt;But first, let&amp;rsquo;s talk modules.
This will be a long post, so buckle up.&lt;/p&gt;
&lt;h2 id=&#34;modules-in-various-programming-languages&#34;&gt;Modules in various programming languages&lt;/h2&gt;
&lt;p&gt;I find it fascinating that a lot of languages have some kind of a module system, yet most of them hide it from the user behind some special keywords and don&amp;rsquo;t allow us to operate on modules as we can do with other objects.
Lua is not one of these languages - its module system is ingenious and yet very simple.
First, let&amp;rsquo;s look at some other languages so you can understand what I&amp;rsquo;m getting at.&lt;/p&gt;
&lt;p&gt;For example, here&amp;rsquo;s Elixir, a language I sometimes tinker with.
I&amp;rsquo;m using an interactive elixir shell, but it&amp;rsquo;ll be the same even if I were to put this module into a file:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-elixir&#34; data-lang=&#34;elixir&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;iex(1)&amp;gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defmodule&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Lib&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;...(1)&amp;gt;   &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;def&lt;/span&gt; foo(), &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;do&lt;/span&gt;: &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;foo&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;...(1)&amp;gt;   &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;def&lt;/span&gt; bar(), &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;do&lt;/span&gt;: &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;bar&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;...(1)&amp;gt; &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:module&lt;/span&gt;, &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Lib&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;lt;&amp;lt;70, 79, 82, 49, 0, 0, 5, 180, 66, 69, 65, 77, 65, 116, 85, 56, 0, 0, 0, 169,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   0, 0, 0, 18, 10, 69, 108, 105, 120, 105, 114, 46, 70, 111, 111, 8, 95, 95,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   105, 110, 102, 111, 95, 95, 10, 97, 116, ...&amp;gt;&amp;gt;, {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:bar&lt;/span&gt;, 0}}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;iex(2)&amp;gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Lib&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Lib&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;iex(3)&amp;gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Lib&lt;/span&gt;.foo()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;foo&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You can see that after the module was defined, we can see a tuple with some keywords, the module symbol, and other stuff.
If we try to examine &lt;code&gt;Lib&lt;/code&gt; in the shell it just prints &lt;code&gt;Lib&lt;/code&gt;.
Yet, we can call the function &lt;code&gt;foo&lt;/code&gt; from this module via the dot syntax: &lt;code&gt;Lib.foo()&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;If we try to inspect what &lt;code&gt;Lib&lt;/code&gt; actually is, we can see that it has a bunch of information but, at least to me, this tells almost nothing of substance:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-elixir&#34; data-lang=&#34;elixir&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;iex(4)&amp;gt; i &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Lib&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Term&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Lib&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Data&lt;/span&gt; type
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Atom&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Module&lt;/span&gt; bytecode
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  []
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Source&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  iex
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Version&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  [249975233796634777878553557963106734802]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Compile&lt;/span&gt; options
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:no_spawn_compiler_process&lt;/span&gt;, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:from_core&lt;/span&gt;, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:no_core_prepare&lt;/span&gt;, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:no_auto_import&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Description&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Call&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Lib&lt;/span&gt;.module_info() to access metadata.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Raw&lt;/span&gt; representation
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:&amp;#34;Elixir.Lib&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Reference&lt;/span&gt; modules
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Module&lt;/span&gt;, &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Atom&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Implemented&lt;/span&gt; protocols
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;IEx.Info&lt;/span&gt;, &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Inspect&lt;/span&gt;, &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;List.Chars&lt;/span&gt;, &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;String.Chars&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Let&amp;rsquo;s look at another language, that I don&amp;rsquo;t often tinker with, but a lot of other people do - Python.
This time I&amp;rsquo;ll put this into a file, as I don&amp;rsquo;t know the shell capabilities of Python, and if it is possible to do stuff like in Elixir.
Here&amp;rsquo;s the same module:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;# lib.py&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;foo&lt;/span&gt; ():
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;foo&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bar&lt;/span&gt; ():
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;bar&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now, if we &lt;code&gt;import&lt;/code&gt; it, we can at least see some indication of what &lt;code&gt;lib&lt;/code&gt; is when we try to inspect it:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;gt;&amp;gt;&amp;gt; &lt;span style=&#34;font-weight:bold&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lib&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;gt;&amp;gt;&amp;gt; lib
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;module &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;lib&amp;#39;&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;from&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;/tmp/lib.py&amp;#39;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;gt;&amp;gt;&amp;gt; lib.foo()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;foo&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;What is this &lt;code&gt;&amp;lt;module &#39;lib&#39; from &#39;/tmp/lib.py&#39;&amp;gt;&lt;/code&gt; thing actually?
Python defines different keywords for working with modules, like &lt;code&gt;from&lt;/code&gt;, &lt;code&gt;import&lt;/code&gt;, &lt;code&gt;as&lt;/code&gt;, and maybe others, as well as a special set of functions to query the module, like &lt;code&gt;dir&lt;/code&gt;.
But the module itself is probably some kind of an object:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;gt;&amp;gt;&amp;gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;type&lt;/span&gt;(lib)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;module&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Here&amp;rsquo;s another language, that I know better than Python or Elixir - Clojure.
In Clojure, similar to Elixir, you can define modules in the REPL, so let&amp;rsquo;s do this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;ns &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lib&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lib&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;foo&lt;/span&gt; [] &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;foo&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;lib/foo&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lib&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bar&lt;/span&gt; [] &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;bar&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;lib/bar&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lib&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;in-ns &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;user&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;namespace&lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;require&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;lib&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lib/foo&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;foo&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Once again, we can see that the namespace is some kind of &lt;code&gt;#namespace[user]&lt;/code&gt; thingy.
If we try to reference the namespace as is in the REPL, we get an error:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lib&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Syntax&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;error&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;compiling&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;at&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;*cider-repl&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;blog/posts&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:localhost:44133&lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clj&lt;/span&gt;)&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:0:0&lt;/span&gt;)&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Unable&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;to&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;resolve &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;symbol&lt;/span&gt;&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lib&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;in&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;this&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;context&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;However, Clojure provides us with a set of &lt;code&gt;ns-*&lt;/code&gt; functions to work with namespaces.
For instance, we can get all interned symbols of the namespace as a map:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;ns-interns &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;lib&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bar&lt;/span&gt; #&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;lib/bar&lt;/span&gt;, &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;foo&lt;/span&gt; #&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;lib/foo&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We can even go back to the &lt;code&gt;lib&lt;/code&gt; module, define a private function, return to the &lt;code&gt;user&lt;/code&gt; module, and inspect the &lt;code&gt;lib&lt;/code&gt; module again:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;in-ns &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;lib&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;namespace&lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lib&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lib&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;^&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:private&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;baz&lt;/span&gt; [] &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;baz&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;lib/baz&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lib&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;in-ns &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;user&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;namespace&lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;ns-interns &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;lib&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;baz&lt;/span&gt; #&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;lib/baz&lt;/span&gt;, &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bar&lt;/span&gt; #&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;lib/bar&lt;/span&gt;, &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;foo&lt;/span&gt; #&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;lib/foo&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;ns-publics &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;lib&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bar&lt;/span&gt; #&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;lib/bar&lt;/span&gt;, &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;foo&lt;/span&gt; #&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;lib/foo&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Yet, modules are something hidden from us, we usually don&amp;rsquo;t operate on them directly.&lt;/p&gt;
&lt;p&gt;So that brings us to Fennel, and therefore Lua.
I will demonstrate things in Fennel just for better clarity, as it provides better inspection capabilities.&lt;/p&gt;
&lt;p&gt;What separates Lua runtime from the rest is that its modules are &lt;em&gt;just tables&lt;/em&gt;.
When we&amp;rsquo;re writing a library, or just a module in our application, the module is just a file on the file system, and at the end of that file the last statement returns a table (or a function):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; lib.fnl&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;foo&lt;/span&gt; [] &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;foo&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bar&lt;/span&gt; [] &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;bar&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;baz&lt;/span&gt; [] &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;baz&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:foo&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;foo&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:bar&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bar&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In this case, the table holds references to local functions, and thus the &lt;code&gt;baz&lt;/code&gt; function is completely private.
When we require this module with the &lt;code&gt;require&lt;/code&gt; function it somehow finds the file of this module on disc, loads it, evaluates the top level, and returns the table, which we just then store in a variable, same as any other value:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lib&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;lib&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lib.foo&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;foo&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If we try to reference &lt;code&gt;lib&lt;/code&gt; here, we&amp;rsquo;ll see that it is just a table, nothing special:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lib&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:bar&lt;/span&gt; #&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;function&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x55f4cfecd350&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:foo&lt;/span&gt; #&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;function&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x55f4cff20610&amp;gt;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;getmetatable &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lib&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We can check if it has a metatable that hides some module-related trickery, but it&amp;rsquo;s not.
It&amp;rsquo;s a plain ol&amp;rsquo; Lua table.&lt;/p&gt;
&lt;h2 id=&#34;lua-module-system&#34;&gt;Lua module system&lt;/h2&gt;
&lt;p&gt;But Lua doesn&amp;rsquo;t stop there.
I mentioned that &lt;code&gt;require&lt;/code&gt; evaluates the top level, so if we put something like &lt;code&gt;(print &amp;quot;hi!&amp;quot;)&lt;/code&gt; into a module, and require it, we&amp;rsquo;ll see the text being printed:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; qux.fnl&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;qux&lt;/span&gt; [] &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;qux&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;print &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;hi!&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:qux&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;qux&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Here&amp;rsquo;s how it looks in the Fennel REPL:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:qux&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;hi!&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:qux&lt;/span&gt; #&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;function&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x55f4cfe7a1e0&amp;gt;&lt;/span&gt;}	&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;./qux.fnl&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;But if we do a second &lt;code&gt;require&lt;/code&gt; the print won&amp;rsquo;t happen:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:qux&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:qux&lt;/span&gt; #&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;function&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x55f4cfe7a1e0&amp;gt;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This is because while the modules are plain tables, the &lt;code&gt;require&lt;/code&gt; function is actually smarter than just read+eval.
Module loading process in Lua ensures that modules are only loaded once, and are cached in a special &lt;code&gt;package&lt;/code&gt; table.&lt;/p&gt;
&lt;h3 id=&#34;package-dot-loaded-caching-module-definitions&#34;&gt;&lt;code&gt;package.loaded&lt;/code&gt; - caching module definitions&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;package.loaded.qux&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:qux&lt;/span&gt; #&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;function&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x55f4cfe7a1e0&amp;gt;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So each time we call &lt;code&gt;(require :something)&lt;/code&gt; it first looks if &lt;code&gt;package.loaded.something&lt;/code&gt; exists, and if it is, it just returns the value from there.
This way, we can unload any module, just by setting a key in the &lt;code&gt;package.loaded&lt;/code&gt; to &lt;code&gt;nil&lt;/code&gt;, and then &lt;code&gt;require&lt;/code&gt; will re-evaluate our module.
Fennel actually provides a REPL command for that, called &lt;code&gt;reload&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;However, it&amp;rsquo;s still not that simple.
Lua&amp;rsquo;s &lt;code&gt;require&lt;/code&gt; is actually extensible.
If the module was not found in the &lt;code&gt;package.loaded&lt;/code&gt; the next place &lt;code&gt;require&lt;/code&gt; checks is &lt;code&gt;package.preload&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&#34;package-dot-preload-preloading-modules-via-anonymous-functions&#34;&gt;&lt;code&gt;package.preload&lt;/code&gt; - preloading modules via anonymous functions&lt;/h3&gt;
&lt;p&gt;This table stores modules in a similar way, except instead of storing tables, it stores functions that when called will load a module.&lt;/p&gt;
&lt;p&gt;We can utilize this in the REPL:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;package.preload.my-lib&lt;/span&gt; []
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;print &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;loading my-lib&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;hello&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;hi &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;!&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:hello&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;hello&lt;/span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;function&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x55f4d4a23d50&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;package.preload.my-lib&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;function&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x55f4d4a23d50&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I&amp;rsquo;ve created a function in that table, that when called will signal that the module is loaded, define a local function, and return a table, referencing that function.
So it&amp;rsquo;s essentially the same as the file approach, except it is stored in a function, which execution is delayed until someone tries to &lt;code&gt;require&lt;/code&gt; the module.
Lua was meant to be able to work in filesystem-less environments, and this is one of the solutions for storing libraries.&lt;/p&gt;
&lt;p&gt;When we &lt;code&gt;require&lt;/code&gt; the &lt;code&gt;my-lib&lt;/code&gt; module, we see the &lt;code&gt;loading my-lib&lt;/code&gt; message, but instead of providing a second value with the file from where the module was read, the value is &lt;code&gt;:preload:&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:my-lib&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;loading&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;my-lib&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:hello&lt;/span&gt; #&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;function&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x55f4d4a4ecf0&amp;gt;&lt;/span&gt;}	&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;:preload:&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This indicates that the library was indeed loaded from the &lt;code&gt;package.preload&lt;/code&gt; table.
We can then use it as normal:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;my-lib&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:my-lib&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;my-lib.hello&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Bob&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;hi Bob!&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This already gives us some power, and Fennel utilizes &lt;code&gt;package.preload&lt;/code&gt; to provide fully self-contained AOT-compiled Lua files that can be shipped without any external dependencies.
Yet, there&amp;rsquo;s a final step in this system that we can discuss.&lt;/p&gt;
&lt;h3 id=&#34;package-dot-searchers-extending-the-module-system&#34;&gt;&lt;code&gt;package.searchers&lt;/code&gt; - extending the module system&lt;/h3&gt;
&lt;p&gt;If the module was found neither in the &lt;code&gt;package.loaded&lt;/code&gt; nor in the &lt;code&gt;package.preload&lt;/code&gt;, the &lt;code&gt;require&lt;/code&gt; function starts using special &lt;code&gt;package.searchers&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;package.searchers&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[#&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;function&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x55f4cfc8b930&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; #&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;function&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x55f4cfc8b970&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; #&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;function&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x55f4cfc8b9b0&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; #&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;function&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x55f4cfc8b9f0&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; #&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;function&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x55f4cff32450&amp;gt;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It&amp;rsquo;s another table in the &lt;code&gt;package&lt;/code&gt; table, that stores a list of functions, that will try to find and load the given module by their own means.
Let&amp;rsquo;s write our own:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;table.insert&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;package.searchers&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mod&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;io.write &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;searching &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mod&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; with a custom searcher\n&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;loader&lt;/span&gt; []
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bye&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;bye %s&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:format&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:bye&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bye&lt;/span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;values &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;loader&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mod&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This searcher function in our case will work for any module regardless of its existence, so by doing this we kinda broke the loading mechanism.
Still, this might be useful in some sandboxing scenarios.
Alternatively, this mechanism can be used if the environment you run Lua in doesn&amp;rsquo;t have a real file system, so finding a module requires some trickery, and thus you can extend the general &lt;code&gt;require&lt;/code&gt; mechanism.
What our function does is not as complicated - it&amp;rsquo;s similar to what we did in the &lt;code&gt;preload&lt;/code&gt; example, except what makes it different is that it basically allows us to do whatever we want before this &lt;code&gt;loader&lt;/code&gt; function is given back to the runtime.&lt;/p&gt;
&lt;p&gt;We can see it works:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:asdf&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;searching&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;asdf&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;with&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;custom&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;searcher&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:bye&lt;/span&gt; #&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;function&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x55ec3e592ae0&amp;gt;&lt;/span&gt;}	&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;asdf&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:qwer&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;searching&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;qwer&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;with&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;custom&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;searcher&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:bye&lt;/span&gt; #&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;function&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x55ec3e529460&amp;gt;&lt;/span&gt;}	&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;qwer&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:asdf&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:bye&lt;/span&gt; #&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;function&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x55ec3e592ae0&amp;gt;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And that it obeys the same caching rules.&lt;/p&gt;
&lt;p&gt;This &lt;code&gt;package.searchers&lt;/code&gt; table is the sole reason why Fennel works as seamlessly as it is.
Setting up Fennel&amp;rsquo;s package searcher means that when we&amp;rsquo;re trying to &lt;code&gt;require&lt;/code&gt; some &lt;code&gt;module&lt;/code&gt; if there is a &lt;code&gt;module.fnl&lt;/code&gt; file on the &lt;code&gt;FENNEL_PATH&lt;/code&gt;, Fennel will compile this module, and then load it as a normal Lua module.
If you want to implement your own Lua-based language, this is definitely the place to embed your compiler.&lt;/p&gt;
&lt;p&gt;Now that you have an idea of how modules work in Lua, let&amp;rsquo;s discuss the main topic of this post - single-file Fennel libraries, and complications related to it.&lt;/p&gt;
&lt;h2 id=&#34;fennel-libraries-with-macros&#34;&gt;Fennel libraries with macros&lt;/h2&gt;
&lt;p&gt;A library in Fennel obeys the exact same rules as a Lua library, except the Fennel compiler adds some steps to the whole process of library loading.
As I explained in the &lt;a href=&#34;#package-dot-searchers-extending-the-module-system&#34;&gt;searchers topic&lt;/a&gt;, the compiler is invoked on the module file before it is given to the Lua runtime.
This means, that when we&amp;rsquo;re loading a Fennel file, it first gets compiled to Lua, and only then it is loaded.
This works well up until we introduce compile-time features into our modules - mainly macros.&lt;/p&gt;
&lt;p&gt;If we look back at Clojure and Elixir examples, I didn&amp;rsquo;t use macros in the modules - let&amp;rsquo;s fix this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lib&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defmacro &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;unless&lt;/span&gt; [&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;test &lt;/span&gt;&amp;amp; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;body&lt;/span&gt;] `(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;when-not &lt;/span&gt;~&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;test &lt;/span&gt;~@&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;body&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;lib/my-do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lib&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;unless&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Syntax&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;error&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;compiling&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;at&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;*cider-repl&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;blog/posts&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:localhost:44133&lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clj&lt;/span&gt;)&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:0:0&lt;/span&gt;)&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Can&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;t&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;take &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;of&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;macro&lt;/span&gt;&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; #&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;lib/unless&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lib&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;ns-interns &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;lib&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;baz&lt;/span&gt; #&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;lib/baz&lt;/span&gt;, &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bar&lt;/span&gt; #&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;lib/bar&lt;/span&gt;, &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;unless&lt;/span&gt; #&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;lib/unless&lt;/span&gt;, &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;foo&lt;/span&gt; #&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;lib/foo&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If we try to take a value of the macro, we get an error, as macros are a compile-time construct.
Yet, it is referenced in the &lt;code&gt;ns-intern&lt;/code&gt; as a var.
And we can go back to the &lt;code&gt;user&lt;/code&gt; module, and use our macro from there:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lib&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;in-ns &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;user&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;namespace&lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lib/unless&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;true&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;println &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;this should never be printed&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In Elixir, it is similar, as you also can provide a macro in your module, and upon requiring the module you can use a macro from it.
Here&amp;rsquo;s an example macro from the &lt;a href=&#34;https://elixir-lang.org/getting-started/meta/macros.html#our-first-macro&#34; target=&#34;_blank&#34;&gt;docs&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-elixir&#34; data-lang=&#34;elixir&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;iex(2)&amp;gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defmodule&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Unless&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;...(2)&amp;gt;   &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defmacro&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;unless&lt;/span&gt;(clause, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;do&lt;/span&gt;: expression) &lt;span style=&#34;font-weight:bold&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;...(2)&amp;gt;     &lt;span style=&#34;font-weight:bold&#34;&gt;quote&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;...(2)&amp;gt;       &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt;(!&lt;span style=&#34;font-weight:bold&#34;&gt;unquote&lt;/span&gt;(clause), &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;do&lt;/span&gt;: &lt;span style=&#34;font-weight:bold&#34;&gt;unquote&lt;/span&gt;(expression))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;...(2)&amp;gt;     &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;...(2)&amp;gt;   &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;...(2)&amp;gt; &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:module&lt;/span&gt;, &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Unless&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;lt;&amp;lt;70, 79, 82, 49, 0, 0, 6, 72, 66, 69, 65, 77, 65, 116, 85, 56, 0, 0, 0, 191,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   0, 0, 0, 20, 13, 69, 108, 105, 120, 105, 114, 46, 85, 110, 108, 101, 115,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   115, 8, 95, 95, 105, 110, 102, 111, 95, 95, ...&amp;gt;&amp;gt;, {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:unless&lt;/span&gt;, 2}}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;iex(3)&amp;gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Unless&lt;/span&gt;.&lt;span style=&#34;font-weight:bold&#34;&gt;unless&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;true&lt;/span&gt;, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;do&lt;/span&gt;: &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;IO&lt;/span&gt;.puts &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;this should never be printed&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;this should never be printed
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;** (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;UndefinedFunctionError&lt;/span&gt;) function &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Unless&lt;/span&gt;.macro_unless/2 is undefined &lt;span style=&#34;font-weight:bold&#34;&gt;or&lt;/span&gt; private.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;However&lt;/span&gt;, there is a macro with the same name &lt;span style=&#34;font-weight:bold&#34;&gt;and&lt;/span&gt; arity.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Be&lt;/span&gt; sure to &lt;span style=&#34;font-weight:bold&#34;&gt;require&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Unless&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; you intend to invoke this macro
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Unless&lt;/span&gt;.&lt;span style=&#34;font-weight:bold&#34;&gt;unless&lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;true&lt;/span&gt;, [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;do&lt;/span&gt;: &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:ok&lt;/span&gt;])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    iex:3: (file)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Except, we can&amp;rsquo;t use this macro right away - unlike in Clojure, we need to &lt;code&gt;require&lt;/code&gt; the module:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-elixir&#34; data-lang=&#34;elixir&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;iex(3)&amp;gt; &lt;span style=&#34;font-weight:bold&#34;&gt;require&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Unless&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Unless&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;iex(4)&amp;gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Unless&lt;/span&gt;.&lt;span style=&#34;font-weight:bold&#34;&gt;unless&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;true&lt;/span&gt;, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;do&lt;/span&gt;: &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;IO&lt;/span&gt;.puts &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;this should never be printed&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Because Elixir&amp;rsquo;s macros are entirely Elixir&amp;rsquo;s concept, BEAM knows nothing about them, and thus you can use them only in Elixir, and it explains why the shell requires some additional steps.
Perhaps these can be automated, as Clojure can do it without any additional &lt;code&gt;require&lt;/code&gt; calls, but I don&amp;rsquo;t know for sure how it is done in Clojure or in Elixir.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m bringing Elixir and Clojure here because both languages are hosted on their respective runtimes - Erlang&amp;rsquo;s BEAM and JVM.
Fennel is similarly hosted on Lua, but on the other hand, is different from these two when it comes to macros.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s add the &lt;code&gt;unless&lt;/code&gt; macro to the &lt;code&gt;lib.fnl&lt;/code&gt; module:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; lib.fnl&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;foo&lt;/span&gt; [] &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;foo&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bar&lt;/span&gt; [] &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;bar&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;macro &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;unless&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;test&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  `(&lt;span style=&#34;font-weight:bold&#34;&gt;when &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;not &lt;/span&gt;&lt;span style=&#34;&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;test&lt;/span&gt;) &lt;span style=&#34;&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:foo&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;foo&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:bar&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bar&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:unless&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;unless&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Trying to load this module, however, will result in a compile error:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lib&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:lib&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;./lib.fnl&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:5:27&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Compile&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;error&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tried&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;to&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;reference&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;macro &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;without&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;calling&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;it&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:foo&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;foo&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:bar&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bar&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:unless&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;unless&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;* &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Try&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;renaming&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;the&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;macro &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;so&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;as&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;not &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;to&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;conflict&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;with&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;locals.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We can&amp;rsquo;t simply export our macro alongside our functions.
What should we do then?&lt;/p&gt;
&lt;p&gt;The fennel language &lt;a href=&#34;https://fennel-lang.org/reference#macros&#34; target=&#34;_blank&#34;&gt;reference&lt;/a&gt; suggests that macros can&amp;rsquo;t be referenced and exported alongside functions
And that &lt;code&gt;macro&lt;/code&gt; is supposed to be used only as file-local macros, and thus these can&amp;rsquo;t be exported.
Additionally to that, when writing &lt;a href=&#34;https://fennel-lang.org/reference#macros-define-several-macros&#34; target=&#34;_blank&#34;&gt;macros&lt;/a&gt;, we can&amp;rsquo;t access any surrounding code.
The reference section then says that in order to export macros we can put them into a separate module and use &lt;code&gt;import-macros&lt;/code&gt; to import them to the arbitrary code.&lt;/p&gt;
&lt;p&gt;The whole macro system in Fennel is not as advanced as in other lisps or as in Elixir, but it gets the job done, it just requires some squats to be done.&lt;/p&gt;
&lt;h3 id=&#34;macro-modules&#34;&gt;Macro modules&lt;/h3&gt;
&lt;p&gt;A macro module is exactly the same as an ordinary Fennel module - it shares the same file extension, same syntax, but is meant to be used in conjunction with &lt;code&gt;import-macros&lt;/code&gt; or &lt;code&gt;require-macros&lt;/code&gt; specials.
To write a macro module we can simply put our &lt;code&gt;unless&lt;/code&gt; macro into a separate file, replacing &lt;code&gt;macro&lt;/code&gt; with &lt;code&gt;fn&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; unless.fnl&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;unless&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;test&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  `(&lt;span style=&#34;font-weight:bold&#34;&gt;when &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;not &lt;/span&gt;&lt;span style=&#34;&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;test&lt;/span&gt;) &lt;span style=&#34;&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:unless&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;unless&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That&amp;rsquo;s right, in Fennel, macros are ordinary functions running in a compiler environment, and now we actually can export them as an ordinary table.
The compiler environment defines additional functions that we can use in macros, such as &lt;code&gt;quote&lt;/code&gt; and &lt;code&gt;unquote&lt;/code&gt; which we&amp;rsquo;re using here in the forms of &lt;code&gt;`&lt;/code&gt; and &lt;code&gt;,&lt;/code&gt;.
Now we can require this module with &lt;code&gt;import-macros&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;import-macros &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Unless&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:unless&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Unless.unless&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;true&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;print &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;this should never be printed&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Unless.unless&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;false&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;print &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;this should be printed&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;this&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;should&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;be&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;printed&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;There&amp;rsquo;s also another special that can import macros from a module: &lt;code&gt;require-macros&lt;/code&gt;.
Unlike &lt;code&gt;import-macros&lt;/code&gt; it doesn&amp;rsquo;t put macros in a binding, instead, it pollutes the current scope with all of the macros from the module:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;require-macros &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:unless&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;unless&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;true&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;print &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;this should be printed&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So &lt;code&gt;(import-macros name module)&lt;/code&gt; is much like &lt;code&gt;(local name (require module))&lt;/code&gt; but for macro modules, and it uses &lt;code&gt;require-macros&lt;/code&gt; underneath.&lt;/p&gt;
&lt;h3 id=&#34;import-macros-and-require&#34;&gt;&lt;code&gt;import-macros&lt;/code&gt; and &lt;code&gt;require&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Speaking of the relationship between &lt;code&gt;import-macros&lt;/code&gt; and &lt;code&gt;require&lt;/code&gt;, they indeed work similarly.
Fennel&amp;rsquo;s developers understood that Lua&amp;rsquo;s module system is very flexible and decided to make a similar interface for macros.&lt;/p&gt;
&lt;p&gt;You couldn&amp;rsquo;t see it, but in the previous example, when I called &lt;code&gt;require-macros&lt;/code&gt; on the &lt;code&gt;unless&lt;/code&gt; module again, it didn&amp;rsquo;t re-read the module from disk.
Instead, it used the same technique of caching, much like &lt;code&gt;package.loaded&lt;/code&gt; but instead, it uses &lt;code&gt;fennel.macro-loaded&lt;/code&gt; to store macros.
We can see that by requiring Fennel in the REPL and inspecting the table:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fennel&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:fennel&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fennel.macro-loaded&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:unless&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:unless&lt;/span&gt; #&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;function&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x56224adc40a0&amp;gt;&lt;/span&gt;}}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We can even do the same thing as with the &lt;code&gt;package.loaded&lt;/code&gt;, and set the &lt;code&gt;unless&lt;/code&gt; module to &lt;code&gt;nil&lt;/code&gt; with &lt;code&gt;(set fennel.macro-loaded.unless nil)&lt;/code&gt;
If we then add some side-effecting code, like &lt;code&gt;(print &amp;quot;macros!&amp;quot;)&lt;/code&gt; to the module, and require it again, we&amp;rsquo;ll see that Fennel will re-read our module:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fennel.macro-loaded.unless&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;import-macros &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Unless&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:unless&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;macros!&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;import-macros &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Unless&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:unless&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;But only once, much like with ordinary &lt;code&gt;require&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Similarly to Lua, Fennel provides its own table with searcher functions for macros:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fennel.macro-searchers&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[#&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;function&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x56224ac5a740&amp;gt;&lt;/span&gt; #&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;function&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x56224ac5a7f0&amp;gt;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So the system is extremely similar, the only thing it lacks is something akin to &lt;code&gt;package.preload&lt;/code&gt; but for macros.
With that in mind let me introduce you to the library problem.&lt;/p&gt;
&lt;h3 id=&#34;the-library-problem&#34;&gt;The library problem&lt;/h3&gt;
&lt;p&gt;Let&amp;rsquo;s imagine, we want to write a library that provides you with a lot of functions, and with some convenience macros that remove some boilerplate.
In reality, almost anything can be done without macros, but macros are great for writing code that you don&amp;rsquo;t want to write yourself.
So let&amp;rsquo;s say we want to add polymorphic dispatch to Fennel by adding multimethods.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s write the functions first:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;multi&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dispatch-fn&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;methods&lt;/span&gt; {}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;setmetatable&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:add-method&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dispatch-val&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fn1&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    (&lt;span style=&#34;font-weight:bold&#34;&gt;tset &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;methods&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dispatch-val&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fn1&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:get-method&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dispatch-val&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    (&lt;span style=&#34;font-weight:bold&#34;&gt;. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;methods&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dispatch-val&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:remove-method&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dispatch-val&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                       (&lt;span style=&#34;font-weight:bold&#34;&gt;tset &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;methods&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dispatch-val&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;))}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:__call&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;method&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self.get-method&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dispatch-fn&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;method&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;)))})))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;add-method&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;multi&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dispatch-val&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;method&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;multi.add-method&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dispatch-val&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;method&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;get-method&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;multi&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dispatch-val&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;multi.get-method&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dispatch-val&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;remove-method&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;multi&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dispatch-val&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;multi.remove-method&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dispatch-val&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:multi&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;multi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:add-method&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;add-method&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:get-method&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;get-method&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:remove-method&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;remove-method&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The idea is simple.
We create an object with the function &lt;code&gt;multi&lt;/code&gt; and give it a &lt;code&gt;dispatch-fn&lt;/code&gt; - the function it will invoke with the arguments to determine what method it needs to call.
If there is a method, it will be called with the same arguments as the &lt;code&gt;dispatch-fn&lt;/code&gt; functions.
I also provided convenience functions that provide some abstraction over the inner implementation of the multimethod object.
Let&amp;rsquo;s try it:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mult&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:multimethods&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;interact&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mult.multi&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt;] (&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a.type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b.type&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mult.add-method&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;interact&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;bunny lion&amp;#34;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bunny&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lion&lt;/span&gt;] &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;bunny runs away&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mult.add-method&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;interact&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;lion bunny&amp;#34;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lion&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bunny&lt;/span&gt;] &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;lion eats bunny&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mult.add-method&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;interact&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;lion lion&amp;#34;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lion1&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lion2&lt;/span&gt;] &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;lions fight&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mult.add-method&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;interact&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;bunny bunny&amp;#34;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bunny1&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bunny2&lt;/span&gt;] &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;bunnies mate&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;interact&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;bunny&amp;#34;&lt;/span&gt;} {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;lion&amp;#34;&lt;/span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;bunny runs away&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;interact&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;lion&amp;#34;&lt;/span&gt;} {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;bunny&amp;#34;&lt;/span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;lion eats bunny&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I opted for a simple example, where I just get the &lt;code&gt;type&lt;/code&gt; field of each object and concatenate them into a string.
Then we dispatch on that string.&lt;/p&gt;
&lt;p&gt;The library is now complete, but it&amp;rsquo;s a bit tedious to type all of these anonymous functions every time, let&amp;rsquo;s add an interface similar to how Clojure does this.
We&amp;rsquo;ll add two macros &lt;code&gt;defmulti&lt;/code&gt;, which given a name and a dispatch fn will create a local variable by itself, and &lt;code&gt;defmethod&lt;/code&gt; which will act the same as &lt;code&gt;add-method&lt;/code&gt; except it will construct the anonymous function for us.
We start by creating the macro module:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;defmulti&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dispatch-fn&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  `(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mult.multi&lt;/span&gt; &lt;span style=&#34;&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dispatch-fn&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;defmethod&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dispatch-val&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  `(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mult.add-method&lt;/span&gt; &lt;span style=&#34;&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt; &lt;span style=&#34;&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dispatch-val&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:defmulti&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;defmulti&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:defmethod&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;defmethod&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We already have the multimethod itself, so let&amp;rsquo;s try our &lt;code&gt;defmethod&lt;/code&gt; macro:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;require-macros &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:multimethod-macros&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;defmethod&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;interact&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;ship rock&amp;#34;&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ship&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_rock&lt;/span&gt;] (&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ship.name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; sinks&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;interact&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;ship&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Wasa&amp;#34;&lt;/span&gt;} {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;rock&amp;#34;&lt;/span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Wasa sinks&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It works, but did you notice the problem?
Let&amp;rsquo;s try this again, but instead, let&amp;rsquo;s call our library something else in the REPL:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mmethods&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:multimethods&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;require-macros &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:multimethod-macros&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;defmulti&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;interact&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt;] (&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a.type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b.type&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;unknown&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:2:?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Compile&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;error&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;unknown&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;identifier&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mult&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Looking into the macroexpansion of &lt;code&gt;defumilti&lt;/code&gt; we see that it does exactly what we told it:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;macrodebug &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;defmulti&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;interact&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt;] (&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a.type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b.type&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;interact&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mult.multi&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt;] (&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a.type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b.type&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Except, the &lt;code&gt;mult&lt;/code&gt; is nowhere to be found.&lt;/p&gt;
&lt;p&gt;So, here&amp;rsquo;s the problem - we need to reuse functions from our function module in the macro module.
Unfortunately, there&amp;rsquo;s literally no way to do it without making some assumptions about the module name.
Instead of using available binding in the macro, we can require the library because it&amp;rsquo;s cached:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;defmulti&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dispatch-fn&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  `(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mmethods#&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:multimethods&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mmethods#.multi&lt;/span&gt; &lt;span style=&#34;&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dispatch-fn&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;defmethod&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dispatch-val&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  `(&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mmethods#&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:multimethods&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mmethods#.add-method&lt;/span&gt; &lt;span style=&#34;&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt; &lt;span style=&#34;&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dispatch-val&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:defmulti&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;defmulti&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:defmethod&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;defmethod&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With this change, everything starts working:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mmethods&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:multimethods&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;require-macros &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:multimethod-macros&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;defmethod&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;interact&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;ship rock&amp;#34;&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ship&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_rock&lt;/span&gt;] (&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ship.name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; sinks&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;interact&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;ship&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Wasa&amp;#34;&lt;/span&gt;} {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;rock&amp;#34;&lt;/span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Wasa sinks&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;But there&amp;rsquo;s another problem - what if the user of our library doesn&amp;rsquo;t like that the module file name is &lt;code&gt;multimethods.fnl&lt;/code&gt; and wants to rename it?
Suppose they already have their own multimethods module and want to try out ours alongside it, so they rename it to &lt;code&gt;aorst-multimethods.fnl&lt;/code&gt;.
Required macros will suddenly stop working because in our macros we hardcoded the &lt;code&gt;multimethods&lt;/code&gt; module name.&lt;/p&gt;
&lt;h4 id=&#34;init-dot-fnl-and-init-macros-dot-fnl&#34;&gt;&lt;code&gt;init.fnl&lt;/code&gt; and &lt;code&gt;init-macros.fnl&lt;/code&gt;&lt;/h4&gt;
&lt;p&gt;One solution to this problem is to use Lua&amp;rsquo;s other hidden module mechanic, related to how the searchers work.&lt;/p&gt;
&lt;p&gt;In Lua, we can load a file by giving &lt;code&gt;require&lt;/code&gt; a module name that matches that file, like &lt;code&gt;require &amp;quot;foo&amp;quot;&lt;/code&gt; will probably load the &lt;code&gt;foo.lua&lt;/code&gt; file.
However, we can also load a directory in the same way - instead of creating &lt;code&gt;foo.lua&lt;/code&gt; we can create a directory &lt;code&gt;foo&lt;/code&gt; and write the contents of &lt;code&gt;foo.lua&lt;/code&gt; into &lt;code&gt;foo/init.lua&lt;/code&gt;.
Then, calling &lt;code&gt;require &amp;quot;foo&amp;quot;&lt;/code&gt; will seamlessly load code from &lt;code&gt;init.lua&lt;/code&gt;, but it will look like we&amp;rsquo;re loaded a directory.&lt;/p&gt;
&lt;p&gt;Fennel supports the same thing for ordinary modules with &lt;code&gt;init.fnl&lt;/code&gt;, but in addition to that, it also supports this for macro modules with &lt;code&gt;init-macros.fnl&lt;/code&gt;.
We can re-implement our multimethod library this way, but we&amp;rsquo;ll change how we require the library in the macros:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; multimethods-lib/init-macros.fnl&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lib-module&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;) &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; for relative require&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;defmulti&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dispatch-fn&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  `(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mmethods#&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lib-module&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mmethods#.multi&lt;/span&gt; &lt;span style=&#34;&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dispatch-fn&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;defmethod&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dispatch-val&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  `(&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mmethods#&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lib-module&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mmethods#.add-method&lt;/span&gt; &lt;span style=&#34;&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt; &lt;span style=&#34;&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dispatch-val&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:defmulti&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;defmulti&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:defmethod&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;defmethod&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This trick is called relative-require.
It&amp;rsquo;s quite common in Lua, but I decided to use it when I was trying to ship huge libraries with lots of macros and inner modules.&lt;/p&gt;
&lt;p&gt;When the module is loaded, Lua passes the module name to the module as an argument.
This &lt;code&gt;(local lib-module ...)&lt;/code&gt; captures it in the &lt;code&gt;lib-module&lt;/code&gt; variable, and then we can refer to it in our macros.
If we now look at what our macros expand to, we&amp;rsquo;ll see that they use the module name correctly:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mmethods&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:multimethods-lib&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;require-macros &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:multimethods-lib&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;macrodebug &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;defmulti&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;interact&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt;] (&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a.type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b.type&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;interact&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mmethods_2_auto&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;multimethods-lib&amp;#34;&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mmethods_2_auto.multi&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt;] (&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a.type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b.type&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now our macros are unbound from the library name itself.
However, shipping library in this way is not that great.
For example, here&amp;rsquo;s how one of my libraries that uses this technique looks if you peek into the library root:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;├── CHANGELOG.md
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;├── CODE_OF_CONDUCT.md
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;├── CONTRIBUTING.md
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;├── doc/
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;├── fennel-test/
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;├── impl/
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;├── init.fnl
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;├── init-macros.fnl
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;├── LICENSE
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;├── Makefile
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;├── README.md
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;└── tests/
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Basically, it&amp;rsquo;s the project&amp;rsquo;s root, and if you want to use this library, the easiest way is to just git-clone the project and require it.
But it means that there are lots of unrelated files, and there&amp;rsquo;s no way to know what files are related unless the project has some kind of manifest, which is not the case for Fennel projects.
It would be much better if you could just grab only the &lt;code&gt;init.fnl&lt;/code&gt; file, name it however you want, and require both macros and functions from it.&lt;/p&gt;
&lt;h4 id=&#34;require-as-include&#34;&gt;Require-as-include&lt;/h4&gt;
&lt;p&gt;Fennel has a feature that can do almost that.
For multi-file libraries, we can AOT compile all of the Fennel code into Lua, and the compiler will inject all of the dependencies in an interesting way.
It does so by tracking what modules we &lt;code&gt;require&lt;/code&gt; and splicing them into the code by using &lt;code&gt;package.preload&lt;/code&gt; trick I&amp;rsquo;ve described way earlier in this post:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;foo&lt;/span&gt; []
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;some-lib&amp;#39;s foo&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;foo&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;some-lib&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:some-lib&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;my-foo&lt;/span&gt; []
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;some-lib.foo&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:my-foo&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;my-foo&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If we call &lt;code&gt;fennel --require-as-include -c my-lib.fnl&lt;/code&gt;, we&amp;rsquo;ll get the following code:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; some_lib
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;package.preload[&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;some-lib&amp;#34;&lt;/span&gt;] = package.preload[&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;some-lib&amp;#34;&lt;/span&gt;] &lt;span style=&#34;font-weight:bold&#34;&gt;or&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt;(...)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;foo&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;some-lib&amp;#39;s foo&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; {foo = foo}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;some_lib = require(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;some-lib&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;my_foo&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; some_lib.foo()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; {[&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;my-foo&amp;#34;&lt;/span&gt;] = my_foo}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As can be seen, the whole module definition of &lt;code&gt;some-lib&lt;/code&gt; was included in the file as an entry in the &lt;code&gt;package.preload&lt;/code&gt;.
In the later code, it is required and used as normal.&lt;/p&gt;
&lt;p&gt;However, this doesn&amp;rsquo;t work with macros, as there is no &lt;code&gt;fennel.macro-preloaded&lt;/code&gt; or something similar.
And for a long enough time, I wasn&amp;rsquo;t sure if it was possible to mimic this behavior at compile time.
But then I remembered that we indeed have the module name at compile time, as clearly shown in the relative-require example.&lt;/p&gt;
&lt;h3 id=&#34;mimicking-preload-behavior-for-macros&#34;&gt;Mimicking preload behavior for macros&lt;/h3&gt;
&lt;p&gt;Here&amp;rsquo;s what I came up with:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;eval-compiler&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lib-module&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;defmulti&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dispatch-fn&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    `(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mmethods#&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lib-module&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mmethods#.multi&lt;/span&gt; &lt;span style=&#34;&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dispatch-fn&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;defmethod&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dispatch-val&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    `(&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mmethods#&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lib-module&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mmethods#.add-method&lt;/span&gt; &lt;span style=&#34;&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt; &lt;span style=&#34;&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dispatch-val&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;tset &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;macro-loaded&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lib-module&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:defmulti&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;defmulti&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:defmethod&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;defmethod&lt;/span&gt;}))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;multi&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dispatch-fn&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;methods&lt;/span&gt; {}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;setmetatable&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:add-method&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dispatch-val&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fn1&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    (&lt;span style=&#34;font-weight:bold&#34;&gt;tset &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;methods&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dispatch-val&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fn1&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:get-method&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dispatch-val&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    (&lt;span style=&#34;font-weight:bold&#34;&gt;. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;methods&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dispatch-val&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:remove-method&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dispatch-val&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                       (&lt;span style=&#34;font-weight:bold&#34;&gt;tset &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;methods&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dispatch-val&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;))}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:__call&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;method&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self.get-method&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dispatch-fn&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;method&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;)))})))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;add-method&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;multi&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dispatch-val&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;method&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;multi.add-method&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dispatch-val&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;method&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;get-method&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;multi&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dispatch-val&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;multi.get-method&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dispatch-val&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;remove-method&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;multi&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dispatch-val&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;multi.remove-method&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dispatch-val&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:multi&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;multi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:add-method&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;add-method&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:get-method&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;get-method&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:remove-method&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;remove-method&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Finally, we can require our library and macros from the same module, and it doesn&amp;rsquo;t have to be a directory!
Here&amp;rsquo;s how it looks:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mm&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:combined-multimethods&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;require-macros &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:combined-multimethods&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;defmulti&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;interact&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt;] (&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a.type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b.type&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;defmethod&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;interact&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;ship rock&amp;#34;&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ship&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_rock&lt;/span&gt;] (&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ship.name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; sinks&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;interact&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;ship&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Wasa&amp;#34;&lt;/span&gt;} {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;rock&amp;#34;&lt;/span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Wasa sinks&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So, it&amp;rsquo;s a combination of techniques, but what exactly is &lt;code&gt;eval-compiler&lt;/code&gt; doing here?&lt;/p&gt;
&lt;p&gt;If you look closely at &lt;code&gt;evel-compiler&lt;/code&gt; body, you&amp;rsquo;ll see that instead of exporting the table at the end of the scope we simply set it to the &lt;code&gt;macro-loaded&lt;/code&gt; table.
We use the module name which was set to &lt;code&gt;combined-multimethods&lt;/code&gt; when the module was required, and thus the &lt;code&gt;macro-loaded.combined-multimethods&lt;/code&gt; now stores the table with macro definitions.
Then, when &lt;code&gt;require-macros&lt;/code&gt; looks up the macro module &lt;code&gt;combined-multimethods&lt;/code&gt;, it sees that it was already loaded, and simply returns it without trying to find a file with these macros.
Alternatively, we could define a macro-searcher that, given a specific &lt;code&gt;module-name&lt;/code&gt; would do the same thing, loading macros while avoiding trying to find a file, but it&amp;rsquo;s more work for almost no benefit over what we have here already.&lt;/p&gt;
&lt;h4 id=&#34;preprocessor-as-include&#34;&gt;Preprocessor-as-include&lt;/h4&gt;
&lt;p&gt;There&amp;rsquo;s still a problem though.
What if we want to write a library, that uses another library, that uses macros in this way?&lt;/p&gt;
&lt;p&gt;One such example is my &lt;a href=&#34;https://gitlab.com/andreyorst/fennel-cljlib&#34; target=&#34;_blank&#34;&gt;cljlib&lt;/a&gt; library I keep re-implementing every few months or so.
In that library I also wanted to ship macros and functions in the same module, but here&amp;rsquo;s a problem - this library depends on other libraries, namely &lt;a href=&#34;https://gitlab.com/andreyorst/lazy-seq&#34; target=&#34;_blank&#34;&gt;lazy-seq&lt;/a&gt; and &lt;a href=&#34;https://gitlab.com/andreyorst/itable&#34; target=&#34;_blank&#34;&gt;itable&lt;/a&gt;.
While &lt;code&gt;itable&lt;/code&gt; doesn&amp;rsquo;t provide any macros, &lt;code&gt;lazy-seq&lt;/code&gt; does, and &lt;code&gt;cljlib&lt;/code&gt; re-uses these macros.&lt;/p&gt;
&lt;p&gt;Before some recent changes I made to both &lt;code&gt;lazy-seq&lt;/code&gt; and &lt;code&gt;cljlib&lt;/code&gt; you had to fiddle with &lt;code&gt;FENNEL_PATH&lt;/code&gt; and &lt;code&gt;FENNEL_MACRO_PATH&lt;/code&gt; in order to use &lt;code&gt;cljlib&lt;/code&gt;, and you had to check out the full repository with submodules.
I feel like this is way too much work for most people, and I don&amp;rsquo;t want anyone to suffer that much, so I changed it to use the trick above and embedded other libraries into it by manually writing the &lt;code&gt;package.preload&lt;/code&gt; trick instead of relying on &lt;code&gt;--require-as-include&lt;/code&gt; flag.
Here&amp;rsquo;s how it looks in the &lt;code&gt;src/cljlib.fnl&lt;/code&gt; file:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;;; itable&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;package.preload.itable&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;package.preload.itable&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;;;###include itable/src/itable.fnl&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        )))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;;; lazy-seq&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;package.preload.lazy-seq&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;package.preload.lazy-seq&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;;;###include lazy-seq/lazy-seq.fnl&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        )))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;;; cljlib&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;eval-compiler&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lib-name&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:cljlib&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; macros ...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  )
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; functions ...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;These &lt;code&gt;;;;###include path&lt;/code&gt; comments are nothing special from the perspective of Fennel, but I made a small &lt;code&gt;build.fnl&lt;/code&gt; script for the library that takes care of them:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;spit-lib&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;path&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;to&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;with-open &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lib&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;io.open &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;path&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;each &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lib&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:lines&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; patching compile-time variable used to store macro module&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; name because when loafing the combined file it will always&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; equal the main module and will break macros in vendored&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; libraries.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;case&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:match&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;%(local lib%-name %(or %.%.%. (.*)&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;to&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:write&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;(local lib-name (or &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\n&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;to&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:write&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\n&amp;#34;&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;with-open &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cljlib&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;io.open &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;./cljlib.fnl&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:w&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;main&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;io.open &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;src/cljlib.fnl&amp;#34;&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;each &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;main&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:lines&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;case&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:match&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;;;;###include (.*)&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;path&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;spit-lib&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;path&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cljlib&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cljlib&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:write&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\n&amp;#34;&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It is meant to be used only for development, the library is pre-built and ready for anyone to grab.
What&amp;rsquo;s interesting about this script is that it also patches the library it includes.
This was a pain to figure out.&lt;/p&gt;
&lt;p&gt;You see, in the &lt;code&gt;lazy-seq&lt;/code&gt; library I&amp;rsquo;m using the same &lt;code&gt;eval-compiler&lt;/code&gt; trick, and it in turn uses the &lt;code&gt;(local lib-name (or ... :lazy-seq))&lt;/code&gt; trick.
However, when this library is spliced into our main file as is, when we load this file as &lt;code&gt;(require :cljlib)&lt;/code&gt;, the &lt;code&gt;...&lt;/code&gt; becomes &lt;code&gt;&amp;quot;cljlib&amp;quot;&lt;/code&gt;, and the &lt;code&gt;lazy-seq&lt;/code&gt; library, included in this file will write its macros into &lt;code&gt;macro-loaded.cljlib&lt;/code&gt; instead of supposed &lt;code&gt;macro-loaded.lazy-seq&lt;/code&gt;.
This can&amp;rsquo;t be worked around, as this happens way before &lt;code&gt;package.preload.lazy-seq&lt;/code&gt; runs, so the &lt;code&gt;...&lt;/code&gt; provided by the function in that table is never used by &lt;code&gt;eval-compiler&lt;/code&gt;.
The only way to delay the &lt;code&gt;eval-compiler&lt;/code&gt; is to put it into the file or use the searcher that will evaluate this block of code by itself which is way too tricky.&lt;/p&gt;
&lt;p&gt;So I made a hack, that while splicing the library code scans for any occurrences of the &lt;code&gt;(local lib-name (or ...&lt;/code&gt; pattern, and replaces it with the name used in the &lt;code&gt;or&lt;/code&gt; expression, without checking &lt;code&gt;...&lt;/code&gt;.
This way, the &lt;code&gt;(local lib-name (or ... :lazy-seq))&lt;/code&gt; becomes &lt;code&gt;(local lib-name (or :lazy-seq))&lt;/code&gt; in the final version of &lt;code&gt;cljlib.fnl&lt;/code&gt;.
Of course, it is extremely finicky, as even an introduction of a newline between &lt;code&gt;lib-name&lt;/code&gt; and &lt;code&gt;(or ...)&lt;/code&gt; expression will break this.
Changing &lt;code&gt;lib-name&lt;/code&gt; to something else will also break this down.&lt;/p&gt;
&lt;p&gt;But even with this kind of monkey-patching it works well enough, as I control what code goes in both libraries, and the user doesn&amp;rsquo;t need to think about it at all.
All that is needed to do is just to grab the &lt;code&gt;cljlib.fnl&lt;/code&gt; from the repo root and put it into the project.
I&amp;rsquo;ve updated &lt;a href=&#34;https://gitlab.com/andreyorst/fenneldoc&#34; target=&#34;_blank&#34;&gt;Fenneldoc&lt;/a&gt; to use the newer version of &lt;code&gt;cljlib&lt;/code&gt; and was pleased to see that it still works.&lt;/p&gt;
&lt;h2 id=&#34;fixing-macros-in-fennel&#34;&gt;Fixing macros in Fennel&lt;/h2&gt;
&lt;p&gt;Even with the ability to ship macros in the same file as functions, I find it weird that Fennel&amp;rsquo;s macro system has all sorts of other limitations.&lt;/p&gt;
&lt;p&gt;Firstly, the inability to use functions defined alongside macros is really bad.
This is one of the reasons we have to do all these squats with relative-require stuff and require the library itself from the macro.
Which in turn makes us more error-prone, if some weird environment will not set the module args (&lt;code&gt;...&lt;/code&gt;) properly.&lt;/p&gt;
&lt;p&gt;Another thing is that macros can&amp;rsquo;t use other macros unless they&amp;rsquo;re defined in a separate module, or in the &lt;code&gt;eval-compiler&lt;/code&gt; trick I was featuring in this post.
If you define a macro with the &lt;code&gt;macro&lt;/code&gt; special, it must be self-contained.
Otherwise, you have to move it somewhere.
I mean, it&amp;rsquo;s weird that Fennel has a proper implementation of macros sitting in the compiler, but for some reason &lt;code&gt;macro&lt;/code&gt; and &lt;code&gt;macros&lt;/code&gt; specials don&amp;rsquo;t use it.&lt;/p&gt;
&lt;p&gt;What I think would fix all this mess is this:&lt;/p&gt;
&lt;p&gt;First, we need to ditch macro modules completely.
They&amp;rsquo;re inferior to ordinary fennel modules and only make things complicated.&lt;/p&gt;
&lt;p&gt;Next, we need to make it so the &lt;code&gt;macro&lt;/code&gt; special sets the macro in the &lt;code&gt;macro-loaded&lt;/code&gt; entry of the current module, much like I manually do in the &lt;code&gt;eval-compiler&lt;/code&gt; block.&lt;/p&gt;
&lt;p&gt;And lastly, when compiling the module to Lua, just load the module at compile time as a whole!
This way not only macros will be able to use other macros, but they&amp;rsquo;ll also be able to use other ordinary functions at compile time!&lt;/p&gt;
&lt;p&gt;The only problem left is how to make it so the generated code can use definitions from the library.
And I think I know the way, and it&amp;rsquo;s similar to how Clojure handles things.&lt;/p&gt;
&lt;p&gt;So basically, same as in Clojure, macros can only use public definitions.
What this means is that these definitions are in the &lt;code&gt;packagr.loaded&lt;/code&gt; by the time we&amp;rsquo;ve required the library.
Therefore, the backquote can safely fully qualify any unqualified symbol in the calling position!&lt;/p&gt;
&lt;p&gt;In other words, the macro &lt;code&gt;bar&lt;/code&gt; from this file:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;foo&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;val&lt;/span&gt;] &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;val&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;macro &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bar&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;expr&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  `(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;foo&lt;/span&gt; &lt;span style=&#34;&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;expr&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:foo&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;foo&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;After macroexpanding will become:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;require-macros &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;doto &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:lib&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;require&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;macrodebug &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bar&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;1 2 3)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;package.loaded.lib.foo&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;1 2 3))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And will work just fine, as it can reach &lt;code&gt;foo&lt;/code&gt;, as it is already in the &lt;code&gt;package.loaded&lt;/code&gt; by that time.
Which is similar to what Clojure does:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;foo&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;val&lt;/span&gt;] &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;val&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;user/foo&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defmacro &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bar&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;expr&lt;/span&gt;] `(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;foo&lt;/span&gt; ~&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;expr&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;user/bar&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;macroexpand &lt;/span&gt;&amp;#39;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bar&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;+ &lt;/span&gt;1 2 3)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user/foo&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;+ &lt;/span&gt;1 2 3))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And as the final change, we need to make that the &lt;code&gt;fennel.searcher&lt;/code&gt; properly sets up &lt;code&gt;macro-loaded&lt;/code&gt; in order to ditch the awkward &lt;code&gt;(doto :lib require)&lt;/code&gt; thing.&lt;/p&gt;
&lt;p&gt;Anyhow, that&amp;rsquo;s all I got for today.
I know that I&amp;rsquo;m writing a lot of devlog posts about my small game dev marathon, so I try to write some posts in-between so that my blog doesn&amp;rsquo;t become too focused on one topic.
Hope that this was an interesting read!&lt;/p&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: Fennel libraries as single files&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Sun, 27 Aug 2023 20:45:00 +0300</pubDate>
    </item><item>
      <title>async.fnl enchancements</title>
      <link>https://andreyor.st/posts/2023-08-02-asyncfnl-enchancements/</link>
      <guid>https://andreyor.st/posts/2023-08-02-asyncfnl-enchancements/</guid>
      <description>&lt;p&gt;Lately, I&amp;rsquo;ve been working on &lt;a href=&#34;https://gitlab.com/andreyorst/async.fnl&#34; target=&#34;_blank&#34;&gt;async.fnl&lt;/a&gt; in my spare time and realized that the previous code that I used to schedule timers was terrible.
Well, &lt;em&gt;realized&lt;/em&gt; isn&amp;rsquo;t an appropriate word here, because I knew it back when I first implemented it, I just didn&amp;rsquo;t bother to make it better until I had a fully working library.
So, a few weeks ago I had an idea on how to make things both more efficient and prevent excessive CPU usage when there&amp;rsquo;s no need to.&lt;/p&gt;
&lt;h2 id=&#34;lua-debug-hooks&#34;&gt;Lua &lt;code&gt;debug&lt;/code&gt; hooks&lt;/h2&gt;
&lt;p&gt;Lua comes with the &lt;a href=&#34;https://www.lua.org/manual/5.4/manual.html#6.10&#34; target=&#34;_blank&#34;&gt;debug&lt;/a&gt; library.
This library provides a set of relatively low-level facilities to implement your own debugger, and one such things are hooks.&lt;/p&gt;
&lt;p&gt;All hook manipulations are done with &lt;a href=&#34;https://www.lua.org/manual/5.4/manual.html#pdf-debug.sethook&#34; target=&#34;_blank&#34;&gt;debug.sethook&lt;/a&gt; and &lt;a href=&#34;https://www.lua.org/manual/5.4/manual.html#pdf-debug.gethook&#34; target=&#34;_blank&#34;&gt;debug.gethook&lt;/a&gt; functions - one to set/unset the hook, and the other to retrieve existing hook, respectively.
A hook is a simple Lua function, that accepts the &lt;code&gt;event&lt;/code&gt; which triggered it.
Lua gives us five types of events we can check for in our hook: &lt;code&gt;&amp;quot;call&amp;quot;&lt;/code&gt;, &lt;code&gt;&amp;quot;tail call&amp;quot;&lt;/code&gt;, &lt;code&gt;&amp;quot;return&amp;quot;&lt;/code&gt;, &lt;code&gt;&amp;quot;line&amp;quot;&lt;/code&gt;, and &lt;code&gt;&amp;quot;count&amp;quot;&lt;/code&gt;, but we&amp;rsquo;re only really interested in one - the &lt;code&gt;&amp;quot;count&amp;quot;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;But before we discuss hooks, I&amp;rsquo;d like to do a small detour into how my old async library handled things.
It will both allow you to understand why I decided to move away from the old implementation, and how we can use hooks to achieve similar facilities later.
Feel free to &lt;a href=&#34;#hooks--the-less-wrong-way&#34;&gt;skip&lt;/a&gt; if you&amp;rsquo;re not interested.&lt;/p&gt;
&lt;h3 id=&#34;scheduler&#34;&gt;Scheduler&lt;/h3&gt;
&lt;p&gt;Here&amp;rsquo;s how asynchronous threads were handled in an older implementation of my other async library.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The library had a special scheduler object, that kept track of all tasks to be run.&lt;/li&gt;
&lt;li&gt;Each task that wanted to stop itself for some time is called the &lt;code&gt;async.park&lt;/code&gt; function, usually indirectly via something like &lt;code&gt;async.take&lt;/code&gt; or &lt;code&gt;async.put&lt;/code&gt;.
&lt;ul&gt;
&lt;li&gt;additionally, If a task wants to sleep for some time, it can call &lt;code&gt;async.sleep&lt;/code&gt;, which, when called on the asynchronous thread, parks it with a special condition, and tells the scheduler that this task should not be touched for the specified amount of time.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Then, once the internal &lt;code&gt;scheduler.run&lt;/code&gt; is called, all tasks are examined, and the shortest amount of sleep is chosen, if any.
&lt;ul&gt;
&lt;li&gt;If there are tasks that aren&amp;rsquo;t sleeping, the system resumes those tasks;&lt;/li&gt;
&lt;li&gt;If, however, all tasks want to sleep, the system determines the minimum amount of time it needs to sleep and puts the main thread to sleep.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Once all tasks ran, the &lt;code&gt;scheduler.sleep&lt;/code&gt; exits unless the user requested it to run until all tasks are fully complete.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This worked reasonably fine but required someone to call the &lt;code&gt;scheduler.run&lt;/code&gt; periodically.
The library tried to make it transparent for the program, as any operation that created threads, pushed or polled for values, and so on, called &lt;code&gt;shceduler.run&lt;/code&gt; internally, to give an illusion that the system actually works in parallel.
Thus, if you made a blocking take on some channel, the &lt;code&gt;scheduler&lt;/code&gt; would run until that channel is ready to return the value (though, this might never happen).&lt;/p&gt;
&lt;p&gt;The main downside of this was that the whole system depends on a central scheduling mechanism, and the more tasks you have spawned, the less performant the scheduler becomes.
For example, here&amp;rsquo;s a function, that tracks the amount of time it took for value to be put to a channel and then read back in another thread:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;{&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;gettime&lt;/span&gt;} (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:socket&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;{&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;put&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;close!&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;take&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chan&lt;/span&gt; &amp;amp;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;as&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;async&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:fennel-async.async&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bench&lt;/span&gt; []
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chan&lt;/span&gt; 1)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lock&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chan&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;var &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;put-time&lt;/span&gt; 0)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; a thread that loops putting the values one by one, and tracks&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; the time when it completed each put&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;async&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;font-weight:bold&#34;&gt;for &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; 1 10]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         (&lt;span style=&#34;font-weight:bold&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;put-time&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;gettime&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;put&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;close!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; a thread that takes values, and measures the amount of time it took&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; for value to be transferred.  Loops for more until the channel&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; is closed&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;async&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;loop&lt;/span&gt; []
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;val&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;take&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;val&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             (&lt;span style=&#34;font-weight:bold&#34;&gt;do &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;print &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;- &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;gettime&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;put-time&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;loop&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;close!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lock&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; waits til both threads are done&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;take&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lock&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Let&amp;rsquo;s call it:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;gt;&amp;gt; (bench)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;6.0796737670898e-05
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;1.1205673217773e-05
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;2.8848648071289e-05
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;9.0599060058594e-06
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;7.8678131103516e-06
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;9.0599060058594e-06
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;8.1062316894531e-06
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;9.0599060058594e-06
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;7.8678131103516e-06
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;2.6941299438477e-05
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;nil
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Pretty fast.
Now, let&amp;rsquo;s add &lt;em&gt;a few&lt;/em&gt; tasks that will immediately park because there&amp;rsquo;s no one to produce values, and will simply exist in a scheduler:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; create 10000 channels&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;channels&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fcollect&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; 1 10000] (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;async.chan&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; spawn 10000 tasks waiting on these channels&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;each &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chan&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;ipairs &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;channels&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;async&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[] (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;async.take&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chan&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This seemingly innocent &lt;code&gt;each&lt;/code&gt; loop took a whopping 148 seconds to execute on my machine!
It takes so much time because the library re-runs the scheduler over an ever-increasing number of tasks on every single call to &lt;code&gt;async&lt;/code&gt;.
So, it&amp;rsquo;s basically O(n²) loop even though it looks like O(n).&lt;/p&gt;
&lt;p&gt;Now, let&amp;rsquo;s call our function again:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;gt;&amp;gt; (bench)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;0.033475875854492
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;0.040903806686401
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;0.044415950775146
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;0.043467998504639
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;0.039731979370117
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;0.039532899856567
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;0.039582014083862
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;0.039039134979248
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;0.039515972137451
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;0.039596080780029
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;nil
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So, even though all of the threads were parked, and our &lt;code&gt;bench&lt;/code&gt; function doesn&amp;rsquo;t interact with any of them directly, its execution was slowed down &lt;strong&gt;severely&lt;/strong&gt;.
For a good measure, let&amp;rsquo;s release all those tasks by putting some values onto the channels with another loop &lt;code&gt;(each [_ c (ipairs channels)] (async.put c 42))&lt;/code&gt; (another 163 seconds to complete), and then re-run the &lt;code&gt;bench&lt;/code&gt; function, to check that it is fast again.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;gt;&amp;gt; (bench)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;0.00029706954956055
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;8.8214874267578e-06
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;9.7751617431641e-06
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;9.0599060058594e-06
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;9.0599060058594e-06
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;9.0599060058594e-06
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;6.1988830566406e-06
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;8.8214874267578e-06
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;1.5974044799805e-05
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;2.4080276489258e-05
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;nil
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And we&amp;rsquo;re back to being fast again.
Yay!..&lt;/p&gt;
&lt;p&gt;This is a major downside of the system that keeps track of all tasks - there&amp;rsquo;s no way of optimizing it because it has to check for all tasks every time - what if some tasks are no longer blocked and can advance?
We can&amp;rsquo;t even partition those tasks, because, as in the example above, the task is not related to timed events at all.
Because of that, I decided to re-implement the library from scratch, but I already &lt;a href=&#34;https://andreyor.st/posts/2023-05-15-clojures-coreasync-port-for-the-fennel-language/&#34;&gt;blogged&lt;/a&gt; about it.&lt;/p&gt;
&lt;h3 id=&#34;fake-it-til-you-actually-need-it&#34;&gt;Fake it til you actually need it&lt;/h3&gt;
&lt;p&gt;In the new version of the library, I avoided the scheduler altogether.
Well, there is a scheduler still, but unless you&amp;rsquo;re using &lt;code&gt;timeout&lt;/code&gt; channels, you can live completely without it (for the most part, that is).
BTW, I shouldn&amp;rsquo;t call it a new version of the library, it is simply a different library, but the facilities are largely the same for both, so we can compare them.&lt;/p&gt;
&lt;p&gt;First things first, let&amp;rsquo;s test the code from the above with the new library:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;import-macros &lt;/span&gt;{&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;go&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;go-loop&lt;/span&gt;} (&lt;span style=&#34;font-weight:bold&#34;&gt;doto &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:async&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;require&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;{&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;!&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;!&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;!!&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;close!&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chan&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;take!&lt;/span&gt;} (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:async&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;{&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;gettime&lt;/span&gt;} (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:socket&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bench&lt;/span&gt; []
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chan&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lock&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chan&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;var &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;put-time&lt;/span&gt; 0)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; a thread that loops putting the values one by one, and tracks&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; the time when it completed each put&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;go&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;for &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; 1 10]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;put-time&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;gettime&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;close!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; a thread that takes values, and measures the amount of time it took&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; for value to be transferred.  Loops for more until the channel&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; is closed&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;go-loop&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;val&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;val&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;font-weight:bold&#34;&gt;do &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;print &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;- &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;gettime&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;put-time&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;recur&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;close!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lock&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; waits til both threads are done&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;!!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lock&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;gt;&amp;gt; (bench)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;8.9883804321289e-05
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;4.6968460083008e-05
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;0.00019192695617676
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;4.6014785766602e-05
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;0.00013494491577148
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;1.8835067749023e-05
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;9.7990036010742e-05
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;2.0027160644531e-05
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;9.8943710327148e-05
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;3.0994415283203e-05
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;nil
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The overall speed is more or less the same but now, let&amp;rsquo;s repeat the same trick, again creating &lt;code&gt;10000&lt;/code&gt; channels, and registering a task on each of them:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; create 10000 channels&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;channels&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fcollect&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; 1 10000] (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chan&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; spawn 10000 tasks waiting on these channels&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;each &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;ipairs &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;channels&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;go&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Not only this code executes almost immediately, taking about a second, but this amount of channels also don&amp;rsquo;t affect our &lt;code&gt;bench&lt;/code&gt; function at all:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;gt;&amp;gt; (bench)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;0.00028419494628906
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;9.2029571533203e-05
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;0.00049304962158203
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;6.6041946411133e-05
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;0.00028800964355469
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;5.1021575927734e-05
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;0.00026488304138184
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;5.6982040405273e-05
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;0.00023293495178223
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;7.9870223999023e-05
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;nil
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So, what&amp;rsquo;s the trick?&lt;/p&gt;
&lt;p&gt;If we take a look at the internals of the library, there&amp;rsquo;s also a queue of dispatched tasks, called, well &lt;code&gt;dispatched-tasks&lt;/code&gt;.
We can load the library as a whole into the REPL and poke around:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;channels&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fcollect&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; 1 10000] (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chan&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;each &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;ipairs &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;channels&lt;/span&gt;)] (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;go&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dispatched-tasks&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;length &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;channels&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;10000
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;channels&lt;/span&gt; 1)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;ManyToManyChannel&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x55fbd1d328d0&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;channels&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:takes&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[#&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;reify&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x55fbd2cbb690&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Handler&amp;gt;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So, even though we&amp;rsquo;ve actually created &lt;code&gt;10000&lt;/code&gt; channels plus a 10000 of &lt;code&gt;go&lt;/code&gt; blocks, each of which is also a channel, and registered a pending take (&lt;code&gt;&amp;lt;!&lt;/code&gt;) on each one, no tasks were actually added to the &lt;code&gt;dispatched-tasks&lt;/code&gt; at all.
A task is only added to the scheduler when the channel is used!
In other words, once we put something onto a channel, that has a pending take, only then the task will be scheduled to execute:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;put!&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;channels&lt;/span&gt; 1) 42)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dispatched-tasks&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{#&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;function&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x55dcaf30ecb0&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;true&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This means that the work done by the scheduler is limited to the amount of resources really used by the program at a given point in time.
So our partitioning problem is gone.
There&amp;rsquo;s still another problem though - we need to run the scheduler somehow.&lt;/p&gt;
&lt;p&gt;Now we can talk about hooks.&lt;/p&gt;
&lt;h2 id=&#34;hooks--the-wrong-way&#34;&gt;Hooks (the wrong way)&lt;/h2&gt;
&lt;p&gt;Initially, when implementing this system I realized, that while the scheduler actually isn&amp;rsquo;t necessary for plain channels at all, because you can always delay the execution of a pending operation until the channel is ready this won&amp;rsquo;t work if I add timeout channels.
And actually, before I introduced timers to the library, there wasn&amp;rsquo;t any &lt;code&gt;dispatched-tasks&lt;/code&gt; kind of thing at all, so the library was truly scheduler-less.
But after I ported the whole thing from ClojureScript, I had to add timeout channels to be fully compatible, thus the scheduling had to be introduced too.&lt;/p&gt;
&lt;p&gt;For a brief note, a &lt;code&gt;timeout&lt;/code&gt; function returns a channel that closes automatically after the specified period of time:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;start&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;time&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;!!&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;timeout&lt;/span&gt; 300))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;print &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Elapsed: &amp;#34;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;- &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;time&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;start&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; s&amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Elapsed&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;0.3021879196167 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;But how exactly it knows when to close?
While we can block our main thread with &lt;code&gt;&amp;lt;!!&lt;/code&gt; OP and inspect the timeout object for the time it needs to sleep, thus putting the main thread to sleep for that time it will also stop all other background tasks from happening.
And if the timeout is awaited asynchronously in a &lt;code&gt;go&lt;/code&gt; block, we can&amp;rsquo;t do even that.&lt;/p&gt;
&lt;p&gt;So, we do need a scheduler that will run regularly and will check for any timeouts that are ready to be released.
My initial thought was that I once again need some kind of &lt;code&gt;scheduler.run&lt;/code&gt; function that will need to be manually called by each function in the library, but this approach has other problems too.&lt;/p&gt;
&lt;p&gt;For example, what if the user will write a tight loop that will run for too long and we&amp;rsquo;ll miss the time we need to release a timeout?
Well, that isn&amp;rsquo;t &lt;em&gt;that&lt;/em&gt; big of a deal, but I&amp;rsquo;d like not to have a system that is this unreliable.
The user can even forget to call &lt;code&gt;scheduler.run&lt;/code&gt; in their loop, wondering why the timer doesn&amp;rsquo;t even count.
So I started searching for other approaches.&lt;/p&gt;
&lt;p&gt;The solution was to use &lt;code&gt;debug.sethook&lt;/code&gt; with some options, to run the hook regularly enough that it will not cause serious performance hit for the system as a whole, and will update timers with enough precision.
And that&amp;rsquo;s exactly what the ClojureScript version of the library &lt;a href=&#34;https://github.com/clojure/core.async/blob/9ebd84a29c943afd1d47baecbeb0200e619e1e00/src/main/clojure/cljs/core/async/impl/dispatch.cljs#L34-L37&#34; target=&#34;_blank&#34;&gt;does&lt;/a&gt;!
Except it uses the &lt;code&gt;goog.async&lt;/code&gt; thing, which I have no idea how it works, but the solution is simple and effective.
As far as I know, JavaScript has some facilities to register callbacks to be run after a certain amount of time, so maybe it&amp;rsquo;s something along the line there.&lt;/p&gt;
&lt;p&gt;So I decided to try this out and made a simple hook that runs every time we return from functions, and every &lt;em&gt;one thousand VM instructions&lt;/em&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; ----8&amp;lt;---- piece of old code ahead -----8&amp;lt;-----&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;-timeouts&lt;/span&gt; {})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;-advance-timeouts&lt;/span&gt; []
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Close any timeout channels whose closing time is less than or equal
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;to current time.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;when &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;next &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;-timeouts&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;to-remove&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;icollect &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ch&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;pairs &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;-timeouts&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                      (&lt;span style=&#34;font-weight:bold&#34;&gt;when &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;&amp;gt; &lt;/span&gt;0 (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;-difftime&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;-time&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ch&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:close&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t&lt;/span&gt;))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;each &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;ipairs &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;to-remove&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold&#34;&gt;tset &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;-timeouts&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;-register-hook&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Run function `f` on each function return and every 1000 instructions.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;Appends the hook to existing one, if found, unless the hook is `f`.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;when &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;and &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;gethook&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sethook&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;match &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;gethook&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sethook&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:r&lt;/span&gt; 1000)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;hook&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mask&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;count&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sethook&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;] (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;hook&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mask&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;count&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;-register-hook&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;-advance-timeouts&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; ----8&amp;lt;----&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And it worked!
Satisfied with the result, and not paying any attention to the slowdown in the REPL, I moved on.
But the bitter taste of this code still followed me, as I knew that this isn&amp;rsquo;t a proper solution by any means.
This had many problems.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The first and obvious one is that the hook runs too frequently, but I didn&amp;rsquo;t think about it too hard because I had other stuff to port to the library.&lt;/li&gt;
&lt;li&gt;Second, and a bit less obvious, the hook runs &lt;em&gt;all the time&lt;/em&gt;, even if there are no timeout channels at all.
Unlike the ClojureScript solution, which schedules the hook once and only when needed, this one runs til the end of time.
Well, if there are no timeout channels it does nothing but the VM still stops to execute it each time the condition is met, which is bad.&lt;/li&gt;
&lt;li&gt;And third, I tried to keep the old hooks around, by using composition and thus made a foreign hook run possibly too often or even not often enough depending on the original settings.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Later, when I added the mentioned &lt;code&gt;dispatched-tasks&lt;/code&gt; table to the code, I started noticing the slowdown even more.
So I knew I need to do something.&lt;/p&gt;
&lt;h2 id=&#34;hooks--the-less-wrong-way&#34;&gt;Hooks (the less wrong way)&lt;/h2&gt;
&lt;p&gt;So, I&amp;rsquo;m pleased to say that all these problems were rectified recently.&lt;/p&gt;
&lt;p&gt;One morning, or a late night, I don&amp;rsquo;t really remember, I thought that it would be nice to actually measure how much time it takes for Lua to execute these 1000 instructions.
I then could adjust the parameter to only run the hook approximately 10ms after it was registered.
Ten milliseconds feels like a decent enough precision for timeout channels.
I mean no one in a sane mind will try to implement a &lt;a href=&#34;https://en.m.wikipedia.org/wiki/Real-time_computing#Hard&#34; target=&#34;_blank&#34;&gt;hard real-time system&lt;/a&gt; with my library, or in Lua for that matter.
Even a firm one.&lt;/p&gt;
&lt;p&gt;Plus, to save up some performance and avoid keeping track of too many timers, I made an optimization to only create a new timer if the time passed since the previous one was created is greater than 10ms.
Thus, the timers at minimum are 10 milliseconds apart from each other.&lt;/p&gt;
&lt;p&gt;After a  bit of testing, it turned out that a million and a half instructions approximately take 10 ms to complete on my machine.
And while 1 million felt like a more appropriate amount to use for advancing timers, I knew that it would change on a per-machine basis, so I decided to tweak the system once more.&lt;/p&gt;
&lt;p&gt;Inspired by the ClojureScript approach, I thought that there was no need to run the hook &lt;em&gt;every&lt;/em&gt; &lt;code&gt;N&lt;/code&gt; instructions.
Instead, I can run it after &lt;code&gt;N&lt;/code&gt; instructions, and then disable it from within the hook itself.
Moreover, I can calculate how much time it took to execute this amount of instructions, and recalculate &lt;code&gt;N&lt;/code&gt; to set the hook to run 10ms in the future.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s the code behind that:&lt;/p&gt;
&lt;p&gt;And the main interface for hook scheduling.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;var &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n-instr&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;register-time&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;orig-hook&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;orig-mask&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;orig-n&lt;/span&gt;) 1&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_000_000&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;schedule-hook&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;hook&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;when &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;and &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;gethook&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sethook&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;hook*&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mask&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n*&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;gethook&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;when &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;not= &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;hook&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;hook*&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold&#34;&gt;set &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;register-time&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;orig-hook&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;orig-mask&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;orig-n&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;font-weight:bold&#34;&gt;values &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;os/clock&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;hook*&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mask&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n*&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sethook&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;main-thread&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;hook&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cancel-hook&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;hook&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;when &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;and &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;gethook&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sethook&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;match &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;gethook&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;main-thread&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;hook&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;?mask&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;?n&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;do &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sethook&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;main-thread&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;orig-hook&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;orig-mask&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;orig-n&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;font-weight:bold&#34;&gt;values &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;?mask&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;?n&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;src-block-caption&#34;&gt;
  &lt;span class=&#34;src-block-number&#34;&gt;Code Snippet 1:&lt;/span&gt;
  Hook cancellation. Returns the hook&#39;s settings for future analysis, and resets to the old hook if specified.
&lt;/div&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;process-messages&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;event&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;took&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;- &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;os/clock&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;register-time&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cancel-hook&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;process-messages&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n-instr&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;not= &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;event&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:count&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;font-weight:bold&#34;&gt;// &lt;/span&gt;0.01 (&lt;span style=&#34;font-weight:bold&#34;&gt;/ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;took&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;faccumulate&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;done&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; 1 1024 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:until&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;done&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;case&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;next &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dispatched-tasks&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;tset &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dispatched-tasks&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;doto &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pcall&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;true&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;each &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ch&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;pairs &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;timeouts&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;when &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;&amp;gt;= &lt;/span&gt;0 (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;difftime&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;time&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold&#34;&gt;tset &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;timeouts&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ch&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:close!&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;when &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;or &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;next &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dispatched-tasks&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;next &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;timeouts&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;schedule-hook&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;process-messages&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n-instr&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;src-block-caption&#34;&gt;
  &lt;span class=&#34;src-block-number&#34;&gt;Code Snippet 2:&lt;/span&gt;
  The main body of the hook, that processes the messages. Re-registers itself if there&#39;s more work to be done. Calculates the amount of time it takes 1 instruction to complete, and uses it to reschedule itself 10ms after the execution.
&lt;/div&gt;
&lt;p&gt;In addition to that I opted out of combining several hooks into a single one.
This feels like a Lua problem - I don&amp;rsquo;t really understand why the VM only allows for a single hook to be registered.
Lua has five different events to hook up to, so why not allow registering five hooks?
And why isn&amp;rsquo;t it possible to register more than one hook for a single event type?
I mean, if there were many hooks registered, just run them in succession.&lt;/p&gt;
&lt;p&gt;I guess I can implement my own &lt;code&gt;sethook&lt;/code&gt; and replace the one that comes with the &lt;code&gt;debug&lt;/code&gt; library with my own version after someone loads my library.
Then register a handler that will keep track of all other hooks registered and run them accordingly.
Maybe I&amp;rsquo;ll try it.&lt;/p&gt;
&lt;p&gt;Two problems though - there&amp;rsquo;s no way of removing a &lt;em&gt;specific&lt;/em&gt; hook in stock Lua, and I will need to somehow determine what hook to call on &lt;code&gt;count&lt;/code&gt; events if more than one was registered.
Especially when each specifies a different amount of instructions.
I guess this is why there&amp;rsquo;s this kind of limitation in the stock &lt;code&gt;debug&lt;/code&gt; library, but I don&amp;rsquo;t think it&amp;rsquo;s impossible to do it in the VM itself with an ever-growing instruction counter.
Probably it&amp;rsquo;s just an optimization.&lt;/p&gt;
&lt;p&gt;In any case, the new system balances itself much better than before keeping 10ms intervals between tasks, and the slowdowns are gone.&lt;/p&gt;
&lt;p&gt;And while I was on it, I realized, that given the fact that I have both &lt;code&gt;scheduked-tasks&lt;/code&gt; and &lt;code&gt;timeouts&lt;/code&gt; storages, instead of checking for them in a hook, I can also do the check when I do a blocking operation.
This means that if the blocking operation only needs to wait for a timeout to close, it can actually sleep instead of doing a busy loop:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;start&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;time&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cpu-start&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;os.clock&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;!!&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;timeout&lt;/span&gt; 1000))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;print &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;CPU time: &amp;#34;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;- &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;os.clock&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cpu-start&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; s&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;print &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Elapsed: &amp;#34;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;- &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;time&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;start&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; s&amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;CPU&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;time&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;0.169319 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Elapsed&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;1.0089449882507 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Another realization came in that there is no point in doing any waiting if there are no active timeouts or tasks dispatched.
Because blocking the only thread means that no other thread can dispatch its task.
And a task can only be dispatched by another task, thus we can exit the waiting loop and throw an error without blocking the execution forever.
This doesn&amp;rsquo;t mean that we&amp;rsquo;re free from data races, far from it, but at least we can detect that the data will never arrive on a channel if we block.
In practice this shouldn&amp;rsquo;t happen too often.&lt;/p&gt;
&lt;p&gt;Probably, there are more clean ways of handling hooks than the one I&amp;rsquo;ve came up with, so feel free to suggest how to change the approach in the &lt;a href=&#34;https://gitlab.com/andreyorst/async.fnl&#34; target=&#34;_blank&#34;&gt;project&amp;rsquo;s repository&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: async.fnl enchancements&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Wed, 02 Aug 2023 09:10:00 +0300</pubDate>
    </item><item>
      <title>Game1 - Results</title>
      <link>https://andreyor.st/posts/2023-07-30-game1-results/</link>
      <guid>https://andreyor.st/posts/2023-07-30-game1-results/</guid>
      <description>&lt;p&gt;Well, this was fun!
A bit exhausting, actually.
The first of five months of the challenge has ended and here are the results:&lt;/p&gt;
&lt;iframe src=&#34;https://itch.io/embed-upload/8414750?color=3e3c57&#34;
        allowfullscreen=&#34;&#34;
        width=&#34;600&#34;
        height=&#34;320&#34;
        frameborder=&#34;0&#34;
        style=&#34;margin-left: auto; margin-right: auto; display: block;&#34;&gt;
  &lt;a href=&#34;https://andreyorst.itch.io/game1&#34;&gt;Play Game1 on itch.io&lt;/a&gt;
&lt;/iframe&gt;
&lt;p&gt;The game isn&amp;rsquo;t really complete, but I did my best to make it feel as complete as possible in the time constraints I had.
Technically, I have 1 day left, but given that I need to start working on the next game immediately I decided to give myself a day off.
It only features one level, and cuts out to the &amp;ldquo;you won&amp;rdquo; screen, but I still consider it a success.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s the last bit of devlog for this particular game outlining some things I did since the last post in no particular order.&lt;/p&gt;
&lt;h2 id=&#34;graphic-overhaul&#34;&gt;Graphic overhaul&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;ve added parallax scrolling to the background, making the game happen inside a cave.
Well, at least, now the background is not that boring to look at, but it&amp;rsquo;s still plain.&lt;/p&gt;
&lt;figure class=&#34;pixelart&#34;&gt;&lt;img src=&#34;https://andreyor.st/2023-07-30-game1-results/background.gif&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;Then, I added a second layer and started experimenting with different colors:&lt;/p&gt;
&lt;figure class=&#34;pixelart&#34;&gt;&lt;img src=&#34;https://andreyor.st/2023-07-30-game1-results/background2.gif&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;The problem with limited colors is that I can&amp;rsquo;t find a way of having foreground and background properly separated without using outlines on sprites, which I wanted to avoid for this game at least.
Thus, slimes are now blue instead of green.
But I like it more this way because it pops from the green ground a bit better.
And now that the background is also green it&amp;rsquo;s a lot more sensible.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve spent some time drawing foliage, like mushrooms, trees, grass, water, and so on.
None of this is animated though - time is once again against me.&lt;/p&gt;
&lt;figure class=&#34;pixelart&#34;&gt;&lt;img src=&#34;https://andreyor.st/2023-07-30-game1-results/foliage.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;Also, added the menus, title screen, cover art, and some fade-in/out animations for smoother transitions:&lt;/p&gt;
&lt;figure class=&#34;pixelart&#34;&gt;&lt;img src=&#34;https://andreyor.st/2023-07-30-game1-results/transitions.gif&#34;/&gt;
&lt;/figure&gt;

&lt;h2 id=&#34;enemy-ai&#34;&gt;Enemy AI&lt;/h2&gt;
&lt;p&gt;While I wanted to add more enemy types to the game I simply ran out of time, so the game only features basic slimes.
Their AI is extremely simple too - just roam forward until there&amp;rsquo;s no more ground, a wall, or another entity, then turns around.&lt;/p&gt;
&lt;p&gt;Still, I had some trouble implementing this at first, as I tried to use the &lt;code&gt;world:check&lt;/code&gt; method to try and move the slime forward and below to check if there&amp;rsquo;s ground to traverse on.
But this didn&amp;rsquo;t work for some reason, so I opted for advanced bump API &lt;code&gt;world:queryRect&lt;/code&gt; and queried the rectangle below the slime instead.
It worked nicely, and perhaps I&amp;rsquo;ll use this to make a more robust AI in future games.&lt;/p&gt;
&lt;p&gt;I was toying for a little bit with flying enemies, but it&amp;rsquo;s hard to make them work right with the environment.
I didn&amp;rsquo;t want something like Medusa heads from Castlevania games, but that&amp;rsquo;s exactly what I got during testing.&lt;/p&gt;
&lt;p&gt;I also finally added the death mechanic, as previously the game lacked it completely.
Death doesn&amp;rsquo;t take away your score, as the game turned out to be hard, and there are not enough coins in the only level to get 100 of them and earn an extra life.&lt;/p&gt;
&lt;h2 id=&#34;level-design&#34;&gt;Level design&lt;/h2&gt;
&lt;p&gt;Probably shouldn&amp;rsquo;t have left this to the last possible moment, but designing interesting levels turned out to be a lot harder than I thought initially.
I think I&amp;rsquo;ve managed to at least do a somewhat challenging one, but you&amp;rsquo;re the judge here.
Probably most enemies and traps are cheap.&lt;/p&gt;
&lt;p&gt;As I mentioned previously, I&amp;rsquo;ve used the map editor to construct the level:&lt;/p&gt;
&lt;figure class=&#34;pixelart&#34;&gt;&lt;img src=&#34;https://andreyor.st/2023-07-30-game1-results/level.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;It&amp;rsquo;s a shame though that &lt;a href=&#34;https://www.mapeditor.org/&#34; target=&#34;_blank&#34;&gt;Tiled&lt;/a&gt;, a tilemap editor, doesn&amp;rsquo;t support TIC&amp;rsquo;s maps.
Well, there&amp;rsquo;s a converter but it didn&amp;rsquo;t work for me.
Map editor in TIC isn&amp;rsquo;t bad, but it isn&amp;rsquo;t as good as something like Tiled.
For example, Tiled has randomization from a selected set of tiles when you paint with them, which makes things like ground feel less repetitive.
In TIC I had to do it by hand, and I may have forgotten to do it somewhere in the game, so excuse me if you&amp;rsquo;ll see something like that.&lt;/p&gt;
&lt;p&gt;I used the bottom of the map to draw menus, backgrounds, transitions, and so on, as can be seen here:&lt;/p&gt;
&lt;figure class=&#34;pixelart&#34;&gt;&lt;img src=&#34;https://andreyor.st/2023-07-30-game1-results/map.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;My initial idea was to implement the first few levels like this, one below another, and then switch the memory bank, draw a new set of tiles, and make more levels.
But not only I ran out of time, I also ran out of ideas.
Maybe next time.&lt;/p&gt;
&lt;p&gt;Overall, I&amp;rsquo;d say making levels isn&amp;rsquo;t my least favorite thing so far but it&amp;rsquo;s close.
I&amp;rsquo;ve played in a fair bit of games with level editors and even published some online, but it never grew on me.
I guess I&amp;rsquo;m not a level designer at heart.&lt;/p&gt;
&lt;h2 id=&#34;music-and-sfx&#34;&gt;Music and SFX&lt;/h2&gt;
&lt;p&gt;This was probably the hardest part.
I can&amp;rsquo;t compose music and TIC&amp;rsquo;s tracker is alien to me. Sound design is a bit easier, but I don&amp;rsquo;t know a lot of tricks, so sounds in this game are far and few between.
Still was worth a shot.&lt;/p&gt;
&lt;figure class=&#34;pixelart&#34;&gt;&lt;img src=&#34;https://andreyor.st/2023-07-30-game1-results/coin-sound.png&#34;/&gt;
&lt;/figure&gt;

&lt;h2 id=&#34;up-next&#34;&gt;Up next&lt;/h2&gt;
&lt;p&gt;The next game in the challenge is a roguelike.
This kind of game poses different problems, like pathfinding, more complex enemy AI in general, randomization of levels, items, etc.
I kinda feel exhausted right now but I&amp;rsquo;ll still try not to repeat the mistake I made and not procrastinate too much in the first weeks.
Though the next month is packed with various life-related events, much more than this one, so we&amp;rsquo;ll see.&lt;/p&gt;
&lt;p&gt;As for this game, here&amp;rsquo;s the cartridge if you want to play it yourself:&lt;/p&gt;
&lt;figure class=&#34;pixelart&#34;&gt;&lt;img src=&#34;https://andreyor.st/2023-07-30-game1-results/game1.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;Though, because the original code requires a more recent version of Fennel than the one TIC provides, the code in the cart above was AOT compiled to Lua and isn&amp;rsquo;t very readable.
Also note that the last stable release of TIC still contains the &lt;a href=&#34;https://github.com/nesbox/TIC-80/issues/1904&#34; target=&#34;_blank&#34;&gt;#1904&lt;/a&gt; bug, which means that my game will run ~10 times slower than it should.
So you either need to play the game on the itch.io page, as it features a more recent version, build a standalone version yourself, or use an older release with the Lua version above.
You can read the original source code at the itch.io page linked above, or in the &lt;a href=&#34;https://gitlab.com/andreyorst/game1/-/blob/main/cart.fnl&#34; target=&#34;_blank&#34;&gt;game repository&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: Game1 - Results&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Sun, 30 Jul 2023 15:29:00 +0300</pubDate>
    </item><item>
      <title>Game1 W4/4 progress</title>
      <link>https://andreyor.st/posts/2023-07-26-game1-w44-progress/</link>
      <guid>https://andreyor.st/posts/2023-07-26-game1-w44-progress/</guid>
      <description>&lt;p&gt;This post is midway through the last week I have to work on the game in a platforming genre.
And it&amp;rsquo;s a bit of a shame because currently, I&amp;rsquo;m having a blast - now that the physics and camera are in place the game already feels like a playable thing.
So I decided to boost this feel and make some graphics so the world won&amp;rsquo;t look too boring to traverse.&lt;/p&gt;
&lt;p&gt;I haven&amp;rsquo;t decided on what the world be like yet, but I&amp;rsquo;m running out of time, and also, I&amp;rsquo;m not that experienced in pixel art.
A few posts ago I wrote how I tried to do pixel art on the phone by using a stylus, and it worked pretty well for me.
So I took out the app again and started thinking about how would I use the colors that are still available to me.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve briefly considered changing the palette too.
The default TIC-80 palette is a bit weird for my taste, and it doesn&amp;rsquo;t include some colors that I&amp;rsquo;d like to have, e.g. brown.
I don&amp;rsquo;t know how, but every time I see some pixel art that uses this particular palette I swear it has brown, but upon closer inspection it&amp;rsquo;s an illusion caused by interplay with the other colors.
Unable to find a new palette that works, and also that doesn&amp;rsquo;t make every other sprite I drew up to this point use some weird colors, I gave up for now.
Maybe I&amp;rsquo;ll just look at what colors I don&amp;rsquo;t use at all or use too infrequently and replace them with the colors I need for my purposes.&lt;/p&gt;
&lt;p&gt;For now, I drew some grass on stone type of terrain (again, no brown for dirt!), and some construction site-type red bars:&lt;/p&gt;
&lt;figure class=&#34;pixelart&#34;&gt;&lt;img src=&#34;https://andreyor.st/2023-07-26-game1-w44-progress/tiles.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;Note, these are tiles, e.g. what goes on the map, but there are some things that are not part of the map, for example, the coin, or the slime enemy.
I&amp;rsquo;ll explain why they&amp;rsquo;re here shortly.&lt;/p&gt;
&lt;p&gt;And here are the sprites:&lt;/p&gt;
&lt;figure class=&#34;pixelart&#34;&gt;&lt;img src=&#34;https://andreyor.st/2023-07-26-game1-w44-progress/sprites.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;As you can see, I&amp;rsquo;m storing these sprites mostly in rows, and tall sprites, like the player character look naturally in the editor.
Except for the ones in the third and fourth rows first half - these are horizontal sprites, but I still store them this way, because of how I do animations.
This reminds me that I haven&amp;rsquo;t explained anything regarding how my game works!
I guess I was too busy implementing it and didn&amp;rsquo;t have any spare time to write a proper post.&lt;/p&gt;
&lt;p&gt;So the animations are implemented in terms of sprites, obviously, but the way I set up them is a bit weird.
And I know, I definitively could save some space and re-use some sprites, because clearly there are doubles or even triples of the same sprite.
But it was easier this way, so I did it anyway.
I have this function, called &lt;code&gt;sprites&lt;/code&gt; that takes an id of the first sprite, the last sprite, and an optional &lt;code&gt;loop?&lt;/code&gt; parameter:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sprites&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;from&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;to&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;loop?&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sprites&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fcollect&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;id&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;from&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;to&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;from&lt;/span&gt;)] &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;id&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;doto &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sprites&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;tset &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:n&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;length &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sprites&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;tset &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:loop?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;loop?&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The result of this function is a table, that simply holds a range of IDs for all the sprites in the animation.
Does the &lt;code&gt;n&lt;/code&gt; key hold the total count of sprites, and &lt;code&gt;loop?&lt;/code&gt;, well, we&amp;rsquo;ll get to it in a moment.&lt;/p&gt;
&lt;p&gt;The other component of animation is how I choose when to change the frame.
I&amp;rsquo;m sure there&amp;rsquo;s a different, and probably more robust way of doing this, but what I&amp;rsquo;ve settled on is this function:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;next-frame&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;obj&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dt&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dt&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dt&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;obj.last-draw-time&lt;/span&gt; 0))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;&amp;gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dt&lt;/span&gt; 60)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sprites&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;obj&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:sprites&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;m/floor&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;/ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dt&lt;/span&gt; 60))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;font-weight:bold&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;obj.last-draw-time&lt;/span&gt; 0)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;obj.frame&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sprites.n&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sprites.loop?&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:number&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;type &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                      (&lt;span style=&#34;font-weight:bold&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;obj.frame&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                      (&lt;span style=&#34;font-weight:bold&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;obj.frame&lt;/span&gt; 1)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              (&lt;span style=&#34;font-weight:bold&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;obj.frame&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clamp&lt;/span&gt; 1 (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;obj.frame&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold&#34;&gt;length &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sprites&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;obj.last-draw-time&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dt&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As you can see, this function receives an object &lt;code&gt;obj&lt;/code&gt; and a delta time &lt;code&gt;dt&lt;/code&gt;.
The object stores its own draw time, and when the sum of &lt;code&gt;dt&lt;/code&gt; and this time is greater than &lt;code&gt;60&lt;/code&gt; I change the frame.
The &lt;code&gt;loop?&lt;/code&gt; field is used in a special way - when the next frame exceeds the total sprite count, we check if the animation should loop.
If the field is &lt;code&gt;true&lt;/code&gt; the animation loops from the first frame.
However, if the field is a number, we restart the animation from that number.
This way the animation can have a set of frames that act as preparation or transition, and then loop only the necessary part.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s how I draw coins:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;coin-sprites&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sprites&lt;/span&gt; 330 335 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:loop&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;coin-collect-sprites&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sprites&lt;/span&gt; 346 351))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;draw-coin&lt;/span&gt; [{&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;frame&lt;/span&gt; &amp;amp;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;as&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self&lt;/span&gt;} {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cam-x&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cam-y&lt;/span&gt;}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;match &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:sprites&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;coin-sprites&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;or &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;coin-sprites&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;frame&lt;/span&gt;) 511)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;spr&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cam-x&lt;/span&gt; -120 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cam-y&lt;/span&gt; -64 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt;) 0 1)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;next-frame&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;/ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dt&lt;/span&gt; 2)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;coin-collect-sprites&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;or &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;coin-collect-sprites&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;frame&lt;/span&gt;) 511)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;spr&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cam-x&lt;/span&gt; -120 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cam-y&lt;/span&gt; -64 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt;) 0 1)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;next-frame&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dt&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;when &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;frame&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;collect-sprites.n&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold&#34;&gt;tset &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;coins&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;There are some wonky numbers in here to adjust to the center of the screen and camera position in the world, but the code should be straightforward.
The &lt;code&gt;(self:sprites)&lt;/code&gt; call simply returns the object&amp;rsquo;s current set of sprites, which I change in other functions depending on the situation.
E.g. if the coin was collected, the object&amp;rsquo;s sprite is changed to the &lt;code&gt;coin-collect-sprites&lt;/code&gt; which doesn&amp;rsquo;t loop, and the last sprite of that animation is invisible.
The coin itself is deleted from the world once the last &lt;code&gt;frame&lt;/code&gt; of the animation was played out.&lt;/p&gt;
&lt;p&gt;&lt;video autoplay loop muted class=&#34;pixelart&#34;&gt;&lt;source src=&#34;https://andreyor.st/2023-07-26-game1-w44-progress/coin-animation.mp4&#34; type=&#34;video/mp4&#34;&gt;
Your browser does not support the video tag.&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;This is the basis for all animation in the game.
Each object has it&amp;rsquo;s &lt;code&gt;:draw&lt;/code&gt; method, and each such method calls to &lt;code&gt;next-frame&lt;/code&gt; to understand what to display next time.&lt;/p&gt;
&lt;p&gt;Interaction with entities is done similarly - each entity has an &lt;code&gt;:interact&lt;/code&gt; method that decides what to do when a collision is detected.
For example, for the slime enemy, the method accepts the &lt;code&gt;y&lt;/code&gt; normal of the collision, and if it is not negative 1, which means that the collision happened from the side or from below, the player is damaged.
Otherwise, the slime sprite set is replaced with the stomp animation, and the object is deleted from the world:&lt;/p&gt;
&lt;p&gt;&lt;video autoplay loop muted class=&#34;pixelart&#34;&gt;&lt;source src=&#34;https://andreyor.st/2023-07-26-game1-w44-progress/slime.mp4&#34; type=&#34;video/mp4&#34;&gt;
Your browser does not support the video tag.&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;By the way, I haven&amp;rsquo;t talked about how I structure the world yet.
You may know, that TIC has an inbuilt map editor:&lt;/p&gt;
&lt;figure class=&#34;pixelart&#34;&gt;&lt;img src=&#34;https://andreyor.st/2023-07-26-game1-w44-progress/map-editor.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;This is basically a level designer for me because I&amp;rsquo;ve implemented a small function that upon loading the cart walks through each tile on the map and populates the world based on it.
I still use &lt;code&gt;map&lt;/code&gt; for drawing the level, but before that, all entity tiles are removed from the map, like in the image above coins and slimes, and the player&amp;rsquo;s head, which acts as a spawn point.
This way I can simply put objects in the map editor, and re-run the game, getting an updated world, complete with collectibles, power-ups, enemies, etc.:&lt;/p&gt;
&lt;p&gt;&lt;video autoplay loop muted class=&#34;pixelart&#34;&gt;&lt;source src=&#34;https://andreyor.st/2023-07-26-game1-w44-progress/level.webm&#34; type=&#34;video/webm&#34;&gt;
Your browser does not support the video tag.&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;Here I&amp;rsquo;m obviously testing things out, but the game feels complete enough to actually start designing some actual levels.
I&amp;rsquo;m running out of time though, so perhaps I&amp;rsquo;ll just make a single course to complete, and that&amp;rsquo;s it.
But it&amp;rsquo;s already more than I&amp;rsquo;ve anticipated at the beginning!&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve also started working on the menu, but there&amp;rsquo;s nothing to show yet.&lt;/p&gt;
&lt;p&gt;From now, I&amp;rsquo;ll probably stop doing any in-game stuff, and concentrate on the level itself and I also need some audio to play when the player collects coins, takes damage, jumps, and so on.
Maybe I&amp;rsquo;ll even include some music if I&amp;rsquo;ll manage to compose something not too annoying to listen to.&lt;/p&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: Game1 W4/4 progress&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Wed, 26 Jul 2023 20:09:00 +0300</pubDate>
    </item><item>
      <title>Game1 W3/4 (again)</title>
      <link>https://andreyor.st/posts/2023-07-22-game1-w34-again/</link>
      <guid>https://andreyor.st/posts/2023-07-22-game1-w34-again/</guid>
      <description>&lt;p&gt;Who knew that writing a post about how I&amp;rsquo;ve procrastinated for two whole weeks instead of following my own challenge would be so motivating?
Immediately after I posted the previous post on Monday, I regained interest and started working on physics integration.
Well, making a platformer without experience turned out to be harder than I thought, though I got stuck on things that are not platformer specific.&lt;/p&gt;
&lt;p&gt;For the first half of the week, I&amp;rsquo;ve been trying to implement collision resolution myself.
This&amp;hellip; didn&amp;rsquo;t go well, as can be seen here:&lt;/p&gt;
&lt;figure class=&#34;pixelart&#34;&gt;&lt;img src=&#34;https://andreyor.st/2023-07-22-game1-w34-again/custom-collisions.gif&#34;
         alt=&#34;Figure 1: The green rectangles depict the area in which I check for possible collisions, and red rectangles mark tiles that collided with the player&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 1: &lt;/span&gt;The green rectangles depict the area in which I check for possible collisions, and red rectangles mark tiles that collided with the player&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;I&amp;rsquo;ve read some tutorials on &lt;a href=&#34;https://github.com/nesbox/TIC-80/wiki/tutorials&#34; target=&#34;_blank&#34;&gt;TIC&amp;rsquo;s wiki&lt;/a&gt;, mainly &lt;a href=&#34;https://medium.com/@btco_code/writing-a-platformer-for-the-tic-80-virtual-console-6fa737abe476&#34; target=&#34;_blank&#34;&gt;this&lt;/a&gt; one.
It mentions how to track collisions by checking nearby squarest cells on the map grid.
That was exactly my idea, but it didn&amp;rsquo;t work well, as was shown in the GIF above.&lt;/p&gt;
&lt;p&gt;I suspect the main reason for that is that the player object moves at irregular intervals because the distance is determined by velocity, and not constant as in the tutorial.
Thus, the object often overshoots or undershoots the wall and the floor, which led to the player stuck in walls, or going completely through them.
It reminded me of problems I had with my &lt;a href=&#34;https://andreyorst.itch.io/brick-game-with-a-twist&#34; target=&#34;_blank&#34;&gt;previous game&lt;/a&gt;, where the ball often got through the platform and bricks, so after failing to do physics again I decided to use a library.&lt;/p&gt;
&lt;p&gt;Using a library in a TIC game means that the library has to be included in the game cart because there&amp;rsquo;s no other way of shipping games for this platform - a cart is a self-contained program without external dependencies.
TIC&amp;rsquo;s carts also have limited capacity so the amount of code I can include is also limited.
Fortunately, there&amp;rsquo;s a small enough library called &lt;a href=&#34;https://github.com/kikito/bump.lua&#34; target=&#34;_blank&#34;&gt;bump.lua&lt;/a&gt; that does AABB collision detection, which is exactly what I need for this type of game.
TIC games are tile-based, so axis-aligned rectangles are exactly what I need to handle.
With some trickery, it is even possible to implement slopes by using special kinds of boxes that define a slope offset based on the X coordinate.&lt;/p&gt;
&lt;p&gt;There was a problem though.
&lt;code&gt;bump.lua&lt;/code&gt; is a Lua library, and while TIC supports Lua, I&amp;rsquo;m doing this game in Fennel.
Usually, it&amp;rsquo;s not a problem, because projects written in Fennel can use Lua libraries without any issues, and technically I could have used &lt;code&gt;bump.lua&lt;/code&gt; as a library from TIC-80 too.
But, as I mentioned, TIC carts must be self-contained, and thus can&amp;rsquo;t load an external library.
So I had to decide - either I port &lt;code&gt;bump.lua&lt;/code&gt; to Fennel, or compile my Fennel code to Lua and continue the development this way.
I also considered re-implementing a smaller subset of &lt;code&gt;bump.lua&lt;/code&gt; specifically for using it in TIC with map tiles, which would probably make the library smaller and easier to handle, but I decided that I want to actually see some results of my work at the end of this month.&lt;/p&gt;
&lt;p&gt;There was another compelling way of handling this situation though.
I could have used Fennel&amp;rsquo;s &lt;code&gt;-require-as-include&lt;/code&gt; compile flag to, well, include &lt;code&gt;bump.lua&lt;/code&gt; as an embedded dependency, and after the development is finished compile the cart to Lua right before shipping.
This would be the easiest way of doing things, as it would mean that I can do a completely normal development and use any libraries I want, but the downside is that the cart will be a hot mess of obfuscated Lua code, and I wanted the cart to actually contain something readable.
Maybe I&amp;rsquo;ll try this in the future, who knows?&lt;/p&gt;
&lt;p&gt;So, after some consideration of continuing in Lua and just copying &lt;code&gt;bump.fnl&lt;/code&gt; code into the cart, I decided to translate &lt;code&gt;bump.lua&lt;/code&gt; to Fennel.
As much as I like Lua, Fennel is more pleasant to work with.
It wasn&amp;rsquo;t that hard to do, given that there&amp;rsquo;s an &lt;a href=&#34;https://fennel-lang.org/see&#34; target=&#34;_blank&#34;&gt;excellent Lua-to-Fennel decompiler&lt;/a&gt;, that did most of the job.
It does generate weird code here and there, calling &lt;code&gt;set-forcibly!&lt;/code&gt; every now and then, and inserting &lt;code&gt;(lua &amp;quot;return &amp;quot;)&lt;/code&gt;  in places where Lua code had a sole &lt;code&gt;return&lt;/code&gt;, or doing things like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- original Lua code&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sortByTiAndDistance&lt;/span&gt;(a,b)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; a.ti == b.ti &lt;span style=&#34;font-weight:bold&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; ir, ar, br = a.itemRect, a.otherRect, b.otherRect
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; ad = rect_getSquareDistance(ir.x,ir.y,ir.w,ir.h, ar.x,ar.y,ar.w,ar.h)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; bd = rect_getSquareDistance(ir.x,ir.y,ir.w,ir.h, br.x,br.y,br.w,br.h)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; ad &amp;lt; bd
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; a.ti &amp;lt; b.ti
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; Lua decompiler result&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sort-by-ti-and-distance&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;when &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a.ti&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b.ti&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ir&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ar&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;br&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold&#34;&gt;values &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a.itemRect&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a.otherRect&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b.otherRect&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ad&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rect-get-square-distance&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ir.x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ir.y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ir.w&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ir.h&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ar.x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ar.y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ar.w&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ar.h&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bd&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rect-get-square-distance&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ir.x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ir.y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ir.w&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ir.h&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;br.x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;br.y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;br.w&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;br.h&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;___antifnl_rtn_1___&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;&amp;lt; &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ad&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bd&lt;/span&gt;)] (&lt;span style=&#34;font-weight:bold&#34;&gt;lua &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;return ___antifnl_rtn_1___&amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;&amp;lt; &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a.ti&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b.ti&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; cleaned version&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sort-by-ti-and-distance&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a.ti&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b.ti&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ir&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a.itemRect&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ar&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a.otherRect&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;br&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b.otherRect&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ad&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rect-get-square-distance&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ir.x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ir.y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ir.w&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ir.h&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ar.x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ar.y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ar.w&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ar.h&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bd&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rect-get-square-distance&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ir.x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ir.y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ir.w&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ir.h&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;br.x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;br.y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;br.w&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;br.h&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold&#34;&gt;&amp;lt; &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ad&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bd&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;&amp;lt; &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a.ti&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b.ti&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;src-block-caption&#34;&gt;
  &lt;span class=&#34;src-block-number&#34;&gt;Code Snippet 1:&lt;/span&gt;
  e.g. here, the decompiler transformed a single-branch &lt;code&gt;if&lt;/code&gt; into &lt;code&gt;when&lt;/code&gt; and generated an explicit return, but a smarter decompiler could transform this into two branched &lt;code&gt;if&lt;/code&gt; without any early returns. Conceptually these two variants are the same, except one is more like the guard-return style and another is more like actual lisp-style.
&lt;/div&gt;
&lt;p&gt;So I took some extra time to clean all &lt;code&gt;set-forcibly!&lt;/code&gt; calls, restored the original comments which were lost during translation, and removed all instances of explicit early returns, by converting the code to use branches instead.
After compiling the library back to Lua, I tested it with some demos listed in the library&amp;rsquo;s readme and it worked fine, so I hope I didn&amp;rsquo;t introduce any new bugs during the cleanup state.
The next thing was to integrate it into the game.&lt;/p&gt;
&lt;p&gt;It wasn&amp;rsquo;t that hard to do, as I just copied the whole library code into the cart, but I was worried if it will be able to handle &lt;em&gt;lots&lt;/em&gt; of squares.
My idea was to iterate over every map cell, check if it is solid or not, and if so add it to the world.
Thus, each non-empty tile on the map exists in the world and acts as a collideable object.
As a result, I can use the map editor basically as a level editor, as adding a tile basically is like adding a world object.&lt;/p&gt;
&lt;p&gt;The resulting performance seems to be fine on my PC, though I&amp;rsquo;m unsure about the browser which I&amp;rsquo;ll target to make the game playable on my itch.io web page.
I&amp;rsquo;m still exploring the idea of using special tile flags to make rooms longer than they seem on the map, as described in the platformer tutorial that I&amp;rsquo;ve mentioned.
But this probably requires special handling when it comes to integrating it with the bump library.
For now, the result (with some debug info) looks like this:&lt;/p&gt;
&lt;figure class=&#34;pixelart&#34;&gt;&lt;img src=&#34;https://andreyor.st/2023-07-22-game1-w34-again/bump.gif&#34;
         alt=&#34;Figure 2: bump.lua in TIC-80 with some debug visualisations of collisions&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 2: &lt;/span&gt;bump.lua in TIC-80 with some debug visualisations of collisions&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;The next thing to do was the camera.
Now, since each object in the world has the same coordinate as the map, the only thing I need to do is implement the translation of world coordinates to screen coordinates based on player position with some slight interpolation.
Fortunately enough, there&amp;rsquo;s a handy &lt;a href=&#34;https://github.com/nesbox/TIC-80/wiki/Camera-tutorial&#34; target=&#34;_blank&#34;&gt;tutorial&lt;/a&gt; on camera movement, and while I&amp;rsquo;d like to try and implement this myself, I decided to rely on external source of wisdom.&lt;/p&gt;
&lt;p&gt;Unfortunately, for some weird reason, the camera described in this tutorial worked differently for me.
For some reason, the player sprite was drawn in the top left corner of the screen, and the camera was also positioned there.
I mean, it moves correctly but is unplayable in this state.
After I&amp;rsquo;ve &lt;em&gt;experimented&lt;/em&gt; with some random numbers I&amp;rsquo;ve managed to get it to work:&lt;/p&gt;
&lt;figure class=&#34;pixelart&#34;&gt;&lt;img src=&#34;https://andreyor.st/2023-07-22-game1-w34-again/camera.gif&#34;
         alt=&#34;Figure 3: The camera moves with a slight delay to add a bit more dynamic feel, but I didn&amp;amp;rsquo;t go for a more proper camera implementation that tries to show more in the direction of movement yet. Also, what&amp;amp;rsquo;s up with these GIFs generated by TIC, their size is around 10MB each, so I had to heavily compress them myself, yet they look entirely the same afterwards.&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 3: &lt;/span&gt;The camera moves with a slight delay to add a bit more dynamic feel, but I didn&amp;rsquo;t go for a more proper camera implementation that tries to show more in the direction of movement yet. Also, what&amp;rsquo;s up with these GIFs generated by TIC, their size is around 10MB each, so I had to heavily compress them myself, yet they look entirely the same afterwards.&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;With that in place, now I need to design some levels and add more graphics, and sounds.
As well, as implement actual environment interactions, such as roaming and collideable enemies, stationary hazards like spikes, health, score, and respawn systems, and maybe some other intractable objects, like coins to collect.
Not sure what I&amp;rsquo;ll do first, probably the latter, as it will teach me how to add collideable items to the world that should not be treated as platforms.&lt;/p&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: Game1 W3/4 (again)&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Sat, 22 Jul 2023 21:03:00 +0300</pubDate>
    </item><item>
      <title>Game1 W3/4</title>
      <link>https://andreyor.st/posts/2023-07-17-game1-w34/</link>
      <guid>https://andreyor.st/posts/2023-07-17-game1-w34/</guid>
      <description>&lt;p&gt;Long story short, no progress so far.
I&amp;rsquo;m starting to think that the way I&amp;rsquo;ve set this challenge up actually mostly demotivates me to continue rather than encourages me to press forward.
To say that I&amp;rsquo;ve been working on Game1 will be both a lie to myself and to you.
Well, I did, but in a tinkerer&amp;rsquo;s fashion - rewriting one piece of code til I&amp;rsquo;m satisfied (except I never am).&lt;/p&gt;
&lt;p&gt;So far I&amp;rsquo;ve managed to put sprites into the TIC-80 engine and created a simple controller, that actually doesn&amp;rsquo;t work how I expected it to, and that&amp;rsquo;s it:&lt;/p&gt;
&lt;figure class=&#34;pixelart&#34;&gt;&lt;img src=&#34;https://andreyor.st/2023-07-17-game1-w34/player-controller.gif&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;Mostly because for the past two weeks I was either distracted by work or by working on a new Emacs window manager described in the last post (that, probably, no one needs, even me).&lt;/p&gt;
&lt;p&gt;I have two weeks left (including this one), and I don&amp;rsquo;t think I&amp;rsquo;ll be able to finish this one in time, at least in its full shape.
Maybe I&amp;rsquo;ll settle on a simpler thing, like a demo in which I just explore how to write a platformer, it&amp;rsquo;ll still be a good start.&lt;/p&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: Game1 W3/4&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Mon, 17 Jul 2023 23:07:00 +0300</pubDate>
    </item><item>
      <title>Clojure&#39;s core.async port for the Fennel language</title>
      <link>https://andreyor.st/posts/2023-05-15-clojures-coreasync-port-for-the-fennel-language/</link>
      <guid>https://andreyor.st/posts/2023-05-15-clojures-coreasync-port-for-the-fennel-language/</guid>
      <description>&lt;p&gt;After I explored asynchronous programming in my first naive implementation &lt;a href=&#34;https://andreyor.st/posts/2021-10-27-naive-async-implementation-in-fennel/&#34;&gt;a few years ago&lt;/a&gt;, I was hooked on the idea of asynchronous communication in programs.
Motivated to take this concept further I&amp;rsquo;ve created the &lt;a href=&#34;https://gitlab.com/andreyorst/fennel-async&#34; target=&#34;_blank&#34;&gt;fennel-async&lt;/a&gt; library that I&amp;rsquo;ve shown &lt;a href=&#34;https://conf.fennel-lang.org/2022&#34; target=&#34;_blank&#34;&gt;at FennelConf 2022&lt;/a&gt;.
While this library works, and I&amp;rsquo;ve managed to write a simple socket-based REPL and integrate it into Emacs as an experiment, I wasn&amp;rsquo;t satisfied with the implementation.
Mainly because the library is pull-based, which means that the tasks are &lt;em&gt;pulled&lt;/em&gt; by the continuously running scheduler.
It poses some difficulties in Lua runtime, as there&amp;rsquo;s no support for multithreading, and the scheduler can&amp;rsquo;t be offloaded to a separate thread.
I soon realized that a proper asynchronous system is push-based, meaning that pushing to the task triggers its activation.
With that in mind I&amp;rsquo;ve started working on a newer version of the library: &lt;a href=&#34;https://gitlab.com/andreyorst/async.fnl&#34; target=&#34;_blank&#34;&gt;async.fnl&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The library started as a small channel-based communication system, where each channel had its own queue of puts, a queue of takes, and an optional buffer, much like &lt;a href=&#34;https://github.com/clojure/core.async&#34; target=&#34;_blank&#34;&gt;core.async from Clojure&lt;/a&gt;.
I was planning to only implement &lt;code&gt;put!&lt;/code&gt;, &lt;code&gt;take!&lt;/code&gt; and &lt;code&gt;alts!&lt;/code&gt; operations, as these are the bare minimum that is needed for the library to be functional, as everything else is bootstrapped on them.
However, it was hard to test the library this way, so I started adding more and more operations, like &lt;code&gt;merge&lt;/code&gt;, &lt;code&gt;into&lt;/code&gt;, eventually added the support for transducers, and before I knew it I was thinking about how to port &lt;code&gt;Mult&lt;/code&gt;, &lt;code&gt;Mix&lt;/code&gt;, and &lt;code&gt;Pub&lt;/code&gt;.
At that moment I decided that I will simply port everything from the &lt;code&gt;core.async&lt;/code&gt;, including tests, and that&amp;rsquo;s where my implementation of channels started failing.
So I ported the channels too.&lt;/p&gt;
&lt;p&gt;Now this library is a mostly complete port of the ClojureScript version of the library.
The reason I&amp;rsquo;ve chosen ClojureScript as a base is that it is also a single-threaded system, so it should behave similarly to Lua, which Fennel uses as its target for compilation.
Interestingly enough, and you don&amp;rsquo;t have to believe me&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;, but up until I decided to port the tests, and later the channel implementation, I was writing this library without looking at the &lt;code&gt;core.async&lt;/code&gt; source code and the resulting Fennel code was quite similar.
Well, this is largely due to the fact that channels are well covered by Rich Hickey in &lt;a href=&#34;https://youtu.be/yJxFPoxqzWE&#34; target=&#34;_blank&#34;&gt;his talk&lt;/a&gt;, and I&amp;rsquo;ve already made three wrong implementations of them, so I knew what I need to do now for the most part.
I&amp;rsquo;m also a bit familiar with Clojure&amp;rsquo;s &lt;code&gt;core.async&lt;/code&gt; code, but only with the public API.
I&amp;rsquo;ve never looked into the implementation of channels, as my tinkering with the library only needed to go as far as the implementation of pipelines, which I&amp;rsquo;ve covered in my post about &lt;a href=&#34;https://andreyor.st/posts/2022-11-21-clojures-coreasync-pipeline-async-off-by-two-error-explained/&#34;&gt;fixing the off-by-two error&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;So when the tests started to fail, I knew that something wasn&amp;rsquo;t right, so after some hours of debugging I ditched my own implementation of channels and ported the code from ClojureScript into Fennel.
This was a fun experience, and I&amp;rsquo;ve even &amp;ldquo;ported&amp;rdquo; &lt;code&gt;reify&lt;/code&gt; and &lt;code&gt;defprotocol&lt;/code&gt; just not to think too much about how to write it manually in every function.
I&amp;rsquo;ve put ported in quotes because it&amp;rsquo;s not a true port, just a similar macro that expands to the runtime definition of an object that conforms to the &lt;code&gt;defprotocol&lt;/code&gt; spec:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;macro &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;defprotocol&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  `(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;&#34;&gt;,&lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;faccumulate&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;methods&lt;/span&gt; {} &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; 1 (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;select &lt;/span&gt;&lt;span style=&#34;&#34;&gt;:&lt;/span&gt;# &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;method&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;select &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;assert-compile&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;list?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;method&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;expected method declaration&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;arglist&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;body&lt;/span&gt;] &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;method&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;assert-compile&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sym?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;expected named method&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;assert-compile&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sequence?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;arglist&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;expected arglist for method &amp;#34;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;tostring &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt;)) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;arglist&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;assert-compile&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;or &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:string&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;type &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;body&lt;/span&gt;)) (&lt;span style=&#34;font-weight:bold&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;body&lt;/span&gt;)) (&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;expected no body for method &amp;#34;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;tostring &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt;)) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;body&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;font-weight:bold&#34;&gt;doto &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;methods&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              (&lt;span style=&#34;font-weight:bold&#34;&gt;tset &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;tostring &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt;) `#(&lt;span style=&#34;font-weight:bold&#34;&gt;&amp;lt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;$&lt;/span&gt; &lt;span style=&#34;&#34;&gt;,&lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;length &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;arglist&lt;/span&gt;)))))))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;macro &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;reify&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;index&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;gensym&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocols&lt;/span&gt; []
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;actions&lt;/span&gt; &amp;#39;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;do&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;var &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;current&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ((&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;loop&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;assert-compile&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;or &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sym?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;list?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;)) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;expected symbol or fnspec&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sym?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;font-weight:bold&#34;&gt;do &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;current&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;table.insert &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocols&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;tostring &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;list?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt; &amp;amp; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;arglist&lt;/span&gt; &amp;amp;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;as&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fnspec&lt;/span&gt;]] &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;assert-compile&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sym?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;expected method name&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;assert-compile&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sequence?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;arglist&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;expected method arglist&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;arglist&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;table.insert&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;actions&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              `(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;case&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;. &lt;/span&gt;&lt;span style=&#34;&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;current&lt;/span&gt; &lt;span style=&#34;&#34;&gt;,&lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;tostring &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f#&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f#&lt;/span&gt; &lt;span style=&#34;&#34;&gt;,&lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;length &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;arglist&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        (&lt;span style=&#34;font-weight:bold&#34;&gt;tset &lt;/span&gt;&lt;span style=&#34;&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;index&lt;/span&gt; &lt;span style=&#34;&#34;&gt;,&lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;tostring &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;&#34;&gt;,&lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;unpack &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fnspec&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;error &lt;/span&gt;&lt;span style=&#34;&#34;&gt;,&lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;arity mismatch for method &amp;#34;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;tostring &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 &lt;span style=&#34;&#34;&gt;,&lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sym&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:_&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;error &lt;/span&gt;&lt;span style=&#34;&#34;&gt;,&lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Protocol &amp;#34;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;tostring &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;current&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; doesn&amp;#39;t define method &amp;#34;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;tostring &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt;)))))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;font-weight:bold&#34;&gt;when &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;not= &lt;/span&gt;0 (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;select &lt;/span&gt;&lt;span style=&#34;&#34;&gt;:&lt;/span&gt;# &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;loop&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    `(&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;index&lt;/span&gt; {}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;actions&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;setmetatable&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:__index&lt;/span&gt; &lt;span style=&#34;&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;index&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;reify&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:__fennelview&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         #(&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;#&amp;lt;&amp;#34;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;tostring &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;$&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:gsub&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;table:&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;reify:&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;: &amp;#34;&lt;/span&gt; &lt;span style=&#34;&#34;&gt;,&lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;table.concat &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocols&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;, &amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;gt;&amp;#34;&lt;/span&gt;)}))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It&amp;rsquo;s a little messy but works fine.
I added it when I was porting &lt;code&gt;Mult&lt;/code&gt;, which looks a lot like the ClojureScript version:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;defprotocol&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Mux&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;muxch&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt;]))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;defprotocol&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Mult&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tap&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ch&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;close?&lt;/span&gt;])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;untap&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ch&lt;/span&gt;])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;untap-all&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt;]))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mult&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ch&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Creates and returns a mult(iple) of the supplied channel
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;`ch`.  Channels containing copies of the channel can be created with
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;tap&amp;#39;, and detached with &amp;#39;untap&amp;#39;.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;Each item is distributed to all taps in parallel and synchronously,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;i.e. each tap must accept before the next item is distributed.  Use
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;buffering/windowing to prevent slow taps from holding up the mult.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;Items received when there are no taps get dropped.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;If a tap puts to a closed channel, it will be removed from the mult.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;var &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dctr&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;atom&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:cs&lt;/span&gt; {}}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;m&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;reify&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Mux&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;muxch&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt;] &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ch&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Mult&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tap&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ch&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;close?&lt;/span&gt;] (&lt;span style=&#34;font-weight:bold&#34;&gt;tset &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;atom&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:cs&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ch&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;close?&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;untap&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ch&lt;/span&gt;] (&lt;span style=&#34;font-weight:bold&#34;&gt;tset &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;atom&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:cs&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ch&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;untap-all&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt;] (&lt;span style=&#34;font-weight:bold&#34;&gt;tset &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;atom&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:cs&lt;/span&gt; {}) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dchan&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chan&lt;/span&gt; 1)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;done&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               (&lt;span style=&#34;font-weight:bold&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dctr&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;- &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dctr&lt;/span&gt; 1))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               (&lt;span style=&#34;font-weight:bold&#34;&gt;when &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;= &lt;/span&gt;0 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dctr&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;put!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dchan&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;true&lt;/span&gt;)))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;go-loop&lt;/span&gt; []
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;val&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ch&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;val&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;font-weight:bold&#34;&gt;each &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;close?&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;pairs &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;atom.cs&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              (&lt;span style=&#34;font-weight:bold&#34;&gt;when &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;close?&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;close!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chs&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;icollect &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;k&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;pairs &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;atom.cs&lt;/span&gt;)] &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;k&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              (&lt;span style=&#34;font-weight:bold&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dctr&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;length &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chs&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              (&lt;span style=&#34;font-weight:bold&#34;&gt;each &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;ipairs &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chs&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                (&lt;span style=&#34;font-weight:bold&#34;&gt;when &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;not &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;put!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;val&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;done&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;m&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:untap&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              (&lt;span style=&#34;font-weight:bold&#34;&gt;when &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;next &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chs&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dchan&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;recur&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;m&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Sure, fennel doesn&amp;rsquo;t have sequences and atoms by default, so this uses mutable tables, but the semantics are the same.&lt;/p&gt;
&lt;p&gt;In general, Fennel isn&amp;rsquo;t exactly compatible with Clojure, as it is a different language.
There&amp;rsquo;s no arity overloading, data structures aren&amp;rsquo;t persistent, and there are no lazy sequences, only iterators over tables.
All these features can be implemented as libraries, and I&amp;rsquo;ve already made &lt;a href=&#34;https://andreyor.st/about#clojure-libraries-for-fennel&#34;&gt;a bunch&lt;/a&gt; that should make a Clojure programmer feel more at home.
Well, at least the strings are immutable by default, which is good!&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve chosen the same versioning scheme as the Clojure version of the library, but it is still in an experimental state.
More tests should be added, I also need to test on different runtimes, as this is only tested to work on Lua 5.4 at the moment.&lt;/p&gt;
&lt;h2 id=&#34;differences-from-the-clojure-version&#34;&gt;Differences from the Clojure version&lt;/h2&gt;
&lt;p&gt;One tricky thing this library requires is the presence of the &lt;code&gt;debug&lt;/code&gt; Lua library.
It is included by default in most Lua implementations, but it may be absent in an embedded Lua.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;debug&lt;/code&gt; library is required to run timers.
By using the &lt;code&gt;debug.sethook&lt;/code&gt; function, when the library is loaded, a hook that checks if any of the timeout channels have expired runs every 1000 Lua instructions, and on each function return.
This needs a bit more profiling to get an optimal amount of instructions between runs, but the tests show a nice accuracy with the error of 10ms, which is largely due to the library trying to minimize the number of timeout channels by rounding their duration to these 10ms.
It&amp;rsquo;s similar to what the Clojure version does, e.g. the expression &lt;code&gt;(= (timeout 1000) (timeout 1000))&lt;/code&gt; is &lt;code&gt;true&lt;/code&gt; because only one timeout channel is created under the hood.
When the &lt;code&gt;debug&lt;/code&gt; library is unavailable, the &lt;code&gt;timeout&lt;/code&gt; function throws an error, but the rest of the library should work fine, as timeout channels aren&amp;rsquo;t used anywhere.&lt;/p&gt;
&lt;p&gt;Another tricky thing is that Lua by default doesn&amp;rsquo;t support sub-second precision for measuring time.
The default &lt;code&gt;os.time&lt;/code&gt; reports the number of seconds since the epoch, and there&amp;rsquo;s no way to get the number of milliseconds.
The solution is to check if the &lt;code&gt;luasocket&lt;/code&gt; or &lt;code&gt;luaposix&lt;/code&gt; libraries are present on the &lt;code&gt;LUA_PATH&lt;/code&gt;.
If so, their implementations of the &lt;code&gt;gettime&lt;/code&gt; function are used, which gives millisecond precision.
Otherwise, the number of milliseconds passed to the &lt;code&gt;timeout&lt;/code&gt; function is rounded up to the next whole second.
Not ideal, but works, especially since the asynchronous code shouldn&amp;rsquo;t be too dependent on specific timings.
The library will warn you if you don&amp;rsquo;t have any of these installed.&lt;/p&gt;
&lt;p&gt;And the final difference from Clojure is that there is no inversion of control (IOC) transformations involved.
Lua, unlike the JVM, supports sackful coroutines, which means that any function can be turned into coroutines that can be stopped and resumed with the &lt;code&gt;coroutine.yield&lt;/code&gt; call.
Thus, all operations that would result in a blocking behavior, like &lt;code&gt;&amp;lt;!&lt;/code&gt; or &lt;code&gt;&amp;gt;!&lt;/code&gt;, actually just capture the running thread with the &lt;code&gt;coroutine.running&lt;/code&gt; put it to the respective queue on the channel where the operation occurs, and the channel calls &lt;code&gt;coroutine.yield&lt;/code&gt;.
Next, when this channel receives another put or takes if there&amp;rsquo;s a such pending thread, it will be resumed with the value of the operation.
Stackful coroutines make the implementation much simpler, without the need to write complex macros that transform the code into state machines.
I wish more languages had them, as it is a great feature that can be used in a variety of ways.
Generators are cool, but Lua coroutines are much cooler.
But I digress.&lt;/p&gt;
&lt;h2 id=&#34;future-plans&#34;&gt;Future plans&lt;/h2&gt;
&lt;p&gt;Overall, this was a fun experiment, and while I really like asynchronous programming, I feel that I need to stop myself here.
There are a lot of other topics I want to get into, like the bytecode VM design, gamedev, and other cool stuff.
So hopefully there will be no more async shenanigans from me.
Though, maybe I&amp;rsquo;ll try to port the TCP module from &lt;code&gt;fennel-async&lt;/code&gt; into this library, but we&amp;rsquo;ll see.
That may be difficult, as there&amp;rsquo;s no way to register a callback on a socket object with the &lt;code&gt;luasocket&lt;/code&gt; library, which almost defeats the purpose of being push-based.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re using Fennel, and you&amp;rsquo;re familiar with &lt;code&gt;core.async&lt;/code&gt; do give this library a test.
I&amp;rsquo;m curious how it will work in other programs because I&amp;rsquo;m making all these libraries, but I don&amp;rsquo;t really have any time to use them as parts of other projects, besides maybe the &lt;a href=&#34;https://gitlab.com/andreyorst/fenneldoc&#34; target=&#34;_blank&#34;&gt;fenneldoc&lt;/a&gt;, which uses the &lt;code&gt;cljlib&lt;/code&gt; library.&lt;/p&gt;
&lt;p&gt;Anyway, thanks for reading, and I hope this library will be useful!&lt;/p&gt;
&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;
&lt;p&gt;You don&amp;rsquo;t have to, but if you read my blog, you may remember that that&amp;rsquo;s the way I usually like to do stuff.
Diving in without any or very little amount of prior knowledge on the topic and thinking about how would I implement that.
And if the result is similar to the reference implementation or differs from it, that&amp;rsquo;s how I know if I made any mistakes, or if my assumptions were correct.
This library started the same way.&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: Clojure&#39;s core.async port for the Fennel language&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Mon, 15 May 2023 22:44:00 +0300</pubDate>
    </item><item>
      <title>New Fennel Proto REPL and call for testing</title>
      <link>https://andreyor.st/posts/2023-04-08-new-fennel-proto-repl-and-call-for-testing/</link>
      <guid>https://andreyor.st/posts/2023-04-08-new-fennel-proto-repl-and-call-for-testing/</guid>
      <description>&lt;p&gt;In the &lt;a href=&#34;https://andreyor.st/posts/2023-03-25-implementing-a-protocol-based-fennel-repl-and-emacs-client/&#34;&gt;previous post&lt;/a&gt; I&amp;rsquo;ve described how to define a simple protocol, upgrade the stock Fennel REPL with it, and create a simple client that works with this setup.
And at the end, I mentioned that I was working on a proper client implementation and a more robust protocol as part of the &lt;code&gt;fennel-mode&lt;/code&gt; package.
So today I&amp;rsquo;m presenting the new &lt;a href=&#34;https://git.sr.ht/~technomancy/fennel-mode/tree/dd2d0845cd8f21f6487c4e8ca5ea104d1fcba11a/item/fennel-proto-repl.el&#34; target=&#34;_blank&#34;&gt;fennel-proto-repl&lt;/a&gt; module!&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s an experimental implementation of the new Fennel REPL client, that is based on the message-callback system, and it provides more robust ways of communicating with the REPL process.
We&amp;rsquo;re not going to remove the old REPL integration support, and it going to remain the default one since I expect that some rough edges still need to be refined, and we still need to wait until Fennel will release the next stable version anyway.
But if you&amp;rsquo;re using the development version of Fennel or don&amp;rsquo;t mind trying things, you can update &lt;code&gt;fennel-mode&lt;/code&gt; and try the new REPL implementation by adding the following hook to your Emacs configuration:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;add-hook&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;fennel-mode-hook&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;fennel-proto-repl-minor-mode&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This new minor mode enables the integration with the new REPL implementation, meaning that all usual commands, such as &lt;kbd&gt;Ctrl+Alt+x&lt;/kbd&gt; (&lt;code&gt;eval-defun&lt;/code&gt;) will use the new REPL implementation.&lt;/p&gt;
&lt;p&gt;At the end of the previous post I mentioned that the protocol-based REPL may not work in all cases, but this limitation should now be lifted in the latest Fennel (that&amp;rsquo;s why the Fennel update is required).
I&amp;rsquo;ve &lt;a href=&#34;https://git.sr.ht/~technomancy/fennel/commit/8adeaad80ab93ba86216c255eda355e99c61b53a&#34; target=&#34;_blank&#34;&gt;sent a patch&lt;/a&gt; that makes inbuilt Fennel REPL more dynamic, and now the currently running REPL can be changed at runtime.
Thus, if your application uses a custom REPL, like the one in the &lt;a href=&#34;https://gitlab.com/alexjgriffith/min-love2d-fennel/-/blob/ecce4e3e802b3a85490341e13f8c562315f751d2/lib/stdio.fnl&#34; target=&#34;_blank&#34;&gt;min-love2d-fennel repo&lt;/a&gt;, you should be able to use new Proto REPL, you&amp;rsquo;ll just need to update the Fennel dependency in your application.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;So this post is a call for testing!&lt;/strong&gt;
If you experience hiccups or problems with the stock &lt;code&gt;fennel-repl&lt;/code&gt; mode in Emacs, give &lt;code&gt;fennel-proto-repl&lt;/code&gt; a try!&lt;/p&gt;
&lt;h2 id=&#34;what-s-new&#34;&gt;What&amp;rsquo;s new&lt;/h2&gt;
&lt;p&gt;Here I&amp;rsquo;ll briefly list enhancements that are now possible thanks to the protocol.
There aren&amp;rsquo;t a lot of new features, the new client mostly provides stability-related improvements, yet, there are some things I&amp;rsquo;d like to note.&lt;/p&gt;
&lt;h3 id=&#34;programmatic-api&#34;&gt;Programmatic API&lt;/h3&gt;
&lt;p&gt;First of all, now it is possible to send both synchronous and asynchronous messages to the REPL process and use a system of callbacks to get back the results.
Previously it was possible but it was quite finicky because of how comint&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt; works, and thus all requests sent outside of the REPL were synchronous (like completions or documentation fetching).
Again, I&amp;rsquo;ve &lt;a href=&#34;https://andreyor.st/posts/2023-03-25-implementing-a-protocol-based-fennel-repl-and-emacs-client/#comint&#34;&gt;described it in detail&lt;/a&gt; in the previous post.
The REPL itself is still synchronous - all messages are processed sequentially, but the client is now decoupled and doesn&amp;rsquo;t have to proactively wait for each message to be processed.&lt;/p&gt;
&lt;p&gt;The new API includes these two functions: &lt;code&gt;fennel-proto-repl-send-message&lt;/code&gt;, and &lt;code&gt;fennel-proto-repl-send-message-sync&lt;/code&gt;.
The first one will never block Emacs and should be used whenever you want to send some code to the REPL but you don&amp;rsquo;t require the result immediately.
Here&amp;rsquo;s an example:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fennel-proto-repl-send-message&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:eval&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;(+ 1 2 3)&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;lambda&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vals&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;%S&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vals&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In this case, the result will be shown when the REPL is ready to process the message.
You can additionally provide error callback and printing callback to capture error messages or data that the REPL requested to print.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fennel-proto-repl-send-message-sync&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:eval&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;(+ 1 2 3)&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; =&amp;gt; (&amp;#34;6&amp;#34;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This will block Emacs until the REPL is ready to process the message, so it should be used with care.
The message, however, can timeout after a configurable amount of time (5 seconds by default), so the block will not be indefinite.&lt;/p&gt;
&lt;p&gt;Most of the features in the new client are implemented via these two functions, so it should be enough for other packages to integrate with the new client if necessary.
I&amp;rsquo;m already thinking about updating my &lt;a href=&#34;https://gitlab.com/andreyorst/ob-fennel&#34; target=&#34;_blank&#34;&gt;ob-fennel&lt;/a&gt; package to use this new REPL implementation, as it will fix a lot of bugs and problems in general.&lt;/p&gt;
&lt;h3 id=&#34;multiple-repls&#34;&gt;Multiple REPLs&lt;/h3&gt;
&lt;p&gt;Support for multiple REPL sessions received some improvements.
Previously, with the comint-based REPL, in order to have more than one REPL active at a time, it was required to rename the existing REPL buffer, and then start a new one.
Otherwise, the function that starts the REPL just jumped to the already running one.
This worked, however, the in-buffer commands, such as &lt;code&gt;eval-defun&lt;/code&gt; or &lt;code&gt;eval-last-sexp&lt;/code&gt; started working with the new REPL buffer unless it also was renamed.
If there wasn&amp;rsquo;t a REPL buffer with the default name these commands didn&amp;rsquo;t work.&lt;/p&gt;
&lt;p&gt;Fennel Proto REPL introduces a way to link a certain buffer to a certain REPL with the &lt;code&gt;fennel-proto-repl-link-buffer&lt;/code&gt; function.
This function provides a list of currently running REPLs to choose from, and after choosing one all in-buffer commands start working with that REPL.
Additionally to that, it&amp;rsquo;s no longer necessary to manually rename the REPL buffer to start a new one - the &lt;code&gt;fennel-proto-repl&lt;/code&gt; function always starts a new REPL and automatically links the current buffer to it.&lt;/p&gt;
&lt;h3 id=&#34;improved-error-reporting&#34;&gt;Improved error reporting&lt;/h3&gt;
&lt;p&gt;The protocol changes how the errors are reported to the client, so the client could better analyze the stack traces and make them clickable.
Now, when the error occurs, a special buffer will pop up, displaying the detailed message and a clickable stack trace:&lt;/p&gt;
&lt;figure class=&#34;invertable&#34;&gt;&lt;img src=&#34;https://andreyor.st/2023-04-08-new-fennel-proto-repl-and-call-for-testing/error-buffer.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;The REPL itself shows a shortened message to avoid too much visual noise.&lt;/p&gt;
&lt;h3 id=&#34;improved-xref-eldoc-and-completion-at-point-support&#34;&gt;Improved Xref, Eldoc, and completion-at-point support&lt;/h3&gt;
&lt;p&gt;Fennel REPL has a command that can provide you with the target file and line of the definition you&amp;rsquo;re interested in, but it&amp;rsquo;s a bit tedious to copy it from the REPL every time.
So the new Xref integration uses a special protocol OP that will automate most of the things.&lt;/p&gt;
&lt;p&gt;Eldoc support was already part of the &lt;code&gt;fennel-mode&lt;/code&gt;, but it was implemented poorly.
The new implementation is asynchronous, and should never block Emacs if the REPL is busy, like what&amp;rsquo;s happened with an older implementation.
We will remove eldoc support from basic &lt;code&gt;fennel-repl&lt;/code&gt; in the future as it causes lots of problems.
Unfortunately, asynchronous Eldoc is a feature of Emacs 28+.
I&amp;rsquo;ve decided not to implement support for older versions of Emacs because in the case of Fennel, there&amp;rsquo;s no way of querying for documentation concurrently with the currently running task, like can be done in other languages, and blocking Emacs is not fun.&lt;/p&gt;
&lt;figure class=&#34;invertable&#34;&gt;&lt;img src=&#34;https://andreyor.st/2023-04-08-new-fennel-proto-repl-and-call-for-testing/arglist-hint.png&#34;
         alt=&#34;Figure 1: Argument list hint by Eldoc&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 1: &lt;/span&gt;Argument list hint by Eldoc&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;figure class=&#34;invertable&#34;&gt;&lt;img src=&#34;https://andreyor.st/2023-04-08-new-fennel-proto-repl-and-call-for-testing/eldoc.png&#34;
         alt=&#34;Figure 2: Documentation hint by Eldoc&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 2: &lt;/span&gt;Documentation hint by Eldoc&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Completion at point also received some enhancements and should be much faster now, because everything is now processed in batches.
The previous implementation requested a list of completions with one command and then sent a request for each item to get its kind.
The new implementation does an initial request, and then a second request that gets kinds for all results of previous requests and caches them until the next completion happens.&lt;/p&gt;
&lt;figure class=&#34;invertable&#34;&gt;&lt;img src=&#34;https://andreyor.st/2023-04-08-new-fennel-proto-repl-and-call-for-testing/completion.png&#34;
         alt=&#34;Figure 3: Completions, complete with candidate kinds, and documentation&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 3: &lt;/span&gt;Completions, complete with candidate kinds, and documentation&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Overall, all these features should be more robust, because we no longer require parsing the output of the REPL, as we had to with comint.&lt;/p&gt;
&lt;h2 id=&#34;rough-edges&#34;&gt;Rough edges&lt;/h2&gt;
&lt;p&gt;The implementation is not perfect, so there are some things to be concerned about.&lt;/p&gt;
&lt;p&gt;The client code is still can be improved performance-wise.
Nothing crazy, but if the process starts spitting out lots of output, it can start piling up and Emacs will chug on it.
This happens when printing huge tables, like &lt;code&gt;_G&lt;/code&gt;, or when a tight loop produces a lot of output, like &lt;code&gt;(for [i 1 1000000] (print i))&lt;/code&gt;.
Disabling process logging can help, and this is why the logging is disabled by default.
Though it should not be a major problem because large amounts of output are rare, and data is usually small.&lt;/p&gt;
&lt;p&gt;The buffer linking mechanism is not as user-friendly as something more automatic, like linking REPLs based on project structure, I agree.
But I hope it is not as bad, and we can always improve this part later as we gather more feedback from the users.&lt;/p&gt;
&lt;p&gt;Lastly, the overall complexity of the client may seem daunting, and there&amp;rsquo;s a lot of code but the architecture is quite simple, it&amp;rsquo;s just that there&amp;rsquo;s a lot of code for various features.&lt;/p&gt;
&lt;p&gt;I hope that it will be good enough to be the default REPL one day.
However, as I&amp;rsquo;ve mentioned, there may be problems with embedded REPLs or just the fact that you can&amp;rsquo;t update the old Fennel version due to some circumstances.
For these cases, there&amp;rsquo;s always the old implementation of the REPL.&lt;/p&gt;
&lt;h2 id=&#34;the-protocol-library&#34;&gt;The Protocol library&lt;/h2&gt;
&lt;p&gt;The protocol behind the new client is in fact editor-agnostic and can be used by other editors.
Because of that, I&amp;rsquo;ve released the protocol as a library: &lt;a href=&#34;https://gitlab.com/andreyorst/fennel-proto-repl-protocol&#34; target=&#34;_blank&#34;&gt;fennel-proto-repl-protocol&lt;/a&gt;, and I&amp;rsquo;m looking forward to others trying it and implement support in their editors.&lt;/p&gt;
&lt;p&gt;The protocol setup is quite simple - all you have to do is either require the protocol library from the REPL and call the provided function with an editor-specific format function.
Or you can send the whole protocol code to a running REPL without using &lt;code&gt;require&lt;/code&gt; as the &lt;code&gt;fennel-proto-repl&lt;/code&gt; module does.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s an example for JSON based messaging:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;format-json&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;env&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;{%s}&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:format&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;table.concat&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         (&lt;span style=&#34;font-weight:bold&#34;&gt;icollect &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;k&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;v&lt;/span&gt;] (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;ipairs &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;%s: %s&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:format&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;env.fennel.view&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;k&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              (&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;v&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:list&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;} (&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;[&amp;#34;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;table.concat &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;]&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:string&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;} (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;env.fennel.view&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:sym&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;} (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;tostring &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;env.protocol.internal-error&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Wrong data kind&amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;env.fennel.view&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;v&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:gsub&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\n&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\\\\n&amp;#34;&lt;/span&gt;))) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;, &amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;function&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x563fec938af0&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; ((&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:protocol&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;format-json&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;id&amp;#34;&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;0&lt;span style=&#34;&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;op&amp;#34;&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;init&amp;#34;&lt;/span&gt;&lt;span style=&#34;&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;status&amp;#34;&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;done&amp;#34;&lt;/span&gt;&lt;span style=&#34;&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;protocol&amp;#34;&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;0.1.0&amp;#34;&lt;/span&gt;&lt;span style=&#34;&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;fennel&amp;#34;&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;1.3.1-dev&amp;#34;&lt;/span&gt;&lt;span style=&#34;&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;lua&amp;#34;&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;PUC Lua 5.4&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;For more info, see the project&amp;rsquo;s &lt;a href=&#34;https://gitlab.com/andreyorst/fennel-proto-repl-protocol/blob/4d4e447094252746e2f0258f075c2d7f95fafa8d/README.md&#34; target=&#34;_blank&#34;&gt;readme&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;All in all, I hope this will help make better tooling for Fennel in the future, and will bring the programming experience closer to what&amp;rsquo;s available for other Lisps.&lt;/p&gt;
&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;
&lt;p&gt;Comint is the generic mechanism for implementing &lt;a href=&#34;https://www.gnu.org/software/emacs/manual/html_node/emacs/Shell-Mode.html&#34; target=&#34;_blank&#34;&gt;interactive shells&lt;/a&gt; in Emacs.
It works by setting up a process output filter and convenience functions for sending input to the process, but it&amp;rsquo;s hard to use it as a machine-to-machine interface.&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: New Fennel Proto REPL and call for testing&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Sat, 08 Apr 2023 10:25:00 +0300</pubDate>
    </item><item>
      <title>Implementing a protocol-based Fennel REPL and Emacs client</title>
      <link>https://andreyor.st/posts/2023-03-25-implementing-a-protocol-based-fennel-repl-and-emacs-client/</link>
      <guid>https://andreyor.st/posts/2023-03-25-implementing-a-protocol-based-fennel-repl-and-emacs-client/</guid>
      <description>&lt;p&gt;Recently I read a post by &lt;a href=&#34;https://tonsky.me/&#34; target=&#34;_blank&#34;&gt;@nikitonsky&lt;/a&gt; about &lt;a href=&#34;https://tonsky.me/blog/clojure-sublimed-3/&#34; target=&#34;_blank&#34;&gt;writing a custom REPL for Clojure and Sublime Text&lt;/a&gt;.
What got my attention was a way of implementing a protocol over a plain Clojure REPL.
In the post, Nikita describes a way to &lt;a href=&#34;https://tonsky.me/blog/clojure-sublimed-3/#repl-upgraded&#34; target=&#34;_blank&#34;&gt;&amp;ldquo;upgrade&amp;rdquo; the connection&lt;/a&gt; by sending code that basically implements a new REPL to the main REPL process.
I liked the idea and decided that two can play this game, and started working on a similar thing, but for Fennel.&lt;/p&gt;
&lt;p&gt;A few months ago I&amp;rsquo;ve &lt;a href=&#34;https://lists.sr.ht/~technomancy/fennel/%3C87o7uuw4sj.fsf%40gmail.com%3E&#34; target=&#34;_blank&#34;&gt;already proposed&lt;/a&gt; the idea of a simple protocol for the Fennel REPL.
The idea was met with a certain amount of skepticism because there&amp;rsquo;s already an implementation of a such protocol that is language agnostic (in theory) and battle-tested.
The protocol in question is called &lt;a href=&#34;https://nrepl.org/&#34; target=&#34;_blank&#34;&gt;nREPL&lt;/a&gt; and it is widely used in the Clojure ecosystem.
There are several client implementations for various editors, and the protocol is extensible enough to support other languages and various clients.&lt;/p&gt;
&lt;p&gt;In fact, Fennel already has an implementation of the nREPL protocol, called &lt;a href=&#34;https://gitlab.com/technomancy/jeejah&#34; target=&#34;_blank&#34;&gt;jeejah&lt;/a&gt;.
However, it has problems.&lt;/p&gt;
&lt;p&gt;First of all, nREPL is mainly designed for Clojure, tested against Clojure, and implements features that Clojure needs in a pretty specific Clojure way.
It&amp;rsquo;s not impossible to implement support for other languages, and there &lt;a href=&#34;https://nrepl.org/nrepl/beyond_clojure.html&#34; target=&#34;_blank&#34;&gt;were attempts&lt;/a&gt; of various completeness.&lt;/p&gt;
&lt;p&gt;Another problem is that nREPL has &amp;ldquo;n&amp;rdquo; in its name for a reason.
It&amp;rsquo;s a Network REPL, which means that the protocol is designed around network communication pipelines.
In principle, it is possible to implement a standard-input/-output or a pipe-based version, but no clients will probably support it.
And Fennel, running on Lua, has some problems with networking.
The luasocket library becomes a dependency and there&amp;rsquo;s no clear way of implementing asynchronous communication.
Again, not impossible, JeeJah does it, but it&amp;rsquo;s hard to do it properly.&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s also bencode.
It&amp;rsquo;s an encoding that is used by torrents.
Encoding and decoding messages may be slow, especially in a single-threaded REPL.
And we&amp;rsquo;ll need to re-implement half of &lt;code&gt;fennel.view&lt;/code&gt; the serialization function to support all kinds of Lua quirks.&lt;/p&gt;
&lt;p&gt;Nikita also has some thoughts on nREPL:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;You need to add nREPL server dependency to your app. It also has a noticeable startup cost (~500ms on my machine).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Which is a good point, although it&amp;rsquo;s not completely true.
Some existing nREPL clients, such as CIDER, can inject the nREPL dependency into your project, so you don&amp;rsquo;t need to actually ship it with your application.
You develop with nREPL, and use all of its goodies, yet your app has no nREPL once it&amp;rsquo;s shipped.
So you only need to include the nREPL dependency if you want to ship your application with capabilities for remote code execution.&lt;/p&gt;
&lt;p&gt;This is not really possible with Fennel, however.
There&amp;rsquo;s no package manager for fennel, and neither there is a way to dynamically inject an entire nREPL library from the client.
But what about injecting a smaller and simpler protocol?&lt;/p&gt;
&lt;p&gt;Why, yes!
That&amp;rsquo;s exactly what Nikita is doing in their Clojure-Sublimed plugin, and I&amp;rsquo;ve decided to do the same in Emacs.&lt;/p&gt;
&lt;h2 id=&#34;the-protocol&#34;&gt;The protocol&lt;/h2&gt;
&lt;p&gt;If you&amp;rsquo;ve read the mailing list discussion I linked earlier, you&amp;rsquo;ve seen that I envisioned line-based, tab-separated messages.
I&amp;rsquo;ve scraped the idea and went for data-based communication: table in, plist out.
Tables can be interpreted by fennel, we can pattern-match on them, and store arbitrary amounts of data.
Plists are natively understood by Emacs Lisp, which is an implementation language of our client.&lt;/p&gt;
&lt;p&gt;So my idea was that I send something like that to Fennel REPL:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:id&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:eval&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;(+ 1 2 3)&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And get back something like:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lisp&#34; data-lang=&#34;lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:id&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:op&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;accepted&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:data&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:id&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:op&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;eval&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:values&lt;/span&gt; (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;6&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:id&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:op&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;done&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I&amp;rsquo;ll explain why there are three outgoing messages for one incoming, but a bit later.
Right now we need to address the main problem: how do we teach Fennel to work in terms of our protocol?&lt;/p&gt;
&lt;p&gt;When I thought about the protocol for the first time, I thought that it will be part of the Fennel REPL by default.
However, Fennel is quite minimalist, and the choice was not to include anything like that.
The REPL is already better than the Lua one.
This is true when we&amp;rsquo;re talking about interactive usage, but not when we&amp;rsquo;re talking about machine interaction.&lt;/p&gt;
&lt;p&gt;So the answer is - REPL upgrade.&lt;/p&gt;
&lt;h2 id=&#34;upgrading-the-repl&#34;&gt;Upgrading the REPL&lt;/h2&gt;
&lt;p&gt;This technique is using the ability to evaluate in the existing REPL, basically implementing a different REPL at runtime.&lt;/p&gt;
&lt;p&gt;For example, here&amp;rsquo;s the simplest REPL:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fennel&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:fennel&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;while &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;io.write &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;repl&amp;gt;&amp;gt; &amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;io.flush&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;print &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fennel.eval&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;io.read&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Sending it to Fennel REPL starts our own REPL inside of it:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Welcome to Fennel 1.3.0 on PUC Lua 5.4!
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Use ,help to see available commands.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Try installing readline via luarocks for a better repl experience.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;gt;&amp;gt; (let [fennel (require :fennel)] (while true (io.write &amp;#34;repl&amp;gt;&amp;gt; &amp;#34;) (io.flush) (print (fennel.eval (io.read)))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;repl&amp;gt;&amp;gt; (+ 1 2 3)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;6
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;However, it&amp;rsquo;s more of a downgrade, rather than an upgrade.
Our prompt doesn&amp;rsquo;t support unfinished expressions, comma-commands no longer work, and so on.
The purpose of this example is to give you a general idea of how the upgrade process works.&lt;/p&gt;
&lt;p&gt;Reimplementing the REPL from scratch is a tough task, but we don&amp;rsquo;t even have to do it!
Fennel comes with an extensible REPL already: the &lt;code&gt;fennel.repl&lt;/code&gt; function accepts a table with the following callbacks:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;readChunk&lt;/code&gt; - poll for the user input.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;onValues&lt;/code&gt; - called when the REPL returns the result of the evaluation,&lt;/li&gt;
&lt;li&gt;&lt;code&gt;onError&lt;/code&gt; - called when the error occurs,&lt;/li&gt;
&lt;li&gt;&lt;code&gt;pp&lt;/code&gt; - pretty-printer function&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If we implement these functions we&amp;rsquo;ll get a REPL that works the way we need it to.&lt;/p&gt;
&lt;h3 id=&#34;implementing-the-proto--col-type--repl&#34;&gt;Implementing the Proto(col|type) REPL&lt;/h3&gt;
&lt;p&gt;First things first, we need &lt;code&gt;fennel&lt;/code&gt; the library.
We&amp;rsquo;ll use some of its public API, later on, but the feature we&amp;rsquo;re interested in the most right now is &lt;code&gt;fennel.repl&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;{&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;repl&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;view&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;eval&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parser&lt;/span&gt; &amp;amp;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;as&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fennel&lt;/span&gt;} (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:fennel&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;io/read&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:write&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;io/write&lt;/span&gt;} &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;io&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocol&lt;/span&gt; {})
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I&amp;rsquo;m caching &lt;code&gt;fennel&lt;/code&gt; and &lt;code&gt;io&lt;/code&gt; functions to avoid some repeated table lookups.
It&amp;rsquo;s only part of the reason though, but more on that later.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl&lt;/span&gt; []
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocol.message&lt;/span&gt; [[&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:id&lt;/span&gt; 0] [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:op&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;init&amp;#34;&lt;/span&gt;] [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:data&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;done&amp;#34;&lt;/span&gt;]])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;repl&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:readChunk&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocol.read-chunk&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:onValues&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocol.on-values&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:onError&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocol.on-error&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:pp&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;] (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;view&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;view&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;)))}))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I&amp;rsquo;ll go through the implementation of each callback but I will not implement the whole protocol as part of this post.
The protocol while small, still has a lot of code, so I&amp;rsquo;ll only do parts that pose interesting challenges.
It will still be a functional protocol, just not as feature-full as the one I&amp;rsquo;ve actually implemented for Emacs integration.&lt;/p&gt;
&lt;p&gt;First things first, let&amp;rsquo;s make the &lt;code&gt;read-chunk&lt;/code&gt; callback.
In the built-in REPL, it is used to print the prompt and handle user input.
We don&amp;rsquo;t need the prompt, as this will not be an interactive REPL, but we do need to poll for user input.
Not just that, our input comes in a form of a message, so we also need to parse it.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocol.read-chunk&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parser-state&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;io/write&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;gt;&amp;gt; &amp;#34;&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;io.flush&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;io/read&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:l&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ok?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;pcall &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;eval&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ok?&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            {&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;id&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:eval&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;} (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocol.accept&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;id&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:eval&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;error &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;message did not conform to protocol&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;error &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;malformed input: &amp;#34;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;tostring &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt;))))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In the &lt;code&gt;read-chunk&lt;/code&gt; function we&amp;rsquo;re reading a line from the client and &lt;code&gt;eval&lt;/code&gt; it.
I could have used just the parser here, but you&amp;rsquo;ll see why having &lt;code&gt;eval&lt;/code&gt; here is useful.
If the evaluation was successful, we call &lt;code&gt;case&lt;/code&gt; and do pattern matching on the message.
If the message matches any pattern (right now the only one) we know how to process it.
The processing is handled by the &lt;code&gt;accept&lt;/code&gt; function, so let&amp;rsquo;s implement it:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocol.current-id&lt;/span&gt; -1)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocol.accept&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;id&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;op&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocol.message&lt;/span&gt; [[&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:id&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;id&lt;/span&gt;] [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:op&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;accept&amp;#34;&lt;/span&gt;]])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocol.current-id&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;id&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;op&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:eval&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\n&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;error &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;unsupported op: &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;op&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The code is quite simple.
The &lt;code&gt;message&lt;/code&gt; function is what sends a message &lt;code&gt;(:id 1 :op &amp;quot;accepted&amp;quot;)&lt;/code&gt; to the client.
Here&amp;rsquo;s how we implement it:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocol.message&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;kvs&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;io/write&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocol.format&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;kvs&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\n&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;io.flush&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocol.format&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;kvs&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;(&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;table.concat&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;font-weight:bold&#34;&gt;icollect &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;k&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;v&lt;/span&gt;] (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;ipairs &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;kvs&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         (&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;:%s %s&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:format&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;k&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:table&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;type &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;v&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                (&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;(&amp;#34;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;table.concat &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;v&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;)&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;view&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;v&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;)&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;message&lt;/code&gt; function simply prints messages to standard out, while &lt;code&gt;format&lt;/code&gt; handles transforming our sequence of pairs to Emacs Lisp plist.&lt;/p&gt;
&lt;p&gt;Believe it or not, we&amp;rsquo;re almost done.
What&amp;rsquo;s left are &lt;code&gt;on-values&lt;/code&gt; and &lt;code&gt;on-error&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocol.on-values&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocol.data&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocol.current-id&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocol.done&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocol.current-id&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocol.data&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;id&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocol.message&lt;/span&gt; [[&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:id&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;id&lt;/span&gt;] [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:op&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;eval&amp;#34;&lt;/span&gt;] [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:values&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;]]))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocol.on-error&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocol.error&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocol.current-id&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocol.done&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocol.current-id&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocol.error&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;id&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocol.message&lt;/span&gt; [[&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:id&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;id&lt;/span&gt;] [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:op&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;error&amp;#34;&lt;/span&gt;] [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:message&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;]]))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;done&lt;/code&gt; function is the final piece of the puzzle:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocol.done&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;id&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocol.message&lt;/span&gt; [[&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:id&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;id&lt;/span&gt;] [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:op&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;done&amp;#34;&lt;/span&gt;]]))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With all of this, we should get our protocol-based REPL up and running after calling &lt;code&gt;(proto-repl)&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;gt;&amp;gt; (proto-repl)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(:id 0 :op &amp;#34;init&amp;#34; :data &amp;#34;done&amp;#34;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;gt;&amp;gt; {:id 1 :eval &amp;#34;(+ 1 2 3)&amp;#34;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(:id 1 :op &amp;#34;accept&amp;#34;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(:id 1 :op &amp;#34;eval&amp;#34; :values (&amp;#34;6&amp;#34;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(:id 1 :op &amp;#34;done&amp;#34;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Nice!
Now, obviously, this omits a lot of plumbing, error handling, other operations, and so forth, but it should give you the idea.
Also, there are a lot of unnecessary table lookups, I just wrote the code in such a way so you could evaluate them one after another without forward declarations.
But, as a result, sending each of those code blocks to a plain Fennel REPL gives us a new REPL that acts in terms of a specified protocol.
Now we&amp;rsquo;ve really upgraded the REPL.&lt;/p&gt;
&lt;p&gt;Unfortunately, this will not work as is, not because we&amp;rsquo;re missing ops or error handling though.
There&amp;rsquo;s an elephant in the room, consider this message: &lt;code&gt;{:id 1 :eval &amp;quot;(print :foo)&amp;quot;}&lt;/code&gt;.
What would happen if we send this message to our REPL?&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;gt;&amp;gt; {:id 1 :eval &amp;#34;(io.write :foo)&amp;#34;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(:id 1 :op &amp;#34;accept&amp;#34;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;foo(:id 1 :op &amp;#34;eval&amp;#34; :values (&amp;#34;#&amp;lt;file (0x7feff913f780)&amp;gt;&amp;#34;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(:id 1 :op &amp;#34;done&amp;#34;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Right, the output is mixed with the protocol messages.
Here&amp;rsquo;s another one:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;gt;&amp;gt; {:id 1 :eval &amp;#34;(io.read :l)&amp;#34;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(:id 1 :op &amp;#34;accept&amp;#34;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now our REPL suddenly waits for user input midway.
So if another protocol message comes, it will be consumed by this read.
So we have to handle this too.&lt;/p&gt;
&lt;h4 id=&#34;handling-io&#34;&gt;Handling IO&lt;/h4&gt;
&lt;p&gt;Unfortunately, Lua doesn&amp;rsquo;t have any way of redirecting output from standard out to something else.
Clojure kinda does:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;with-out-str&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;.println&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;System/out&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;foo&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Even though we call the &lt;code&gt;println&lt;/code&gt; method of the &lt;code&gt;System/out&lt;/code&gt; class, this expression still returns a string &lt;code&gt;&amp;quot;foo\n&amp;quot;&lt;/code&gt;.
It is possible because in the JVM there are ways to configure that.
I&amp;rsquo;ve tried using &lt;code&gt;io.output&lt;/code&gt; in Fennel, but it can only be set to a file, we can&amp;rsquo;t pass it a table that implements the necessary methods:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; naive approach&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;orig-out&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;io.output&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fake-file&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:data&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:write&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;] (&lt;span style=&#34;font-weight:bold&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t.data&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t.data&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;)))}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;io.output &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fake-file&lt;/span&gt;) &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;; runtime error: bad argument #1 to &amp;#39;output&amp;#39; (FILE* expected, got table)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;print &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:foo&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;io.output &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;orig-out&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fake-file.data&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So we need to set up IO in such a way that it works as expected when we communicate through a protocol, yet wraps the IO inside of the user&amp;rsquo;s code.
Fortunately, we can do that:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;set-io&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;env&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[{&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;stdin&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;stderr&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;stdout&lt;/span&gt;} &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;io&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:write&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fd/write&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fd/read&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &amp;amp;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;as&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fd&lt;/span&gt;} (&lt;span style=&#34;font-weight:bold&#34;&gt;. &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;getmetatable &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;stdin&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:__index&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;env.print&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;env.io.write&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;table.concat &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;] &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\t&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\n&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;env.io.write&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;env.io.output&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:write&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;env.io.read&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mode&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;input&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;env.io.input&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;input&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;stdin&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocol.read&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mode&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;input&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mode&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fd.write&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fd&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;or &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fd&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;stdout&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fd&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;stderr&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocol.message&lt;/span&gt; [[&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:id&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocol.current-id&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                             [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:op&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;print&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                             [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:data&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;table.concat &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;] &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;)]])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fd/write&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fd&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fd&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fd.read&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fd&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fd&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;stdin&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;env.io.read&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fd/read&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fd&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It&amp;rsquo;s a bit of code, but what it essentially does is this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;store the original values of &lt;code&gt;stdin&lt;/code&gt;, &lt;code&gt;stdout&lt;/code&gt;, &lt;code&gt;stderr&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;define a bunch of replacement functions, like &lt;code&gt;env.print&lt;/code&gt;, &lt;code&gt;env.io.write&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;capture original &lt;code&gt;*FILE&lt;/code&gt; metatable in &lt;code&gt;fd&lt;/code&gt; and override it&amp;rsquo;s metamethods.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Unlike tables, all file objects in Lua share the same metatable, so we only need to redefine metatable entries for the &lt;code&gt;stdin&lt;/code&gt; file.
Though it may depend on the implementation of the Lua runtime being used.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;env&lt;/code&gt; argument here is a table that will be used in the &lt;code&gt;fennel.repl&lt;/code&gt;, so we need to change that bit of code.
Because we don&amp;rsquo;t want to actually modify the real &lt;code&gt;_G&lt;/code&gt; table, we&amp;rsquo;ll need to copy it first:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;copy-table&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;collect &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;k&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;v&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;pairs &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;k&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;v&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Here&amp;rsquo;s our new REPL:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl&lt;/span&gt; []
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocol.message&lt;/span&gt; [[&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:id&lt;/span&gt; 0] [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:op&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;init&amp;#34;&lt;/span&gt;] [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:data&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;done&amp;#34;&lt;/span&gt;]])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;repl&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:env&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;doto &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;copy-table&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_G&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;set-io&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:readChunk&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocol.read-chunk&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:onValues&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocol.on-values&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:onError&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocol.on-error&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:pp&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;] (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;view&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;view&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;)))}))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now, when we send the &lt;code&gt;{:id 1 :eval &amp;quot;(io.write :foo)&amp;quot;}&lt;/code&gt; message, we get proper IO handling:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;gt;&amp;gt; (proto-repl)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(:id 0 :op &amp;#34;init&amp;#34; :data &amp;#34;done&amp;#34;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;gt;&amp;gt; {:id 1 :eval &amp;#34;(io.write :foo)&amp;#34;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(:id 1 :op &amp;#34;accept&amp;#34;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(:id 1 :op &amp;#34;print&amp;#34; :data &amp;#34;foo&amp;#34;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(:id 1 :op &amp;#34;eval&amp;#34; :values (&amp;#34;#&amp;lt;file (0x7f0e234e7780)&amp;gt;&amp;#34;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(:id 1 :op &amp;#34;done&amp;#34;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Great, now we get a message with the &lt;code&gt;print&lt;/code&gt; OP, and the data to be printed.
The client then can detect such message and act accordingly.
We can even add support for different descriptors, hide &lt;code&gt;stderr&lt;/code&gt; messages, or color them differently.
But what about the opposite operation?
How do we read input from the user?&lt;/p&gt;
&lt;p&gt;This is a bit tricky.
The general idea is the same, we need to tell the client that the REPL is awaiting input, but we also need to wait in such way that other messages don&amp;rsquo;t get confused with user input.
You can see that in the &lt;code&gt;set-io&lt;/code&gt; function, the &lt;code&gt;io.read&lt;/code&gt; calls &lt;code&gt;protocol.read&lt;/code&gt; if the descriptor is &lt;code&gt;stdin&lt;/code&gt;.
Let&amp;rsquo;s implement &lt;code&gt;protocol.read&lt;/code&gt; now:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocol.read&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mode&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tmpname&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;with-open &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;p&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;io.popen &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;mktemp -u /tmp/proto-repl.XXXXXXXX 2&amp;gt;/dev/null&amp;#34;&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;p&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:l&lt;/span&gt;))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;io.popen &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;mkfifo &amp;#39;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tmpname&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#39; 2&amp;gt;/dev/null&amp;#34;&lt;/span&gt;)) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:close&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocol.message&lt;/span&gt;  [[&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:id&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocol.current-id&lt;/span&gt;] [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:op&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;read&amp;#34;&lt;/span&gt;] [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:data&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tmpname&lt;/span&gt;]])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;with-open &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;io.open &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tmpname&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mode&lt;/span&gt;))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;io.popen &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;rm -f &amp;#39;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tmpname&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#39;&amp;#34;&lt;/span&gt;)) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:close&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now, if we call &lt;code&gt;io.read&lt;/code&gt; as part of our code, we should get back a message:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;gt;&amp;gt; {:id 1 :eval &amp;#34;(io.read :n)&amp;#34;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(:id 1 :op &amp;#34;accept&amp;#34;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(:id 1 :op &amp;#34;read&amp;#34; :data &amp;#34;/tmp/proto-repl.adTbqVI2&amp;#34;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If we write data, in this case a number to that file, we should get it processed by the REPL:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;echo&lt;/span&gt; 27 &amp;gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;/tmp/proto-repl.adTbqVI2&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And indeed we get the usual messages we get from &lt;code&gt;eval&lt;/code&gt; OP:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(:id 1 :op &amp;#34;eval&amp;#34; :values (&amp;#34;27&amp;#34;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(:id 1 :op &amp;#34;done&amp;#34;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Unfortunately, Lua doesn&amp;rsquo;t have an inbuilt filesystem library, so this method is not cross-platform.
It will probably work under BSD systems, and Macs, but not under Windows, unless you&amp;rsquo;re using WSL, but still not guaranteed.
I don&amp;rsquo;t have a Windows PC, so I can&amp;rsquo;t test, but if you know a cross-platform, or even just a special case for Windows, for creating a named FIFO pipe, and attaching to it, it&amp;rsquo;d be great if you reach me.&lt;/p&gt;
&lt;p&gt;This pretty much concludes our very basic, yet fully functional protocol!&lt;/p&gt;
&lt;p&gt;The IO part is the trickiest part because there may be specifics to how files are read, but again, we can&amp;rsquo;t expect that the target application will have &lt;code&gt;luafilesystem&lt;/code&gt; installed.
But there&amp;rsquo;s a way to work this around.
So we do have a final small change to make in our &lt;code&gt;read-chunk&lt;/code&gt; function.&lt;/p&gt;
&lt;h4 id=&#34;making-the-protocol-extensible-at-runtime&#34;&gt;Making the protocol extensible at runtime&lt;/h4&gt;
&lt;p&gt;You may remember that I&amp;rsquo;ve chosen &lt;code&gt;eval&lt;/code&gt; over &lt;code&gt;parser&lt;/code&gt; in the REPL to work with incoming messages.
There was a specific reason for it - the message can actually be not for the target application, but for the REPL itself!
And we don&amp;rsquo;t even need any kind of special-casing for it, only a &lt;code&gt;nop&lt;/code&gt; OP:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocol.read-chunk&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parser-state&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;io/write&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;gt;&amp;gt; &amp;#34;&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;io.flush&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;io/read&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:l&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ok?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;pcall &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;eval&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ok?&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          {&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;id&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:eval&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;} (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocol.accept&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;id&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:eval&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          {&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;id&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:nop&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;} &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\n&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;error &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;message did not conform to protocol&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;error &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;malformed input: &amp;#34;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;tostring &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt;))))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We also need to expose the &lt;code&gt;protocol&lt;/code&gt; table in the &lt;code&gt;_G&lt;/code&gt; table, and &lt;code&gt;fennel&lt;/code&gt; for convenience:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_G.proto-repl&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocol&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_G.fennel&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fennel&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With these changes, we can send a message like &lt;code&gt;(do (print &amp;quot;hi!&amp;quot;) {:id 1 :nop &amp;quot;&amp;quot;})&lt;/code&gt; and it will be processed by the &lt;code&gt;eval&lt;/code&gt;, and the &lt;code&gt;print&lt;/code&gt; call will be evaluated outside of the main protocol handling.
Thus, we can get fancy!
Here, for example, how we can make our protocol respond in JSON:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;((&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;to-json-protocol&lt;/span&gt; []
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_G.proto-repl.format&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;{&amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;table.concat&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              (&lt;span style=&#34;font-weight:bold&#34;&gt;icollect &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;k&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;v&lt;/span&gt;] (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;ipairs &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;v&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:table&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;type &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;v&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            (&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;[&amp;#34;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;table.concat &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;v&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;, &amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;]&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fennel.view&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;v&lt;/span&gt;))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  (&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fennel.view&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;k&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;: &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;v&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;, &amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;}&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:id&lt;/span&gt; 15 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:nop&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;}))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now, if we send this to the REPL, we will get nothing back, since the OP in question is &lt;code&gt;nop&lt;/code&gt;, however, the &lt;code&gt;format&lt;/code&gt; function will be redefined.
So if we send one more message, the usual &lt;code&gt;eval&lt;/code&gt; one, we&amp;rsquo;ll get back JSON messages in response:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;gt;&amp;gt; {:id 1 :eval &amp;#34;(+ 1 2 3)&amp;#34;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&amp;#34;id&amp;#34;: 1, &amp;#34;op&amp;#34;: &amp;#34;accept&amp;#34;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&amp;#34;id&amp;#34;: 1, &amp;#34;op&amp;#34;: &amp;#34;values&amp;#34;, &amp;#34;data&amp;#34;: [&amp;#34;6&amp;#34;]}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&amp;#34;id&amp;#34;: 1, &amp;#34;op&amp;#34;: &amp;#34;done&amp;#34;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This is why languages with the capability to run any code at runtime are cool in my opinion.
We can build our application while it is running.
Any protocol method, that we&amp;rsquo;ve defined can be re-implemented at runtime.
So if you&amp;rsquo;re running Windows, you can redefine &lt;code&gt;protocol.read&lt;/code&gt; to support your particular platform without even asking me to update the code.
(But please, if you know a more portable way of handling input, send me a message).&lt;/p&gt;
&lt;p&gt;As a final change, let&amp;rsquo;s remove the &lt;code&gt;&amp;gt;&amp;gt;&lt;/code&gt; prompt from the &lt;code&gt;read-chunk&lt;/code&gt;, and we&amp;rsquo;re done.
The prompt is not needed, it was only to help you differentiate what messages we&amp;rsquo;ve sent, and what messages we receive.
For the machine the prompt will only get in the way:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocol.read-chunk&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parser-state&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;io/read&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:l&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ok?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;pcall &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;eval&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ok?&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          {&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;id&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:eval&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;} (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocol.accept&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;id&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:eval&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          {&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;id&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:nop&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;} &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\n&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;error &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;message did not conform to protocol&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;error &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;malformed input: &amp;#34;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;tostring &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt;))))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Finally, we can add the call to &lt;code&gt;proto-repl&lt;/code&gt; to our protocol code, so right after we&amp;rsquo;ve sent it the new REPL is started automatically:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now, for real, this concludes the basic protocol implementation.
This is, in fact, what I started with, and then gradually made it more mature by extending the number of operations the protocol supports, and making it more robust.
Not every protocol method is exposed to be changed in my implementation though.
This was more like a demo that you can follow, but in the real version of the protocol, it is a single giant function that gets sent to the REPL in one go.&lt;/p&gt;
&lt;p&gt;Now, we can talk about the client, because without the client our protocol has no value.&lt;/p&gt;
&lt;h2 id=&#34;the-client&#34;&gt;The client&lt;/h2&gt;
&lt;p&gt;My editor of choice is Emacs for many reasons.
And this is one of them - we can make all kinds of applications in Emacs, including a custom client for a custom protocol.
We&amp;rsquo;re like full-stack developers now, but our backend is written in Fennel and our frontend will be written in Emacs Lisp.&lt;/p&gt;
&lt;p&gt;As I mentioned at the beginning of the post, I&amp;rsquo;ve chosen plists because Emacs understands them natively.
Still, our messages come in as strings, so we&amp;rsquo;ll need to parse them.
But how will we organize our client to begin with?&lt;/p&gt;
&lt;h3 id=&#34;comint&#34;&gt;Comint&lt;/h3&gt;
&lt;p&gt;The current implementation of the Fennel REPL in the &lt;code&gt;fennel-mode&lt;/code&gt; package uses the inbuilt &lt;code&gt;comint&lt;/code&gt; package to do all of the heavy lifting.
Comint is Emacs&amp;rsquo; generic interface for providing user interaction to asynchronous processes.
The selling point is that you can start almost any interactive program in Comint, set the prompt regexp and it will work.
However, the problems start when we begin building a machine-to-machine interface over a human-to-machine interface.&lt;/p&gt;
&lt;p&gt;As with any kind of interface it involves parsing the output.
Our protocol is no different here, we&amp;rsquo;re still going to parse output, so what&amp;rsquo;s wrong with doing it via comint, especially since it already knows how to do the majority of things?
Comint even has the redirection facility to deal with such tasks specifically.&lt;/p&gt;
&lt;p&gt;The answer is - there&amp;rsquo;s no message queue that spans over both comint and the target process.&lt;/p&gt;
&lt;p&gt;For example, you can send a long-running code to the REPL that will print something after a long period of time, like this one:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;do &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;for &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; 1 1000000] &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;print &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;foo&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;bar&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;baz&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Once the loop is completed the stdout of the process will contain a string like this one: &lt;code&gt;foo\tbar\tbaz&lt;/code&gt;.
Comint will grab it and print it to the REPL.
All good.&lt;/p&gt;
&lt;p&gt;But if we set up a redirect while this loop runs, that, say, queries for the completions from the REPL, we can get into a funny situation.
Imagine, user typed &lt;code&gt;f&lt;/code&gt; and pressed the &lt;kbd&gt;Tab&lt;/kbd&gt; key.
The current implementation of completion support in &lt;code&gt;fennel-mode&lt;/code&gt; package will use a comint redirect mechanism, and for this case, it will send the following expression &lt;code&gt;,complete f&lt;/code&gt; to the REPL.
The output of the &lt;code&gt;,complete f&lt;/code&gt; command will be &lt;code&gt;fn\tfor\tfcollect\tfaccumulate&lt;/code&gt;, another tab-separated line, but our REPL is busy at the moment, running the loop.
What can go wrong?&lt;/p&gt;
&lt;p&gt;What happens is that the &lt;code&gt;,complete f&lt;/code&gt; is buffered by the process stdin, and not processed unless the REPL is able to read the message.
The comint redirect, however, is waiting for the output from the process and grabs what&amp;rsquo;s first to appear there.
So it grabs the output from the &lt;code&gt;print&lt;/code&gt; function and uses it as the data for the completion engine.
While the REPL gets the output from the &lt;code&gt;,complete&lt;/code&gt; command:&lt;/p&gt;
&lt;figure class=&#34;invertable&#34;&gt;&lt;img src=&#34;https://andreyor.st/2023-03-25-implementing-a-protocol-based-fennel-repl-and-emacs-client/redirection-race.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;This is a race, and the last request from comint wins the first output from the process.
It just so happens that both messages used a format similar enough for completion to work.
In most cases, completion will silently fail, and the REPL will just lose the results of the expression.&lt;/p&gt;
&lt;p&gt;Comint is not suited for working with a protocol like ours, but we can still reuse a fair bit of comint features in our client.
Instead, we&amp;rsquo;ll have two separate processes - one for the server that implements the protocol, and one for the REPL that acts as a fake process with all comint goodies.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s what our architecture will look like:&lt;/p&gt;
&lt;figure class=&#34;invertable&#34;&gt;&lt;img src=&#34;https://andreyor.st/2023-03-25-implementing-a-protocol-based-fennel-repl-and-emacs-client/scheme.svg&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;By separating input from output, and effects from parsing, we avoid all problems with comint racing over process output and misparsing different commands.
And the input doesn&amp;rsquo;t have to come from comint, we can send messages via the input sender from anywhere, so code interaction in the buffer is easy to implement too.&lt;/p&gt;
&lt;p&gt;Notice how ID comes into play here - we read user input, format it as a message, and assign it an ID, which we send to the server.
While doing so, we register a callback for the message in a hash table, that uses message IDs as keys, and callback as values.
Once the server has processed the message, it responds with several messages of its own, all of which include a callback.
We then parse these messages in the output filter, which looks for the callback in the hash table.
If the callback was found, it is being called with the data from the message according to the protocol.
And the callback can print the result back to the REPL, to a completion engine, or to any other target buffer.&lt;/p&gt;
&lt;p&gt;This is also the reason why our protocol answers with special messages &lt;code&gt;accept&lt;/code&gt; and &lt;code&gt;done&lt;/code&gt; before and after the data-oriented ones, like &lt;code&gt;values&lt;/code&gt;, &lt;code&gt;print&lt;/code&gt;, &lt;code&gt;read&lt;/code&gt;, and such.
All protocol operations require a callback to reach the user, but once the message is processed fully its callback can be released.
This is what the &lt;code&gt;done&lt;/code&gt; OP is for in our protocol, but what about &lt;code&gt;accept&lt;/code&gt;?&lt;/p&gt;
&lt;p&gt;Right now in my design, &lt;code&gt;accept&lt;/code&gt; is a noop, but I can see some potential later use cases.
One of them is for implementing asynchronous timeouts.
For example, when we register a callback we can store the maximum amount of time that is meaningful for such a callback to exist.
Once the server answers with the &lt;code&gt;accepted&lt;/code&gt; OP, we can check if the time since callback registration exceeds the lifespan of the callback.
If not, we continue waiting for other messages, otherwise, we unassign it.&lt;/p&gt;
&lt;p&gt;Another possible use for the  &lt;code&gt;accept&lt;/code&gt; OP is to cancel previous callbacks.
This is not particularly useful in the context of a single-threaded Lua application, as it will always process messages sequentially, but nothing prevents us from implementing an asynchronous REPL.
In an asynchronous context, it is quite possible that a message will be accepted before the previous one was fully processed.
And in cases like when we query for completions, we are interested only in the latest results, so we can use &lt;code&gt;accept&lt;/code&gt; to cancel the previous completion callback.&lt;/p&gt;
&lt;p&gt;But enough talk, let&amp;rsquo;s write some code!&lt;/p&gt;
&lt;h3 id=&#34;server-process&#34;&gt;Server process&lt;/h3&gt;
&lt;p&gt;Now, I must say, that in the same way that we didn&amp;rsquo;t implement a full-blown protocol, we won&amp;rsquo;t implement a full-blown client.
However, I will try to provide a complete enough example that you&amp;rsquo;ll be able to make your own client like this in the future if you wanted to.&lt;/p&gt;
&lt;p&gt;We start simple - we need a way to start the server process that will act as a pipe:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defvar&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl--upgrade-code&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;...whole protocol code...&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defvar&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl-process&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; *proto-repl*&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defvar&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl--message-callbacks&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defvar&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl--message-id&lt;/span&gt; 0)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl--start-server&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;command&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Start the Fennel REPL process.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;COMMAND is used to start the Fennel REPL.  Sends the upgrade code
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;to the REPL and waits for completion via a callback.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proc&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;make-process&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:name&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl-process&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:buffer&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl-process&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:command&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;split-string-shell-command&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;command&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:connection-type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;pipe&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:filter&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;#&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl--process-filter&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer-disable-undo&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl-process&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;with-current-buffer&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl-process&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mode-line-process&lt;/span&gt; &amp;#39;(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;:%s&amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Waiting for Fennel REPL initialization...&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl--message-callbacks&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl--message-id&lt;/span&gt; 0)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl--assign-callback&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;#&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl--start-repl&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;send-string&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proc&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;format&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;%s\n&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl--upgrade-code&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;First of all, let&amp;rsquo;s address the elephant in the room - the protocol code.
Our package needs to somehow obtain the protocol code and send it to the REPL process.
I&amp;rsquo;ve chosen to store it as a string, even though it is a very long string.
The reasoning behind this is that I want this file to be both self-contained and because package management in Emacs is a mess, and there&amp;rsquo;s no reliable way to obtain a file that is located in the same package unless they&amp;rsquo;re both in the same directory, which may not be the case&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;.
Not the most elegant solution, but it works.&lt;/p&gt;
&lt;p&gt;Next up, we define two more variables, one for process buffer name, and another one for storing callbacks.
For simplicity&amp;rsquo;s sake, I&amp;rsquo;ll use an associative list for callbacks, but in the real client, a hash table with fast equality function should be used.&lt;/p&gt;
&lt;p&gt;And the main piece of code - the function that starts the process.
Code should be mostly self-explanatory, but in case it&amp;rsquo;s not, the main idea is to start the process and assign a process filter to it.
The process filter will be the next thing we&amp;rsquo;ll implement, so I&amp;rsquo;ll save the explanation for later.
After that, we do a few setup steps and send the message to the process with the upgrade code.
Sending messages is another bit part of the client, and we&amp;rsquo;ll look into them as well.&lt;/p&gt;
&lt;h4 id=&#34;process-filtering&#34;&gt;Process filtering&lt;/h4&gt;
&lt;p&gt;The process filter is a function that accepts two arguments, the process being filtered and the data that was read from it.
By specifying a custom process filter we actually prevent any output from the process in the process buffer, so some kind of logging should be implemented.
And here&amp;rsquo;s our first challenge.&lt;/p&gt;
&lt;p&gt;Our protocol works on a one message per line basis, yet the output from the process is received in hunks instead of lines.
It is quite possible to receive a message that contains the start of the next message without its end.
In a case like this, a custom encoding would be a much better choice than using a line-based protocol, but we can workaround the problem by implementing buffering.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defvar&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl--message-buf&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl--buffered-split-string&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;string&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Split STRING on newlines.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;If the string doesn&amp;#39;t end with a newline character, the last (or
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;the only) line of the string is buffered and excluded from the
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;result.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;strings&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;string-lines&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;string&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;when&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl--message-buf&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;setcar&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;strings&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;concat&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl--message-buf&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;car&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;strings&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl--message-buf&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;string-suffix-p&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\n&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;string&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;strings&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl--message-buf&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;car&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;last&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;strings&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nbutlast&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;strings&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;First, we split the string on newlines, removing empty lines, as they&amp;rsquo;re irrelevant to us.
Next, if we have something in our buffer, we concatenate it with the first line, as it is a leftover from the previous hunk.
Then we check if the string ends with a newline, if it is we return lines as is.
If not, we set the buffer to the last incomplete line and return everything except for the last line.&lt;/p&gt;
&lt;p&gt;This way, the protocol is much more resilient to process buffering, and the fact that Emacs doesn&amp;rsquo;t read line by line on most systems.
Yes, our protocol is line-based and it&amp;rsquo;s not exactly machine-friendly, but it is much easier than using some kind of encoding, like bencode.&lt;/p&gt;
&lt;p&gt;Once we have a list of lines, we can begin processing them.
Here&amp;rsquo;s our process filter:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl--process-filter&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Parse the MESSAGE and process it with the callback handler.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;dolist&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl--buffered-split-string&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;substring&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;string-match-p&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;(:id &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;when-let&lt;/span&gt; ((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;condition-case&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                           (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;car&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-from-string&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                         (error &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;when&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;plistp&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl--handle-protocol-op&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;with-current-buffer&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl-process&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;goto-char&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;point-max&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;insert&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In this function, we&amp;rsquo;re going to work on a line-by-line basis because the first thing we do is split the incoming message.
However, the input massaging doesn&amp;rsquo;t stop there - for each message we want to strip everything that is not part of it.
If you remember, before we had our IO wrapped, the output from &lt;code&gt;io.write&lt;/code&gt; was right before one of the messages.
This is partly why we do it.
In fact, this should never happen, but we can&amp;rsquo;t control it before the protocol is initialized, especially because by default Fennel REPL is quite verbose.
If we send a partially complete expression to the base Fennel REPL it will display a &lt;code&gt;..&lt;/code&gt; prompt, so while sending our protocol line by line we&amp;rsquo;ll get back a lot of dots preceding the initialization message:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;...............................................(:id 0 :op &amp;#34;initialized&amp;#34;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So we have to deal with it.
This function is also the right place to add logging, but I&amp;rsquo;m omitting it for the sake of simplicity and just emitting everything to the process buffer.&lt;/p&gt;
&lt;p&gt;After we&amp;rsquo;ve split the input, and truncated it we parse it with the &lt;code&gt;read-form-string&lt;/code&gt; function.
This again is where some errors might lurk - if our protocol ever would return two messages in a single line, we&amp;rsquo;ll lose the last one.
So you might want to check for that.
If the message was read successfully, we also check if it is a plist with the &lt;code&gt;plistp&lt;/code&gt; function, and pass it to the protocol handler.&lt;/p&gt;
&lt;p&gt;The protocol handler is the meat of our client.
It manages callbacks for each message and handles all supported protocol OPs.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl--handle-protocol-op&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Handle protocol MESSAGE.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;Message contains an id, operation to execute, and any additional
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;data related to the operation.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;id&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;plist-get&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:id&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;op&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;plist-get&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:op&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;when-let&lt;/span&gt; ((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;callback&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl--get-callback&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;id&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;pcase&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;op&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;accept&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;done&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl--unassign-callback&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;id&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;unless&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl--callbacks-pending?&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl--display-prompt&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;eval&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;values&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;plist-get&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:values&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;funcall&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;callback&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;format&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;%s\n&amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;string-join&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;values&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\t&amp;#34;&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;print&amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl--print&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;plist-get&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:data&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;read&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;inhibit-message&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;write-region&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-string&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;stdin: &amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;plist-get&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:data&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;error&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl--display-error&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;plist-get&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:type&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;plist-get&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:data&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;plist-get&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:traceback&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;init&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl--unassign-callback&lt;/span&gt; 0)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;funcall&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;callback&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;))))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Even though our protocol is quite small, we do have a few OPs to support.
As I&amp;rsquo;ve mentioned the &lt;code&gt;accept&lt;/code&gt; OP is a nop, but the &lt;code&gt;done&lt;/code&gt; OP is quite important.
You can see, that we unassign the callback for the message, and then check if there are pending callbacks.
This allows us to avoid drawing the prompt in the REPL because pending callbacks mean that the REPL is still busy.&lt;/p&gt;
&lt;p&gt;Another special OP is the &lt;code&gt;init&lt;/code&gt; one.
It has a special callback with the ID 0, and this callback is strictly for the REPL initialization.
Other callbacks should be pretty much self-explanatory.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s write functions for dealing with callbacks:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl--get-callback&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;id&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Get a callback for a message with this ID.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cdr&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;assoc&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;id&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl--message-callbacks&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl--unassign-callback&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;id&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Remove callback assigned to a message with this ID.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl--message-callbacks&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;assoc-delete-all&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;id&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl--message-callbacks&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl--assign-callback&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;callback&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Assign CALLBACK and return the id it was assigned to.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;id&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl--message-id&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;add-to-list&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;proto-repl--message-callbacks&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cons&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;id&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;callback&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl--message-id&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;1+&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;id&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;id&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl--callbacks-pending?&lt;/span&gt; ()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Check for callbacks that still waiting for the DONE message.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl--message-callbacks&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With these, we can do all operations on callbacks that our client requires.
The &lt;code&gt;proto-repl--assign-callback&lt;/code&gt; is an interesting one.
It increments the ID after it assigned the callback, and returns the ID of the callback itself.
This is our main interface for sending messages to the REPL.&lt;/p&gt;
&lt;h4 id=&#34;user-interaction&#34;&gt;User interaction&lt;/h4&gt;
&lt;p&gt;With the server part mostly done, we can make the comint part that is an actual user interface to our protocol-based REPL.
Let&amp;rsquo;s start with the mode for the REPL:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;fennel-mode&lt;/span&gt;) &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; for font-lock&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defvar&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl-buffer&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;*Fennel Proto REPL*&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defvar&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl-prompt&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;gt;&amp;gt; &amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;define-derived-mode&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl-mode&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;comint-mode&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Fennel Proto REPL&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Major mode for Fennel REPL.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;\\{proto-repl-mode-map}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;comint-prompt-regexp&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;format&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;^%s&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl-prompt&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;comint-prompt-read-only&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;comint-input-sender&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;proto-repl--input-sender&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mode-line-process&lt;/span&gt; &amp;#39;(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;:%s&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;setq-local&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;comment-end&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fennel-font-lock-setup&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;set-syntax-table&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fennel-mode-syntax-table&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;unless&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;comint-check-proc&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;current-buffer&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proc&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;start-process&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl-buffer&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;current-buffer&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;add-hook&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;kill-buffer-hook&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;lambda&lt;/span&gt; ()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;when-let&lt;/span&gt; ((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proc&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;get-buffer-process&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl-process&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;delete-process&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proc&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;insert&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;;; Welcome to the Fennel Proto REPL\n&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;set-marker&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;process-mark&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proc&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;point&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl--display-prompt&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;There&amp;rsquo;s a lot to dig in, but the main part is where we start a new process with the &lt;code&gt;start-process&lt;/code&gt; function.
This process is what the comint will use for it&amp;rsquo;s internal implementation of input handling and such.
Let&amp;rsquo;s look at the &lt;code&gt;fennel-repl--input-sender&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl--input-sender&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;input&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Sender for INPUT from the REPL buffer to REPL process.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;let*&lt;/span&gt; ((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;id&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl--assign-callback&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;#&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl--print&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mesg&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;format&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;{:id %s :%s %S}\n&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;id&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;eval&amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;substring-no-properties&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;input&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;send-string&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl-process&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mesg&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This function is responsible for sending the input to the server as a message, so it formats user input like one.
Before sending the message it assigns the callback, and then the rest of our system should just work.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;proto-repl--display-prompt&lt;/code&gt; is a simple function that just prints the prompt to the REPL buffer:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl--display-prompt&lt;/span&gt; ()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Display prompt.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proc&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;get-buffer-process&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl-buffer&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;comint-output-filter&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proc&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl-prompt&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And the &lt;code&gt;proto-repl--print&lt;/code&gt; is a default callback for printing anything to the REPL buffer:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl--print&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proc&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;get-buffer-process&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl-buffer&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;comint-output-filter&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proc&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This function is almost identical to the prompt displaying one, but it is mostly for the simplicity&amp;rsquo;s sake.
In fact the real one is a bit more complicated because we want to print stuff before the prompt if we&amp;rsquo;re sending code not from the REPL but from the buffer.
I&amp;rsquo;ve left this out as it&amp;rsquo;s not that hard to implement.&lt;/p&gt;
&lt;p&gt;So the last thing we need is to actually start the REPL in a buffer:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl--start-repl&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Start the REPL.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Fennel Proto REPL initialized&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;with-current-buffer&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;get-buffer-create&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl-buffer&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl-mode&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pop-to-buffer&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;current-buffer&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This one is a callback we&amp;rsquo;ve used when starting a server.
And this one is the funtion for the end user:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl&lt;/span&gt; ()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Fennel Proto REPL.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;interactive&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;if-let&lt;/span&gt; ((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;repl-buffer&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;get-buffer&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl-buffer&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;process-live-p&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;get-buffer-process&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;repl-buffer&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pop-to-buffer&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;repl-buffer&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl--start-server&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;fennel --repl&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl--start-server&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;fennel --repl&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;get-buffer&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl-buffer&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And the client is done!
Let&amp;rsquo;s try it:&lt;/p&gt;
&lt;figure class=&#34;invertable&#34;&gt;&lt;img src=&#34;https://andreyor.st/2023-03-25-implementing-a-protocol-based-fennel-repl-and-emacs-client/new-client.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;On the left is the REPL buffer, which is responsible for input handling, and sending messages.
On the right is the server buffer, which shows the process log.
As you can see, we&amp;rsquo;ve got the usual messages for all our expressions.&lt;/p&gt;
&lt;h2 id=&#34;new-fennel-repl-integration-for-emacs&#34;&gt;New Fennel REPL integration for Emacs&lt;/h2&gt;
&lt;p&gt;Sure, the implementation of the client and the protocol has a lot of room for improvement, but it is enough for the purpose of this post.
As a matter of fact, I&amp;rsquo;m almost done working on a proper implementation, and most of the code here is greatly simplified version of what I&amp;rsquo;ve already made for the &lt;code&gt;fennel-mode&lt;/code&gt; package.
For now it lives in a separate module, but I have high hopes on completely replacing inbuilt comint-based client with this protocol based one, once I test it more.
It will probably still live in a separate module for a while even after I will consider it mostly complete, so users would be able to try it in their environments, but my hopes are high.&lt;/p&gt;
&lt;p&gt;There is one problem though - this protocol implementation may not work in some contexts.
For instance, if you&amp;rsquo;re already providing a custom REPL in your application, that is based on the &lt;code&gt;fennel.repl&lt;/code&gt; and implements its own &lt;code&gt;readChunk&lt;/code&gt;, that, for example, doesn&amp;rsquo;t read from &lt;code&gt;stdin&lt;/code&gt;.
One such example is the &lt;a href=&#34;https://love2d.org/&#34; target=&#34;_blank&#34;&gt;LÖVE&lt;/a&gt; game engine, there&amp;rsquo;s an &lt;a href=&#34;https://gitlab.com/alexjgriffith/min-love2d-fennel/-/blob/master/lib/stdio.fnl&#34; target=&#34;_blank&#34;&gt;implementation&lt;/a&gt; of the REPL that polls for input on a separate thread.
If we send our protocol-based REPL to such a custom REPL, we&amp;rsquo;ll negate all the efforts made to make the REPL work in a non-blocking way.
For Clojure, this works because the REPL already lives in its own thread, but there are no threads in Lua apart from what coroutines provide.&lt;/p&gt;
&lt;p&gt;So I&amp;rsquo;m still thinking about how to handle the situation when the upgrade is impossible.
This is why the official protocol is much better than such a custom one, but alas.&lt;/p&gt;
&lt;p&gt;You can already try this REPL if you check out the &lt;code&gt;proto-repl&lt;/code&gt; branch in the &lt;a href=&#34;https://git.sr.ht/~technomancy/fennel-mode/tree/proto-repl&#34; target=&#34;_blank&#34;&gt;fennel-mode&lt;/a&gt; project.
If you&amp;rsquo;re using &lt;a href=&#34;https://github.com/radian-software/straight.el&#34; target=&#34;_blank&#34;&gt;straight.el&lt;/a&gt;, or &lt;a href=&#34;https://github.com/quelpa/quelpa&#34; target=&#34;_blank&#34;&gt;Quelpa&lt;/a&gt;, or Emacs version recent enough to have the &lt;code&gt;package-vc-install&lt;/code&gt; function, you can try installing fennel-mode and supplying the &lt;code&gt;proto-repl&lt;/code&gt; branch to the recipe.&lt;/p&gt;
&lt;p&gt;If you want to experiment with the code that is provided in this article for example for the purpose of building a similar protocol for another language, this very article is written in the literate style, and you can grab it &lt;a href=&#34;https://andreyor.st/2023-03-25-implementing-a-protocol-based-fennel-repl-and-emacs-client.org&#34;&gt;here&lt;/a&gt;.
Run the &lt;code&gt;org-babel-tangle&lt;/code&gt; on it, and you should get the &lt;code&gt;protocol.fnl&lt;/code&gt; file with all the necessary functions, and &lt;code&gt;proto-repl.el&lt;/code&gt; file with the Emacs Lisp code.
You&amp;rsquo;ll need to put the protocol code to the &lt;code&gt;proto-repl--upgrade-code&lt;/code&gt; variable, as I&amp;rsquo;ve excluded it from the article&amp;rsquo;s text since it was making that particular code block too long.&lt;/p&gt;
&lt;p&gt;Thank you for reading!
I hope this was interesting and useful.
As always, if you have any thoughts you want to discuss on the matter, feel free to contact me via one of the ways mentioned on the &lt;a href=&#34;https://andreyor.st/about#links&#34;&gt;about&lt;/a&gt; page.&lt;/p&gt;
&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;
&lt;p&gt;Package managers like straight.el or quelpa use recipes to specify what files to use during the build process.
It is possible that users of the package may not notice that the recipe needs to be changed.
This can be handled by the package archive like MELPA, but I&amp;rsquo;d rather not bother with it right now.&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: Implementing a protocol-based Fennel REPL and Emacs client&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Sat, 25 Mar 2023 19:47:00 +0300</pubDate>
    </item><item>
      <title>Small languages with little tooling</title>
      <link>https://andreyor.st/posts/2022-11-02-small-languages-with-little-tooling/</link>
      <guid>https://andreyor.st/posts/2022-11-02-small-languages-with-little-tooling/</guid>
      <description>&lt;p&gt;When it comes to software I prefer things that are simple and small, even though I&amp;rsquo;m using Emacs.
This is mainly the reason why my favorite languages are Clojure and Fennel.
However, it doesn&amp;rsquo;t end on programming languages themselves, I like small tools in general.
One such example would be &lt;a href=&#34;https://kakoune.org/&#34; target=&#34;_blank&#34;&gt;Kakoune&lt;/a&gt; - a text editor, inspired by Vim, which focuses on multiple selections.&lt;/p&gt;
&lt;p&gt;Kakoune doesn&amp;rsquo;t have a scripting language, and when I started using it, the collection of plugins was relatively small, and it didn&amp;rsquo;t have a plugin manager at all.
With a limited amount of options, it&amp;rsquo;s easier to start using particular software, because you don&amp;rsquo;t have the problem of choice, especially when you know nothing about the things that you&amp;rsquo;re choosing from.
You pick it up, and you&amp;rsquo;re good to go.
This was a major problem for me to get into Emacs, as, as opposed to Kakoune, not only does it has a pretty huge core full of features, but it also has a ton of packages written by users over the years, and several package managers to install those.&lt;/p&gt;
&lt;p&gt;Eventually, I figured things out, and now I&amp;rsquo;m a happy Emacs user, but its enormous pack of inbuilt features still bothers me, and Kakoune made me understand why I like small ecosystems.
It&amp;rsquo;s because in a small ecosystem it&amp;rsquo;s easier to see what is needed by people, and you can participate in making things better not just for yourself but for everyone.&lt;/p&gt;
&lt;p&gt;Don&amp;rsquo;t quote me out on this, but I think &lt;a href=&#34;https://github.com/andreyorst/plug.kak&#34; target=&#34;_blank&#34;&gt;plug.kak&lt;/a&gt; was the first fully featured plugin and configuration manager for Kakoune, which I made mostly for myself, but to my surprise, it got to be pretty popular.
There even were plugins (written by other people) that suggested using &lt;code&gt;plug.kak&lt;/code&gt; as a preferred way of installing them.
Before &lt;code&gt;plug.kak&lt;/code&gt; people had to use the default mechanism of loading, which used an &lt;code&gt;autoload&lt;/code&gt; directory to specify what Kakoune should load at startup, and creating a such directory in your config disabled system-wide &lt;code&gt;autoload&lt;/code&gt; directory, making Kakoune featureless.
This was one of my motivations behind &lt;code&gt;plug.kak&lt;/code&gt;, because I saw issues in Kakoune&amp;rsquo;s repository titled mentioned that the creation of the &lt;code&gt;auotload&lt;/code&gt; dir broke their config in an unexpected way of not loading any of the inbuilt features.
My approach was to create a, hopefully, small system that knows where to look for external stuff and how to load and configure it.
And people seemed to like it.&lt;/p&gt;
&lt;p&gt;I also wrote a bunch of other plugins for Kakoune, all of which are listed &lt;a href=&#34;https://andreyor.st/about/#kakoune&#34;&gt;here&lt;/a&gt;, if you&amp;rsquo;re interested.
This helped me shape Kakoune into a thing that I liked to use, having features that I need, and also igniting my interest in programming in general, because the tools I built were used by other Kakoune users, and it was inspiring.
Later on alternatives to &lt;code&gt;plug.kak&lt;/code&gt; appeared, and I&amp;rsquo;m glad because they were simpler and more efficient.
I no longer maintain &lt;code&gt;plug.kak&lt;/code&gt;, as I no longer use Kakoune, but it still has a place in my heart.&lt;/p&gt;
&lt;p&gt;Before Kakoune I made plugins for Vim, but given that the plugin ecosystem was already saturated, my plugins were made mostly for myself and I wasn&amp;rsquo;t hoping that anybody else would prefer them to alternatives.
It was fun, still.&lt;/p&gt;
&lt;p&gt;So my point is - I like to participate in small ecosystems, mostly because the points where an improvement is welcome are more visible.
This leads us back to programming languages, and Fennel in particular.&lt;/p&gt;
&lt;h2 id=&#34;the-fennel-programming-language&#34;&gt;The Fennel Programming Language&lt;/h2&gt;
&lt;p&gt;If you read my blog, you may have seen posts about Fennel before, and likely know what it is.
If not, here&amp;rsquo;s a quick introduction:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;a href=&#34;https://fennel-lang.org&#34; target=&#34;_blank&#34;&gt;Fennel&lt;/a&gt; is a small surface language implemented on top of the Lua language.
It has a Clojure-inspired syntax, and Lisp macro system, allowing users to extend the language with new constructs pretty easily.
Fennel compiles down to Lua, and doesn&amp;rsquo;t have its own semantics, besides mentioned macro system and being a bit more strict.
And because Fennel is actually just a compiler, it includes almost no runtime features.
Its only runtime components are REPL (Read Eval Print Loop), which is a common thing for Lisps, and the pretty-printer - a small library that prints data structures in a way that can be read back by Fennel compiler, or just examined by us, humans.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I&amp;rsquo;ve been using fennel for almost 2 years now, and I&amp;rsquo;ve been reflecting on what has changed for me personally.
What&amp;rsquo;s improved, what things I made for myself, and so forth.
And looking at my project workflow in Fennel, and seeing a lot of stuff happening, I get the impression of working in a mature language, with a mature ecosystem.
So I decided to write about this topic, highlighting interesting changes, that happened in the past two years of my Fennel experience.&lt;/p&gt;
&lt;h3 id=&#34;pretty-printer&#34;&gt;Pretty Printer&lt;/h3&gt;
&lt;p&gt;When I started using Fennel, the pretty-printer module was in a bit sad state.
It worked, but its output was not formatted as one would expect from a language with Clojure-like syntax.
Instead, it was formatted more like Lua code, and because of that, it was difficult to inspect deeply nested structures.&lt;/p&gt;
&lt;p&gt;I have a &lt;a href=&#34;https://andreyor.st/posts/2021-01-09-pretty-printing-for-fennel-language/&#34;&gt;post&lt;/a&gt; describing existing problems and my approach in detail, but in short, I had to rewrite the &lt;code&gt;fennelview.fnl&lt;/code&gt; module from the ground up.
And as far as I can tell, the community liked the new pretty printer, so the effort was well worth it.
It needed some tweaks here and there afterward made by other people, but I think this is still my biggest contribution to Fennel, especially since we&amp;rsquo;re seeing results of the pretty printer every time we send something to the REPL.
Which made Fennel much more pleasant to work with (for me, at least).&lt;/p&gt;
&lt;h3 id=&#34;the-fennel-cljlib-library&#34;&gt;The &lt;code&gt;fennel-cljlib&lt;/code&gt; library&lt;/h3&gt;
&lt;p&gt;With the pretty printer in place, I started working on various libraries that were just interesting to make.
The first one was &lt;a href=&#34;https://gitlab.com/andreyorst/fennel-cljlib.git&#34; target=&#34;_blank&#34;&gt;fennel-cljlib&lt;/a&gt;, which was aimed at Clojure programmers that wanted to try out Fennel but didn&amp;rsquo;t want to give up some of the features they love in Clojure.
The library was crappy and had a lot of problems, which I fixed over the years, but right now I would say that it is solid.
Of course, there&amp;rsquo;s still a lot of room for improvement, but I&amp;rsquo;ve already utilized this library in some projects, and even seen its use in projects from other people!&lt;/p&gt;
&lt;p&gt;One thing that this library made me good at is writing macros.
Fennel has a similar syntax compared to Clojure, but it&amp;rsquo;s not the same, and some features are missing.
For instance, in Clojure, there is such thing as multi-arity functions, which are extremely handy.
Here&amp;rsquo;s how you might define such a function in Clojure:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;add&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Sum arbitrary amount of numbers.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ([] 0)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ([&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt;] &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ([&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt;] (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ([&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt;] (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ([&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;d&lt;/span&gt;] (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;d&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ([&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;d&lt;/span&gt; &amp;amp; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rest&lt;/span&gt;] (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;apply &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;add&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;d&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rest&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So if you call this function with zero arguments given, the &lt;code&gt;([] 0)&lt;/code&gt; arity is selected, and &lt;code&gt;0&lt;/code&gt; is the return value.
If you call it with three arguments, the &lt;code&gt;([a b c] (+ a b c))&lt;/code&gt; branch is selected, and the return is the sum of three arguments.
However, if you call it with five-or-more arguments, the last arity &lt;code&gt;([a b c d &amp;amp; rest] (apply add (+ a b c d) rest))&lt;/code&gt; is selected, which will recursively call itself with less and fewer arguments, until it reaches another arity.
So the call stack is &lt;code&gt;(add 1 2 3 4 5 6 7 8 9 10)&lt;/code&gt; to &lt;code&gt;(add 10 5 6 7 8 9 10)&lt;/code&gt; followed by &lt;code&gt;(add 28 8 9 10)&lt;/code&gt; and the result value is &lt;code&gt;55&lt;/code&gt;.
That&amp;rsquo;s three tail-recursive calls, to sum 10 numbers, and we do as much work to avoid unnecessary recursive calls.&lt;/p&gt;
&lt;p&gt;Of course, math functions, such as this can be written in a more performant way without any recursion, this just illustrates the idea, that you can write functions in a pretty much declarative style: given this amount of arguments do this thing.
And with the &lt;code&gt;cljlib&lt;/code&gt; library we can define such functions
But I&amp;rsquo;ve lied to you, that&amp;rsquo;s actually not Clojure up there, but Fennel code, &lt;a href=&#34;https://gitlab.com/andreyorst/fennel-cljlib/blob/e7951b59b9168fc57d83b6a0aaaf1c31d56cfa7f/init.fnl#L88-L95&#34; target=&#34;_blank&#34;&gt;defining one of the functions&lt;/a&gt; in &lt;code&gt;cljlib&lt;/code&gt;.
And if you scroll through the linked code, you&amp;rsquo;ll see that pretty much every function utilizes this feature of the language.
Even more so, if you take a look at Clojure sources, you&amp;rsquo;ll notice that a lot of code was ported almost directly, which some changes needed for it to work on the Lua runtime.&lt;/p&gt;
&lt;p&gt;But I&amp;rsquo;m going a bit off-topic here, this post is about the projects related to the language ecosystem, not just random projects of mine.
However, this library motivated me to make a contribution to the ecosystem, because I felt that there&amp;rsquo;s a point for improvement in the current workflow.
In the end, all I really want is a comfortable environment so I could enjoy programming a bit more, and maybe make it more enjoyable for other people as a side effect.
And I&amp;rsquo;m glad to see other people using the next project I&amp;rsquo;m going to talk about.&lt;/p&gt;
&lt;h3 id=&#34;fenneldoc&#34;&gt;Fenneldoc&lt;/h3&gt;
&lt;p&gt;&lt;a href=&#34;https://gitlab.com/andreyorst/fenneldoc.git&#34; target=&#34;_blank&#34;&gt;Fenneldoc&lt;/a&gt; is the tooling I wanted for Fennel so badly that I had to make one myself.&lt;/p&gt;
&lt;p&gt;This project is a rather simple documentation generation tool, which extracts documentation strings from functions&amp;rsquo; metadata, and creates a set of Markdown formatted files.
I wanted this tool because, already mentioned, &lt;code&gt;cljlib&lt;/code&gt; project had 60+ functions and 10+ macros, and I had to maintain documentation for all of that by hand.
And while I was working on this library and adding new functions, or changing existing ones, I had to keep the documentation in sync.
At some point, I was tired of noticing that I forgot to update some function&amp;rsquo;s documentation, or forgot to mention one entirely.
So I wrote &lt;code&gt;fenneldoc&lt;/code&gt; and &lt;a href=&#34;https://gitlab.com/andreyorst/fennel-cljlib/-/commit/4ea70bf39971eeb742a5de689a9ad8ba63559ecb&#34; target=&#34;_blank&#34;&gt;replaced&lt;/a&gt;, all of the manually written documentation with auto-generated one.&lt;/p&gt;
&lt;p&gt;I &lt;strong&gt;know&lt;/strong&gt;, a lot of people seem to agree on the topic that auto-generated documentation is bad, however, I don&amp;rsquo;t think it&amp;rsquo;s entirely true.
There&amp;rsquo;s a popular post by Jacob Kaplan-Moss, which describes what to write in the documentation.
It has a paragraph regarding auto-generated documentation:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Don’t.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Auto-generated documentation is almost worthless.
At best it’s a slightly improved version of simply browsing through the source, but most of the time it’s easier just to read the source than to navigate the bullshit that these autodoc tools produce.
About the only thing auto-generated documentation is good for is filling printed pages when contracts dictate delivery of a certain number of pages of documentation.
I feel a particularly deep form of rage every time I click on a “documentation” link and see auto-generated documentation.&lt;/p&gt;
&lt;p&gt;There’s no substitute for documentation written, organized, and edited by hand.&lt;/p&gt;
&lt;p&gt;I’ll even go further and say that auto-generated documentation is worse than useless: it lets maintainers fool themselves into thinking they have documentation, thus putting off actually writing good reference by hand.
If you don’t have documentation just admit to it.
Maybe a volunteer will offer to write some!
But don’t lie and give me that auto-documentation crap.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class=&#34;src-block-caption&#34;&gt;
&lt;a href=&#34;https://jacobian.org/2009/nov/10/what-to-write/&#34;&gt;Jacob Kaplan-Moss: Writing great documentation: What to write&lt;/a&gt;
&lt;/div&gt;
&lt;p&gt;I&amp;rsquo;m not sure exactly what kind of documentation here was in mind, and I can agree if we&amp;rsquo;re talking about documentation that was generated from the code alone.
I should also note that I have written a lot of documentation by hand before, and I would say that not all documentation is better when written like that.
And documentation can be hard to write in general, it certainly was for me.&lt;/p&gt;
&lt;p&gt;When working on a library, handwriting the documentation becomes very hard.
Not only do you have to sync every documentation entry with every update in your code base, but you&amp;rsquo;ll also have to remember what&amp;rsquo;s in the documentation and what&amp;rsquo;s missing.
And if you&amp;rsquo;re covering only the public API of your library it&amp;rsquo;s one thing, but when you also cover the private APIs for other developers to understand it&amp;rsquo;s a different kind of beast.
Doing all of this by hand can leave you no time to work on features as a result.&lt;/p&gt;
&lt;p&gt;The point is - it entirely depends on how documentation is generated, how it was written, and also for who you write it.
Your handwritten documentation may as well be complete garbage, useless for the end user if you have written it in a bad style or with a great lack of detail.
The same goes for auto-generated documentation - it &lt;em&gt;can&lt;/em&gt; be good, if the tooling is good, and if programmers took their time in writing meaningful things in the documentation strings/comments.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m getting a bit ranty here.&lt;/p&gt;
&lt;p&gt;So I think I found a compromise - I hand-write all documentation on a function level and generate the markdown files which enrich the documentation text with links between items automatically.
Paired with the fine-tuning of documentation order &lt;code&gt;fenneldoc&lt;/code&gt; provides, and the ability to add a general notice on top, it is possible to create documentation that reads as a normal document, yet is still usable when you found yourself in the sources.
And it is never out of date, unless you forgot to update it, which also happens without auto-generating.&lt;/p&gt;
&lt;p&gt;But there&amp;rsquo;s more.
What I also wanted from Fenneldoc was documentation testing.&lt;/p&gt;
&lt;p&gt;When I write documentation, I also include a lot of examples of how to use certain functions, or how they can be combined.
But after I change these functions, some examples might stop working.
And what&amp;rsquo;s good about having examples that don&amp;rsquo;t work when you try them?&lt;/p&gt;
&lt;p&gt;So Fenneldoc runs all examples and ensures that they at least compile.
You can include tests right into them, so they break when you&amp;rsquo;ve introduced an incompatible change and forgot to update the documentation.
It also checks if you&amp;rsquo;ve mentioned all of the function&amp;rsquo;s arguments in the documentation, and warns if it couldn&amp;rsquo;t find a cross-link to an item.&lt;/p&gt;
&lt;p&gt;For example, here&amp;rsquo;s another function from &lt;code&gt;cljlib&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;defn&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;into&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Returns a new coll consisting of `to` with all of the items of `from`
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;conjoined. A transducer `xform` may be supplied.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;# Examples
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;Insert items of one collection into another collection:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;```fennel
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;(assert-eq [1 2 3 :a :b :c] (into [1 2 3] \&amp;#34;abcd\&amp;#34;))
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;(assert-eq {:a 2 :b 3} (into {:a 1} {:a 2 :b 3}))
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;```
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;Transform a hash-map into a sequence of key-value pairs:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;``` fennel
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;(assert-eq [[:a 1]] (into (vector) {:a 1}))
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;```
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;You can also construct a hash-map from a sequence of key-value pairs:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;``` fennel
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;(assert-eq {:a 1 :b 2 :c 3}
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;           (into (hash-map) [[:a 1] [:b 2] [:c 3]]))
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;```&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ([] (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vector&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ([&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;to&lt;/span&gt;] &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;to&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ([&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;to&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;from&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   (&lt;span style=&#34;font-weight:bold&#34;&gt;match &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;getmetatable &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;to&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:cljlib/editable&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;true&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;persistent!&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;reduce&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;conj!&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;transient&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;to&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;from&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;reduce&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;conj&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;to&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;from&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ([&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;to&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;xform&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;from&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   (&lt;span style=&#34;font-weight:bold&#34;&gt;match &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;getmetatable &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;to&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:cljlib/editable&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;true&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;persistent!&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;transduce&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;xform&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;conj!&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;transient&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;to&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;from&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;transduce&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;xform&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;conj&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;to&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;from&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You can see that it has a basic description of what it does, and a few examples of what happens when you use it.
Arguments to the function exist in the documentation, and they&amp;rsquo;re using a Markdown notation for monospaced text by being enclosed via the backticks, for instance, the &lt;code&gt;`xform`&lt;/code&gt; argument.
Here the documentation is just a string of Markdown formatted text in general.&lt;/p&gt;
&lt;p&gt;Below is the example section, which features code blocks denoted with the triple backticks, following a language name: &lt;code&gt;``` fennel ... ```&lt;/code&gt;.
In each example, there is a test, and you can see that all invocations are wrapped in &lt;code&gt;assert-eq&lt;/code&gt; calls, which is an assertion macro from my &lt;code&gt;fennel-test&lt;/code&gt; library.
In this particular example, I made a mistake and forgot to add the letter &lt;code&gt;d&lt;/code&gt; into the result of the very first call to &lt;code&gt;into&lt;/code&gt;.
When I try to export this documentation to Markdown, I get an error:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;In file: &amp;#39;init.fnl&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Error in docstring for: &amp;#39;into&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;In test:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;``` fennel
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(assert-eq [1 2 3 :a :b :c] (into [1 2 3] &amp;#34;abcd&amp;#34;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(assert-eq {:a 2 :b 3} (into {:a 1} {:a 2 :b 3}))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;```
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Error:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;assertion failed for expression:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(eq [1 2 3 &amp;#34;a&amp;#34; &amp;#34;b&amp;#34; &amp;#34;c&amp;#34;] (into [1 2 3] &amp;#34;abcd&amp;#34;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; Left: [1 2 3 &amp;#34;a&amp;#34; &amp;#34;b&amp;#34; &amp;#34;c&amp;#34;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Right: [1 2 3 &amp;#34;a&amp;#34; &amp;#34;b&amp;#34; &amp;#34;c&amp;#34; &amp;#34;d&amp;#34;]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The error message comes from the &lt;code&gt;assert-eq&lt;/code&gt; macro, which tests whether the &lt;em&gt;left&lt;/em&gt; expression is equal to the &lt;em&gt;right&lt;/em&gt; one.
Fenneldoc just makes it possible to see the test itself before it.
A simple test, but can catch some mistakes in the documentation!&lt;/p&gt;
&lt;p&gt;I find this tool quite usable and a big part of my project workflow - every project I do has documentation generated with Fenneldoc, and I even read it from time to time, despite the fact that I was the one writing it.&lt;/p&gt;
&lt;h3 id=&#34;fennel-test&#34;&gt;Fennel test&lt;/h3&gt;
&lt;p&gt;Speaking of testing, I also created a &lt;a href=&#34;https://gitlab.com/andreyorst/fennel-test&#34; target=&#34;_blank&#34;&gt;fennel-test&lt;/a&gt; library because I didn&amp;rsquo;t like libraries aimed at testing Lua.
My library provides its own test runner, and tests are structured similarly to how they are in Clojure.
And if your project uses this library, it is possible to include it in the documentation testing pipeline as well, as I&amp;rsquo;ve shown before.&lt;/p&gt;
&lt;p&gt;Now, including huge tests in the documentation is really bad - in my opinion it should hold only small examples that also act as tests.
Also, I think that everything you write in the docstring should be displayed as is, so Fenneldoc doesn&amp;rsquo;t try to hide any stuff from the code blocks - the reader should see the whole picture.
The Rust programming language &lt;a href=&#34;https://doc.rust-lang.org/rustdoc/write-documentation/documentation-tests.html#include-items-only-when-collecting-doctests&#34; target=&#34;_blank&#34;&gt;took a different approach&lt;/a&gt;, even has hidden documentation tests, that are there only when you test the documentation, not when you export it.
I don&amp;rsquo;t think this is the correct way, but the paragraph mentions that it has something to do with the internal limitations of their testing framework.&lt;/p&gt;
&lt;p&gt;So you should write tests that are a lot more complicated than your documentation tests, but since it is reserved for the test suite it&amp;rsquo;s not a problem.
Here&amp;rsquo;s the test for the &lt;code&gt;into&lt;/code&gt; function I&amp;rsquo;ve been talking about before:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;deftest&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;test-into&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;testing&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;into&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;assert-eq&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;core.into&lt;/span&gt; [] &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;) [])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;assert-eq&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;core.into&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;assert-eq&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;core.into&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt; [1 2 3]) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;core.list&lt;/span&gt; 3 2 1))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;assert-eq&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;core.into&lt;/span&gt; [] []) [])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;assert-eq&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;core.into&lt;/span&gt; [1 2 3] []) [1 2 3])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;assert-eq&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;core.into&lt;/span&gt; [1 2 3] [4 5 6]) [1 2 3 4 5 6])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;assert-eq&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;core.into&lt;/span&gt; {} {}) {})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;assert-eq&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;core.into&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:a&lt;/span&gt; 1} {}) {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:a&lt;/span&gt; 1})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;assert-eq&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;core.into&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:a&lt;/span&gt; 1} {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:b&lt;/span&gt; 2}) {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:a&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:b&lt;/span&gt; 2})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;assert-eq&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;core.into&lt;/span&gt; [] {}) [])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;assert-eq&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;core.into&lt;/span&gt; {} []) [])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;assert-eq&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;. &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;getmetatable &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;core.into&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;core.vector&lt;/span&gt;) {})) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:cljlib/type&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:vector&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;assert-eq&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;. &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;getmetatable &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;core.into&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;core.hash-map&lt;/span&gt;) [])) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:cljlib/type&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:hash-map&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; ... more various cases ...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Here, the &lt;code&gt;deftest&lt;/code&gt; is a macro, that defines the test function which is then executed by the test runner.
The runner can shuffle tests, capture errors, and form the log afterward.
I like how it works, and it&amp;rsquo;s fine for my use cases.
There also are other facilities, like fixtures, which you can use to wrap each test, or all of the tests with additional code, but they only work when using the test runner.&lt;/p&gt;
&lt;p&gt;OK, hopefully, this is all great and can help us write more understandable and maintainable programs in Fennel.
What about support from text editors then?&lt;/p&gt;
&lt;h3 id=&#34;editor-tooling&#34;&gt;Editor tooling&lt;/h3&gt;
&lt;p&gt;And text-editor support is another thing that often requires improvements when we&amp;rsquo;re dealing with young languages.
I&amp;rsquo;ve created Fennel syntax highlighting support for Kakoune, and I also currently maintain the &lt;code&gt;fennel-mode&lt;/code&gt; package for Emacs.
I know that Visual Studio Code has some support for Fennel, and NeoVim has great support with interactive features, and even the ability to configure the editor in Fennel itself.
Similarly to NeoVim, there&amp;rsquo;s also a text editor, called Lite, which is written in Lua, and there are projects that make it extendable via Fennel, which is great!
Still, Emacs as of this moment has the best Fennel support (IMO), as it has good support for Lisps in general.
However, there are always places to improve tooling, and I improved Fennel&amp;rsquo;s support in Emacs by providing automatic completions, documentation popups, and a scratch buffer for a different approach for interactive sessions.
I have some more plans on improving the REPL support and dynamic highlighting of loaded macro forms.&lt;/p&gt;
&lt;p&gt;In addition to that, I&amp;rsquo;ve made a small package to add support for Fennel to Org Mode, called &lt;code&gt;ob-fennel&lt;/code&gt;.
I have an &lt;a href=&#34;https://andreyor.st/posts/2022-09-26-reproducible-research-with-org-mode-fennel-and-love/&#34;&gt;extensive post&lt;/a&gt; that goes into detail about how it can be used, so if you&amp;rsquo;re interested you can read it.&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s an interesting project on the horizon: &lt;a href=&#34;https://git.sr.ht/~xerool/fennel-ls/&#34; target=&#34;_blank&#34;&gt;fennel-ls&lt;/a&gt; - a language server for Fennel.
A very welcome addition to the language ecosystem, and as far as I can tell after speaking with the author - a passionate project.
And, as far as I can see, every mature language eventually gets a language server, so this is a good sign!&lt;/p&gt;
&lt;h2 id=&#34;what-s-next&#34;&gt;What&amp;rsquo;s next&lt;/h2&gt;
&lt;p&gt;There&amp;rsquo;s one point I want to replace in my current workflow with my Fennel project - coverage statistics.
Currently, I use the &lt;code&gt;luacov&lt;/code&gt; project, which analyzes Lua code specifically.
This is not a huge problem for me - I can read Lua, and I learned to read Lua that Fennel generates, but it is still a point of inconvenience.&lt;/p&gt;
&lt;p&gt;Ideally, I would like to have a tool similar to &lt;a href=&#34;https://github.com/cloverage/cloverage&#34; target=&#34;_blank&#34;&gt;cloverage&lt;/a&gt;, which is a Clojure library for generating code coverage reports.
I like it, because not only it works with Clojure code, and not some Java decompiled byte code, but it also shows coverage in terms of forms, not just lines.
For Fennel, it is a huge deal, because like in many lisps, forms may sit on a single line.
Though it is not a problem because I opt out of the &lt;code&gt;--correlate&lt;/code&gt; flag when I compile the project for coverage testing, so all one-liners are transformed into multiple lines, and I get pretty accurate coverage results.
Still inconvenient.&lt;/p&gt;
&lt;p&gt;But all of the above is only a small fraction of what has happened with Fennel overall - it&amp;rsquo;s just things that I&amp;rsquo;ve experienced in my project workflow.
There&amp;rsquo;s a lot of cool stuff happening even right now, and I welcome everybody to the upcoming &lt;a href=&#34;https://conf.fennel-lang.org/2022&#34; target=&#34;_blank&#34;&gt;FennelConf 2022&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;From my point of view, Fennel grew a lot during the last two years.
We had the first major release and extended the language with new macros, and there are a lot of projects in the works regarding making the compiler more general via a plugin system.
I&amp;rsquo;m very excited about the future of Fennel and want to thank everybody in the community, which I&amp;rsquo;m glad I&amp;rsquo;m a part of.&lt;/p&gt;
&lt;p&gt;And I believe this situation is not unique to Fennel.
I know people who participate in other programming language-related communities, and I hear great things about them too.
Being in a small community is also beneficial in that you get to know a lot of people, and when someone new comes with some crazy ideas it&amp;rsquo;s always great to see what they can create with the project you are also passionate about.&lt;/p&gt;
&lt;p&gt;So keep hacking!
I&amp;rsquo;m looking forward to seeing more projects that help make developing ecosystem better, and I do my best for the ones I participate in!&lt;/p&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: Small languages with little tooling&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Wed, 02 Nov 2022 20:31:00 +0300</pubDate>
    </item><item>
      <title>Reproducible Research with Org Mode, Fennel, and LÖVE</title>
      <link>https://andreyor.st/posts/2022-09-26-reproducible-research-with-org-mode-fennel-and-love/</link>
      <guid>https://andreyor.st/posts/2022-09-26-reproducible-research-with-org-mode-fennel-and-love/</guid>
      <description>&lt;p&gt;Today I would like to talk about three separate tools, and how we can combine them with the power of Emacs.&lt;/p&gt;
&lt;p&gt;Our tools for today are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://fennel-lang.org&#34; target=&#34;_blank&#34;&gt;Fennel&lt;/a&gt; - a Lisp-like surface syntax for Lua that makes programming in Lua fun and more robust.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://orgmode.org/&#34; target=&#34;_blank&#34;&gt;Org Mode&lt;/a&gt; - a markup language and an application inside Emacs, which allows its users to create documents that include interactive pieces of code.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://love2d.org/&#34; target=&#34;_blank&#34;&gt;LÖVE&lt;/a&gt; - a game engine that allows programming games in Lua.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This post is itself a program, describing how you could create similar Org documents and explore &lt;a href=&#34;https://en.wikipedia.org/wiki/Literate_programming&#34; target=&#34;_blank&#34;&gt;literate programming&lt;/a&gt;/&lt;a href=&#34;https://en.wikipedia.org/wiki/Reproducibility#Reproducible_research&#34; target=&#34;_blank&#34;&gt;reproducible research&lt;/a&gt; with Fennel, or other languages for that matter.
It&amp;rsquo;s possible thanks to Org Mode and my new package &lt;a href=&#34;https://gitlab.com/andreyorst/ob-fennel&#34; target=&#34;_blank&#34;&gt;ob-fennel&lt;/a&gt;, which implements necessary functions for sending Fennel code blocks to the REPL process.
For a better experience, you should read this in Emacs, and you can get the original &lt;code&gt;.org&lt;/code&gt; file from &lt;a href=&#34;https://andreyor.st/2022-09-26-reproducible-research-with-org-mode-fennel-and-love.org&#34;&gt;here&lt;/a&gt;.
If you want to follow the instructions, make sure to &lt;a href=&#34;https://fennel-lang.org/setup&#34; target=&#34;_blank&#34;&gt;install Fennel&lt;/a&gt; and &lt;a href=&#34;https://github.com/love2d/love/releases&#34; target=&#34;_blank&#34;&gt;LÖVE&lt;/a&gt; for this to work.&lt;/p&gt;
&lt;h2 id=&#34;bootstrapping-löve&#34;&gt;Bootstrapping LÖVE&lt;/h2&gt;
&lt;p&gt;First, we need to bootstrap LÖVE so it could understand Fennel code:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; fennel = require &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;fennel&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;table.insert(package.loaders &lt;span style=&#34;font-weight:bold&#34;&gt;or&lt;/span&gt; package.searchers, fennel.searcher)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We&amp;rsquo;ve required &lt;code&gt;fennel&lt;/code&gt; the library and registered the &lt;code&gt;fennel.searcher&lt;/code&gt; function as one of the functions responsible to loading files.
With that, theoretically, we no longer need to write any more Lua code, and instead, we can write in Fennel, and then use plain Lua&amp;rsquo;s &lt;code&gt;require&lt;/code&gt; to load the files.
Let&amp;rsquo;s create a REPL (Read Eval Print Loop) that will allow us to do interactive programming in LÖVE via its thread and event systems.&lt;/p&gt;
&lt;p&gt;First, let&amp;rsquo;s require &lt;code&gt;fennel&lt;/code&gt; once again, and also require &lt;code&gt;love.event&lt;/code&gt;.
Next, we&amp;rsquo;ll do a little trick that I&amp;rsquo;ll explain later, but for now, we&amp;rsquo;ll only need to capture the module-scope value of &lt;code&gt;...&lt;/code&gt; into variables &lt;code&gt;event&lt;/code&gt; and &lt;code&gt;channel&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fennel&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:fennel&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:love.event&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This will make sense in a moment.
Now, we need a REPL itself.
REPL consists of the prompt that asks for more input, and the loop that calls the prompt which reads some input and sends it to a channel.
Let&amp;rsquo;s define the &lt;code&gt;prompt&lt;/code&gt; function first:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;prompt&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;next-line?&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;io.write &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;next-line?&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;.. &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;gt;&amp;gt; &amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;io.flush&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;tostring &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;io.read&lt;/span&gt;)) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\n&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now, we can create the infinite loop, that will read from &lt;code&gt;stdin&lt;/code&gt; and push the read value into LÖVE&amp;rsquo;s event system.
That&amp;rsquo;s where we&amp;rsquo;ll use the captured &lt;code&gt;event&lt;/code&gt; variable, however, we&amp;rsquo;ll need to run this loop only in a LÖVE thread, so we&amp;rsquo;ll check if the &lt;code&gt;channel&lt;/code&gt; was bound:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;match &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;event&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;channel&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;while &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;match &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;channel&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:demand&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:data&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;output&lt;/span&gt;] (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;print &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;table.concat &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;output&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\t&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cont?&lt;/span&gt;] (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.event.push&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;event&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;prompt&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cont?&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:error&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;kind&lt;/span&gt; &amp;amp; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;print &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;string.format&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;%s error: %s&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;kind&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              (&lt;span style=&#34;font-weight:bold&#34;&gt;accumulate &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;msg&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;ipairs &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                (&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;msg&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;tostring &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt;))))))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Once data appears in the channel, this function exterminates what pattern it received.
It is always a table, where the first element means the kind of data, and the rest of the table is the data itself.
That&amp;rsquo;s the protocol we&amp;rsquo;re going to write in a moment.&lt;/p&gt;
&lt;p&gt;The loop check if the &lt;code&gt;event-type&lt;/code&gt; is either &lt;code&gt;:data&lt;/code&gt; or &lt;code&gt;:error&lt;/code&gt; and acts accordingly.
In addition to that, there&amp;rsquo;s a third event-type &lt;code&gt;:next-line&lt;/code&gt; which represents the situation when the REPL receives incomplete input and waits for more lines.
Let&amp;rsquo;s implement this protocol:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;thread&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;-&amp;gt; &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;repl.fnl&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.filesystem.read&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fennel.compileString&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.filesystem.newFileData&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:repl&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.thread.newThread&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;io-channel&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.thread.newChannel&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;coro&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;coroutine.create &lt;/span&gt;#(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fennel.repl&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;$...&lt;/span&gt;))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;-&amp;gt;&amp;gt; &lt;/span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:readChunk&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[{&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;stack-size&lt;/span&gt; &amp;amp;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;as&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vaiv&lt;/span&gt;}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;io-channel&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:push&lt;/span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;&amp;gt; &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;stack-size&lt;/span&gt; 0)])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;coroutine.yield&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:onValues&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;io-channel&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:push&lt;/span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:data&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;]))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:onError&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;kind&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;io-channel&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:push&lt;/span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:error&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;kind&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;]))}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;coroutine.resume &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;coro&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;thread&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:start&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:eval&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;io-channel&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.handlers.eval&lt;/span&gt; #(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;coroutine.resume &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;coro&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;$&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This is an asynchronous REPL, made with Lua&amp;rsquo;s coroutines.
You may wonder, how it will start the &lt;code&gt;loop&lt;/code&gt; function if it was under the &lt;code&gt;when channel&lt;/code&gt; guard, but that&amp;rsquo;s exactly what this piece of code does.&lt;/p&gt;
&lt;p&gt;First, it loads itself via &lt;code&gt;love.filesystem.read&lt;/code&gt; and compiles Fennel code to Lua via &lt;code&gt;fennel.compileString&lt;/code&gt; function.
Next, this compiled representation is used to create a &lt;a href=&#34;https://love2d.org/wiki/FileData&#34; target=&#34;_blank&#34;&gt;&lt;code&gt;FileData&lt;/code&gt;&lt;/a&gt; object, that is used to start a LÖVE thread with the &lt;code&gt;love.thread.newThread&lt;/code&gt; function.
So this module will be executed twice - first when &lt;code&gt;main.lua&lt;/code&gt; loads the file, and second, when LÖVE spawns the thread, but were not there, yet.&lt;/p&gt;
&lt;p&gt;After we&amp;rsquo;ve created the &lt;code&gt;thread&lt;/code&gt; we create an &lt;code&gt;io-channel&lt;/code&gt; and the REPL coroutine.
Next, we start the &lt;code&gt;coroutine&lt;/code&gt; by passing it a table of functions, each of which will &lt;code&gt;push&lt;/code&gt; data to the &lt;code&gt;io-channel&lt;/code&gt;.
Importantly, the &lt;code&gt;readChunk&lt;/code&gt; function pauses the coroutine after every read, allowing it to run asynchronously within the main thread.&lt;/p&gt;
&lt;p&gt;Finally, we start the &lt;code&gt;thread&lt;/code&gt; by passing &lt;code&gt;:eval&lt;/code&gt; which will be bound to the &lt;code&gt;event&lt;/code&gt; variable, and &lt;code&gt;io-channel&lt;/code&gt; which will be bound to &lt;code&gt;channel&lt;/code&gt;.
This thread spins the &lt;code&gt;loop&lt;/code&gt; function, which blocks the thread waiting for the input, while the main LÖVE thread continues to run.&lt;/p&gt;
&lt;p&gt;With all of that, we can finally &lt;code&gt;require&lt;/code&gt; the &lt;code&gt;repl.fnl&lt;/code&gt; file in the &lt;code&gt;main.lua&lt;/code&gt; like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;require &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;repl&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Also, let&amp;rsquo;s disable vsync while we&amp;rsquo;re at it.
For some reason, it makes the REPL slow on my machine.
We won&amp;rsquo;t be needing it anyway:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love&lt;/span&gt;.&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;conf&lt;/span&gt;(t)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  t.window.vsync = 0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now we can start hacking in real time!&lt;/p&gt;
&lt;h2 id=&#34;drawing-plots&#34;&gt;Drawing plots&lt;/h2&gt;
&lt;p&gt;Since we&amp;rsquo;re done with the literate programming example, let&amp;rsquo;s look at how the reproducible research can be organized.
I&amp;rsquo;m sure you should be familiar with the concept of a notebook, like &lt;a href=&#34;https://rmarkdown.rstudio.com/&#34; target=&#34;_blank&#34;&gt;R Markdonw&lt;/a&gt; or &lt;a href=&#34;https://jupyter.org/&#34; target=&#34;_blank&#34;&gt;Jupiter&lt;/a&gt;.
We&amp;rsquo;re going to achieve something like that.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re reading this file in Emacs, which you should, press the &lt;code&gt;C-c C-v t&lt;/code&gt; shortcut, which will run the &lt;code&gt;org-babel-tangle&lt;/code&gt; function.
After executing it, Emacs will create three files &lt;code&gt;main.lua&lt;/code&gt;, &lt;code&gt;conf.lua&lt;/code&gt;, and &lt;code&gt;repl.fnl&lt;/code&gt; in the same directory as this file.
If you&amp;rsquo;re not reading this file in Emacs, then, well, get Emacs, or just believe me - it works.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s plot a function via LÖVE2D and Fennel.
I&amp;rsquo;m not sure if there&amp;rsquo;s a library for drawing plots with LÖVE, but it&amp;rsquo;s ain&amp;rsquo;t fun to use something like that anyways, so let&amp;rsquo;s build our own!
First, we&amp;rsquo;ll need a &lt;a href=&#34;https://love2d.org/wiki/Canvas&#34; target=&#34;_blank&#34;&gt;Canvas&lt;/a&gt; object to draw to:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;canvas&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.graphics.newCanvas&lt;/span&gt; 640 480))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Put the cursor in this source code block and press &lt;code&gt;C-c C-c&lt;/code&gt; shortcut (or call the &lt;code&gt;org-babel-execute-src-block&lt;/code&gt; function with &lt;code&gt;M-x&lt;/code&gt;)
The empty LÖVE window will appear, and Emacs will display a message in the prompt area, with the contents something like &amp;ldquo;Please re-evaluate once Fennel is initialized&amp;rdquo;.
We won&amp;rsquo;t be needing this window, so you can minimize it - we&amp;rsquo;ll be drawing off-screen onto a canvas and then saving it as an image.
Org-mode provides us with all we&amp;rsquo;ll need to preview results without leaving Emacs.&lt;/p&gt;
&lt;p&gt;Once Fennel is loaded, and all threads were spawned, hit &lt;code&gt;C-c C-c&lt;/code&gt; again, and you should see &lt;code&gt;&amp;quot;nil&amp;quot;&lt;/code&gt; in the echo area.
This means that the code was executed successfully and the &lt;code&gt;canvas&lt;/code&gt; variable was created.&lt;/p&gt;
&lt;p&gt;Now, let&amp;rsquo;s write a function that will draw a grid to the active canvas.
First, we&amp;rsquo;ll need a function that will calculate the grid step based on the zoom level.
Our zoom level is represented in percentages, which we&amp;rsquo;ll later convert to values by dividing by &lt;code&gt;100&lt;/code&gt;.
However, for our grid, we will be doing an infinite zoom with finite details.&lt;/p&gt;
&lt;p&gt;This function computes the step between each grid line based on current &lt;code&gt;zoom&lt;/code&gt; level.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;calc-step&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;zoom&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;gscale&lt;/span&gt; (^ 10 (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bit.bor&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;math.log &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;zoom&lt;/span&gt; 10) 0))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;* &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;zoom&lt;/span&gt; 100 (&lt;span style=&#34;font-weight:bold&#34;&gt;/ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;gscale&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It&amp;rsquo;s a bit convoluted, but the key here is the bitwise &lt;code&gt;or&lt;/code&gt; operator - that&amp;rsquo;s what makes our grid cycle between zoom levels properly.
We now can define the function that computes and draws the grid itself:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;draw-grid&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;zoom&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;w&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;h&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.graphics.getCanvas&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:getDimensions&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;step&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;calc-step&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;zoom&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.graphics.setColor&lt;/span&gt; [1 1 1 1])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.graphics.rectangle&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:fill&lt;/span&gt; 0 0 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;w&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;h&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.graphics.setLineWidth&lt;/span&gt; 1)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;each &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;step&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;color&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;ipairs &lt;/span&gt;[[(&lt;span style=&#34;font-weight:bold&#34;&gt;/ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;step&lt;/span&gt; 10) [0.7 0.7 0.7 (&lt;span style=&#34;font-weight:bold&#34;&gt;/ &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;% &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;step&lt;/span&gt; 1000) 1000)]]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    [(&lt;span style=&#34;font-weight:bold&#34;&gt;* &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;step&lt;/span&gt; 1) [0.9 0.9 0.9 (&lt;span style=&#34;font-weight:bold&#34;&gt;- &lt;/span&gt;1 (&lt;span style=&#34;font-weight:bold&#34;&gt;/ &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;% &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;step&lt;/span&gt; 1000) 1000))]]])]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;grid&lt;/span&gt; []]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fcollect&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;/ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;w&lt;/span&gt; 2) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;step&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;w&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;step&lt;/span&gt;     &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:into&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;grid&lt;/span&gt;] [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; 0 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;h&lt;/span&gt;])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fcollect&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;- &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;/ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;w&lt;/span&gt; 2) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;step&lt;/span&gt;) 0 (&lt;span style=&#34;font-weight:bold&#34;&gt;- &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;step&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:into&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;grid&lt;/span&gt;] [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; 0 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;h&lt;/span&gt;])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fcollect&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;/ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;h&lt;/span&gt; 2) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;step&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;h&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;step&lt;/span&gt;     &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:into&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;grid&lt;/span&gt;] [0 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;w&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt;])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fcollect&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;- &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;/ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;h&lt;/span&gt; 2) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;step&lt;/span&gt;) 0 (&lt;span style=&#34;font-weight:bold&#34;&gt;- &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;step&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:into&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;grid&lt;/span&gt;] [0 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;w&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt;])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.graphics.setColor&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;color&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold&#34;&gt;each &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;ipairs &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;grid&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.graphics.line&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt;))))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This function actually draws two grids - one for unit size, and one for 1/10 of the unit size, and applies dynamic transparency based of the &lt;code&gt;zoom&lt;/code&gt; level.
This way, we can create an illusion of the infinite zoom level, that
It&amp;rsquo;s a bit verbose, but all it really does is create a table of line segments from the center of the canvas in all four directions with the calculated &lt;code&gt;step&lt;/code&gt; interval.&lt;/p&gt;
&lt;p&gt;This only draws the grid, though, we also need to draw the X and Y axis, with some markings indicating the zoom level:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;draw-axis&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;zoom&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;w&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;h&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.graphics.getCanvas&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:getDimensions&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;step&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;calc-step&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;zoom&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.graphics.setLineWidth&lt;/span&gt; 1)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.graphics.setColor&lt;/span&gt; [0.3 0.3 0.3 1])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.graphics.line&lt;/span&gt; [(&lt;span style=&#34;font-weight:bold&#34;&gt;/ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;w&lt;/span&gt; 2) 0 (&lt;span style=&#34;font-weight:bold&#34;&gt;/ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;w&lt;/span&gt; 2) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;h&lt;/span&gt;])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.graphics.line&lt;/span&gt; [0 (&lt;span style=&#34;font-weight:bold&#34;&gt;/ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;h&lt;/span&gt; 2) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;w&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;/ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;h&lt;/span&gt; 2)])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;h&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;/ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;h&lt;/span&gt; 2) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;w&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;/ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;w&lt;/span&gt; 2)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;for &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;step&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;w&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;step&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.graphics.line&lt;/span&gt; [(&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;w&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;h&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;w&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;h&lt;/span&gt; 2)])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.graphics.print&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;string.format &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;%.1f&amp;#34;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;/ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;zoom&lt;/span&gt;)) (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;w&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;h&lt;/span&gt; 5)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;for &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;- &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;step&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold&#34;&gt;- &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;w&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold&#34;&gt;- &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;step&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.graphics.line&lt;/span&gt; [(&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;w&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;h&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;w&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;h&lt;/span&gt; 2)])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.graphics.print&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;string.format &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;%.1f&amp;#34;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;/ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;zoom&lt;/span&gt;)) (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;w&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;h&lt;/span&gt; 5)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;for &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;step&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;h&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;step&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.graphics.line&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;w&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;h&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;w&lt;/span&gt; 2) (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;h&lt;/span&gt;)])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.graphics.print&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;string.format &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;%.1f&amp;#34;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;- &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;/ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;zoom&lt;/span&gt;))) (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;w&lt;/span&gt; 5) (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;h&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;for &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;- &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;step&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold&#34;&gt;- &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;h&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold&#34;&gt;- &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;step&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.graphics.line&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;w&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;h&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;w&lt;/span&gt; 2) (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;h&lt;/span&gt;)])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.graphics.print&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;string.format &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;%.1f&amp;#34;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;- &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;/ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;zoom&lt;/span&gt;))) (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;w&lt;/span&gt; 5) (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;h&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.graphics.print&lt;/span&gt; 0 (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;w&lt;/span&gt; 5) (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;5 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;h&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This function works similarly to the &lt;code&gt;draw-grid&lt;/code&gt; one, except it only draws two lines intersecting at the canvas&amp;rsquo; center, and the numbers, indicating units of measure.
Each number also has a small mark at the axis for better readability.&lt;/p&gt;
&lt;p&gt;Finally, let&amp;rsquo;s write a function &lt;code&gt;plot&lt;/code&gt; that will accept a function &lt;code&gt;fun&lt;/code&gt; which it will plot on the canvas, and some additional arguments, like &lt;code&gt;from&lt;/code&gt;, &lt;code&gt;to&lt;/code&gt;, &lt;code&gt;step&lt;/code&gt;.
Also, did I mention that you should press &lt;code&gt;C-c C-c&lt;/code&gt; &lt;strong&gt;on each code block&lt;/strong&gt; in this section?
It will send the code to the running LÖVE process, and we will be able to see the results dynamically.
But before we do that, let&amp;rsquo;s write a function that transforms so-called world coordinates to screen coordinates:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;world-&amp;gt;screen-coordinates&lt;/span&gt; [[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt;] &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;zoom&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;w&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;h&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.graphics.getCanvas&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:getDimensions&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    [(&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;* &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;zoom&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold&#34;&gt;/ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;w&lt;/span&gt; 2)) (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;- &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;* &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;zoom&lt;/span&gt;)) (&lt;span style=&#34;font-weight:bold&#34;&gt;/ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;h&lt;/span&gt; 2))]))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Oh, and we also need a function for generating a unique file name for the output image:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;unique-fname&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;suffix&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;base&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ext&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;string.match &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;(.*)%.(.-)$&amp;#34;&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.filesystem.getInfo&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;base&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;suffix&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;.&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ext&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;unique-fname&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;suffix&lt;/span&gt; 0) 1))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;base&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;suffix&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;.&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ext&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Alright, here&amp;rsquo;s the &lt;code&gt;plot&lt;/code&gt; function:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;plot&lt;/span&gt; [{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:fun&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;from&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;to&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;step&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;zoom&lt;/span&gt;}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;image&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;unique-fname&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;result.png&amp;#34;&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;canvas&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:renderTo&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     #(&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;zoom&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;/ &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;zoom&lt;/span&gt; 100) 100)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;w&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;h&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.graphics.getCanvas&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:getDimensions&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;draw-grid&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;zoom&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;draw-axis&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;zoom&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.graphics.setColor&lt;/span&gt; [1 0 0 1])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.graphics.setLineWidth&lt;/span&gt; 1)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;points&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fcollect&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;from&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;to&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;step&lt;/span&gt; 0.1)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                       (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;world-&amp;gt;screen-coordinates&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;)] &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;zoom&lt;/span&gt;))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;font-weight:bold&#34;&gt;each &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x1&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y1&lt;/span&gt;] (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;ipairs &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;points&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;font-weight:bold&#34;&gt;match &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;points&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; 1))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x2&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y2&lt;/span&gt;] (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.graphics.line&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x1&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y1&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x2&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y2&lt;/span&gt;))))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;canvas&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:newImageData&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:encode&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:png&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;image&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.filesystem.getSaveDirectory&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;/&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;image&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This function uses the &lt;a href=&#34;https://love2d.org/wiki/Canvas:renderTo&#34; target=&#34;_blank&#34;&gt;&lt;code&gt;renderTo&lt;/code&gt;&lt;/a&gt; method of the &lt;code&gt;canvas&lt;/code&gt; object.
It accepts an anonymous function, which draws the gird, the axis, sets the color of the plot to red, and finally draws the plot with &lt;code&gt;love.graphics.points&lt;/code&gt;.
We can execute it like that, by pressing &lt;code&gt;C-c C-c&lt;/code&gt; on the next code block:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;plot&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:fun&lt;/span&gt; #(&lt;span style=&#34;font-weight:bold&#34;&gt;* &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;$&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;$&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:from&lt;/span&gt; -50 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:to&lt;/span&gt; 50 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:step&lt;/span&gt; 0.01 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:zoom&lt;/span&gt; 5000})
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;figure class=&#34;invertable&#34;&gt;&lt;img src=&#34;https://andreyor.st/ox-hugo/result.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;This produces an image, which you should see if you call the &lt;code&gt;org-toggle-inline-images&lt;/code&gt; function.
As you can see, it plots a simple &lt;img src=&#34;https://andreyor.st/ltximg/2022-09-26-reproducible-research-with-org-mode-fennel-and-love_3731252ebff9619616923189ae68cffd87243765.svg&#34; alt=&#34;\(x^2\)&#34; class=&#34;org-svg&#34; /&gt; function, but we can plot any other, like &lt;img src=&#34;https://andreyor.st/ltximg/2022-09-26-reproducible-research-with-org-mode-fennel-and-love_6d8bccd3ef0e0eaa85bfa9ec415d47791e2b8900.svg&#34; alt=&#34;\(\tan(\sin(x))\)&#34; class=&#34;org-svg&#34; /&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;plot&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:fun&lt;/span&gt; #(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;math.tan &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;math.sin &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;$&lt;/span&gt;)) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:from&lt;/span&gt; -10 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:to&lt;/span&gt; 10 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:zoom&lt;/span&gt; 5000})
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;figure class=&#34;invertable&#34;&gt;&lt;img src=&#34;https://andreyor.st/ox-hugo/result1.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;Or a more complex example would be generating a square wave via this formula &lt;img src=&#34;https://andreyor.st/ltximg/2022-09-26-reproducible-research-with-org-mode-fennel-and-love_6d8ca5aa31feffe0dccb81a596a0322bc3db7924.svg&#34; alt=&#34;\(\sum_{k=1,3,5,7,...,29}^{} \frac{sin(x\mul{k})}{k}\)&#34; class=&#34;org-svg&#34; /&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;plot&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:fun&lt;/span&gt; #(&lt;span style=&#34;font-weight:bold&#34;&gt;accumulate &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;math.sin &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;$&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                          &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;k&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;ipairs &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fcollect&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;k&lt;/span&gt; 3 29 2] &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;k&lt;/span&gt;))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;/ &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;math.sin &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;* &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;$&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;k&lt;/span&gt;)) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;k&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:from&lt;/span&gt; -500 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:to&lt;/span&gt; 500 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:step&lt;/span&gt; 0.01 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:zoom&lt;/span&gt; 8000})
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;figure class=&#34;invertable&#34;&gt;&lt;img src=&#34;https://andreyor.st/ox-hugo/result2.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;You get the idea.&lt;/p&gt;
&lt;p&gt;Additionally, we can create a function that plots Org tables, like this one:&lt;/p&gt;
&lt;p&gt;&lt;a id=&#34;table--lines&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;x&lt;/th&gt;
&lt;th&gt;y&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;12&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;15&lt;/td&gt;
&lt;td&gt;20&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;17&lt;/td&gt;
&lt;td&gt;-2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;19&lt;/td&gt;
&lt;td&gt;-7&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;25&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The function is mostly similar to &lt;code&gt;plot&lt;/code&gt; except instead of calling a function it just goes through each table row, and builds line segments to draw:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;plot-table&lt;/span&gt; [{&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;zoom&lt;/span&gt;}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;image&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;unique-fname&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;result.png&amp;#34;&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;canvas&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:renderTo&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     #(&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;zoom&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;/ &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;zoom&lt;/span&gt; 1000) 100)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;w&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;h&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.graphics.getCanvas&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:getDimensions&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;draw-grid&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;zoom&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;draw-axis&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;zoom&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.graphics.setColor&lt;/span&gt; [1 0 0 1])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.graphics.setLineWidth&lt;/span&gt; 1)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold&#34;&gt;each &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;row&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;ipairs &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x1&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y1&lt;/span&gt;] (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;world-&amp;gt;screen-coordinates&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;row&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;zoom&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;font-weight:bold&#34;&gt;match &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; 1))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;next-row&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x2&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y2&lt;/span&gt;] (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;world-&amp;gt;screen-coordinates&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;next-row&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;zoom&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.graphics.line&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x1&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y1&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x2&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y2&lt;/span&gt;)))))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;canvas&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:newImageData&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:encode&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:png&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;string.format &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;image&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.filesystem.getSaveDirectory&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;/&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;image&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We can plot it like this, passing the table via the &lt;code&gt;:var data=lines&lt;/code&gt; header property:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;plot-table&lt;/span&gt; {&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:zoom&lt;/span&gt; 1000})
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;figure class=&#34;invertable&#34;&gt;&lt;img src=&#34;https://andreyor.st/ox-hugo/result3.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;You can build more complex functions, that, for example, draw several graphs on the same canvas, or draw entirely different types of graphs altogether.
Though this requires defining functions for all these kinds of visualizations, and I guess this is why people tend to use other languages for the task, like R.&lt;/p&gt;
&lt;h2 id=&#34;inline-evaluation&#34;&gt;Inline evaluation&lt;/h2&gt;
&lt;p&gt;Well, graphs are cool and all, but what about supplying values into the text directly?
We can do that too, and although, we could do this in our LÖVE REPL, that&amp;rsquo;s a great opportunity to showcase another ability of Org Babel - run multiple instances of Fennel, using completely different environments!&lt;/p&gt;
&lt;p&gt;For example, suppose we have some kind of a formula, that, for example, calculates the &lt;a href=&#34;https://en.wikipedia.org/wiki/Ackermann_function&#34; target=&#34;_blank&#34;&gt;Ackermann function&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;A&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;m&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt; 0) 0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;m&lt;/span&gt; 0) (&lt;span style=&#34;font-weight:bold&#34;&gt;* &lt;/span&gt;2 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt; 1) 2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;A&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;- &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;m&lt;/span&gt; 1)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;A&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;m&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;- &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt; 1)))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We can define the function &lt;img src=&#34;https://andreyor.st/ltximg/2022-09-26-reproducible-research-with-org-mode-fennel-and-love_08e585494f53002724747488de2bb88e8c747eb3.svg&#34; alt=&#34;\(n^2\)&#34; class=&#34;org-svg&#34; /&gt; using the &lt;span class=&#34;inline-src language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;code&gt;(fn square [n] (A 1 n))&lt;/code&gt;&lt;/span&gt;, and use it like &lt;span class=&#34;inline-src language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;code&gt;(square 4)&lt;/code&gt;&lt;/span&gt; producing &lt;code&gt;16&lt;/code&gt; as a result.
Or, we can define a function that computes &lt;img src=&#34;https://andreyor.st/ltximg/2022-09-26-reproducible-research-with-org-mode-fennel-and-love_4b35030e5268b8d41819f83682871bc4a74d81f7.svg&#34; alt=&#34;\(2\uparrow\uparrow{n}\)&#34; class=&#34;org-svg&#34; /&gt; like this: &lt;span class=&#34;inline-src language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;code&gt;(fn two⇈n [n] (A 2 n))&lt;/code&gt;&lt;/span&gt;.
Calling it as &lt;span class=&#34;inline-src language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;code&gt;(two⇈n 4)&lt;/code&gt;&lt;/span&gt; gives us &lt;code&gt;65536&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;These code blocks are running in a separate session, using a regular Lua interpreter, instead of our LÖVE REPL.
This is done by specifying the &lt;code&gt;:session&lt;/code&gt; header argument, and giving it a name, which instructs &lt;code&gt;ob-fennel&lt;/code&gt; to spawn a new process.
Upon exporting, the results of the inline evaluation would update automatically which eliminates the problem of stale data in the paper.
The results always reflect the actual code they were computed with.&lt;/p&gt;
&lt;h2 id=&#34;the-power-of-org&#34;&gt;The power of Org&lt;/h2&gt;
&lt;p&gt;The examples above are just the tip of the iceberg of what you can do with the Org package.
Back when I wasn&amp;rsquo;t an Emacs user, I often found threads on the topic &amp;ldquo;why should I use Emacs?&amp;rdquo; and each of these threads contained at least one answer which just said &amp;ldquo;Org Mode&amp;rdquo;.
I never understood why - what&amp;rsquo;s so good about Org that I can&amp;rsquo;t get from, say, Markdown?&lt;/p&gt;
&lt;p&gt;Since then, I&amp;rsquo;ve switched to Emacs and started this blog, using Org Mode, Hugo, and the &lt;a href=&#34;https://ox-hugo.scripter.co/&#34; target=&#34;_blank&#34;&gt;ox-hugo&lt;/a&gt; package.
Org mode has a built-in exporting engine, which can export &lt;code&gt;.org&lt;/code&gt; files to PDF, ODT, LaTeX, Markdown, or HTML files.
The ox-hugo package adds another backend for this engine, which exports to Hugo compatible markdown, which is then used by Hugo to build this website.&lt;/p&gt;
&lt;p&gt;And when I was starting this blog, I wasn&amp;rsquo;t sure that I made the right investment - I&amp;rsquo;ve just switched to Emacs a couple of months before, and I&amp;rsquo;m using this Org thing for writing.
I was uneasy because if I would stop enjoying writing in this setup I might lose all motivation for writing altogether.
But thankfully, I&amp;rsquo;ve liked the Org+Hugo combination, and it became the reason why I haven&amp;rsquo;t left Emacs since - it&amp;rsquo;s just too good as a writing experience.&lt;/p&gt;
&lt;p&gt;Literate programming was the way I learned Org.
I&amp;rsquo;ve &lt;a href=&#34;https://gitlab.com/andreyorst/dotfiles/blob/21ef6737690678a5e29d47e0563df095e25cd873/.config/emacs/README.org&#34; target=&#34;_blank&#34;&gt;used it to configure Emacs&lt;/a&gt; because Org Mode provides a way to load &lt;code&gt;.org&lt;/code&gt; files as Emacs Lisp files, and you can replace your &lt;code&gt;init.el&lt;/code&gt; with &lt;code&gt;init.org&lt;/code&gt; if you want to.
But to be honest, it&amp;rsquo;s a fun experiment, but I don&amp;rsquo;t find literate programming to be that practical.
It&amp;rsquo;s even harder to consider, given that there aren&amp;rsquo;t a lot of tools besides Emacs, that allows writing programs in this style using &lt;em&gt;any&lt;/em&gt; language.
And you can&amp;rsquo;t just make your coworkers use Emacs all of a sudden.
Yes, there are solutions specific to a particular language, but they lack usability in my opinion.&lt;/p&gt;
&lt;p&gt;Reproducible research was a hot topic lately, and the growing popularity of Jupiter notebooks is a great indication.
Org Mode might not provide all the fancy UI elements, that Jupiter notebook has, but theoretically speaking, nothing prevents you from writing a UI in a standalone tool, like the game engine, and using it as a rendering frontend from the comfort of Emacs.
This post partly shows this, although, I went a more static route with embedded images.
But still, anything is possible if you have the dedication to do it.&lt;/p&gt;
&lt;p&gt;I hope this post was an interesting read, and you&amp;rsquo;ve become interested in Emacs and Org Mode, or even in Fennel and LÖVE combo.
Feel free to contact me if you have any questions on the topic.
See you soon!&lt;/p&gt;&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: Reproducible Research with Org Mode, Fennel, and LÖVE&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Mon, 26 Sep 2022 00:57:00 +0300</pubDate>
    </item><item>
      <title>Fennel Game Jam 2022</title>
      <link>https://andreyor.st/posts/2022-06-12-fennel-game-jam-2022/</link>
      <guid>https://andreyor.st/posts/2022-06-12-fennel-game-jam-2022/</guid>
      <description>&lt;p&gt;Quite recently a Fennel game jam happened on &lt;a href=&#34;https://itch.io/&#34; target=&#34;_blank&#34;&gt;itch.io&lt;/a&gt; and I&amp;rsquo;ve decided to participate.
I&amp;rsquo;ve been part of the Fennel community for some years, and every once in a while a lot of people from this community participated in a lisp game jam, but I&amp;rsquo;ve never made a game before, so I&amp;rsquo;ve skipped these events.
However, when the Fennel-specific game jam was announced I decided that I must finally put myself together and participate.&lt;/p&gt;
&lt;p&gt;The rules of the jam were quite relaxed - you basically had to use fennel for game programming, and release the game under an &lt;a href=&#34;https://opensource.org/licenses&#34; target=&#34;_blank&#34;&gt;OSI approved license&lt;/a&gt;.
No theme, no engine restrictions, no size requirement - an ideal situation for a programmer like me, who doesn&amp;rsquo;t know how to make a game, at all.
When I was young, and I mean, like almost 20 years ago, I only toyed with &lt;a href=&#34;https://en.wikipedia.org/wiki/Adobe_Flash#Macromedia&#34; target=&#34;_blank&#34;&gt;Macromedia Flash&lt;/a&gt; and ActionScript 2.0 at my school computer class, making interactive cartoons, which can hardly be considered games.
It&amp;rsquo;s not like I&amp;rsquo;m a complete stranger to game programming though, we had a very brief introduction to game programming at the university, except we never actually programmed games during these courses.
So, for example, I know what delta time is, how it should be used, or how to do vector math needed for basic movement, but this doesn&amp;rsquo;t count as experience.
If you read my blog, you may remember my small projects like &lt;a href=&#34;https://andreyor.st/posts/2020-06-04-simple-ray-casting-with-clojurescript/&#34;&gt;raycasting&lt;/a&gt; and &lt;a href=&#34;https://andreyor.st/posts/2020-10-15-raymarching-with-fennel-and-love/&#34;&gt;raymarching&lt;/a&gt;, which feature movement, camera programming, basic collision detection, and a basic game-loop.
So actually I felt prepared when I decided to enter the jam.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve already tried LÖVE2D in the mentioned raymarching example, so I&amp;rsquo;ve decided to change things up a bit since I&amp;rsquo;ve wanted to explore another project - &lt;a href=&#34;https://tic80.com/&#34; target=&#34;_blank&#34;&gt;TIC-80&lt;/a&gt;.
The change from LÖVE2D to TIC-80 actually made it easier for me, since I could do the sprite-work and sound effects inside tic&amp;rsquo;s inbuilt editors.
So I&amp;rsquo;ve begun to work on it.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ll try to structure this post as a series of days based on the notes I made during the event.
There probably will not be any code though, as I have no early versions, since I&amp;rsquo;ve opted out of using version control systems for this project, to keep the retro vibe of the fantasy computer.&lt;/p&gt;
&lt;h2 id=&#34;day-1&#34;&gt;Day 1&lt;/h2&gt;
&lt;p&gt;The hardest day in my opinion because it is the day when I &lt;strong&gt;have&lt;/strong&gt; to start working on a project I haven&amp;rsquo;t had any thoughts about beforehand.
I&amp;rsquo;ve sat down and thought about what kind of game I &lt;em&gt;can&lt;/em&gt; make in the limited time of the event which was going from May 25 to Jun 1st.
Given 5 days and almost no game development experience, I&amp;rsquo;ve decided to play it safe and make a Breakout-like game.
Though a plain breakout clone would be a bit boring, so I&amp;rsquo;ve decided that I&amp;rsquo;ll put a small twist once you destroy the final block which would shake things a bit and hopefully be a welcome surprise.&lt;/p&gt;
&lt;p&gt;Now, since the theme was chosen I at least knew what I needed to start - a ball, a platform, and a box to bounce the ball to prevent it from flying away to infinity.
But I didn&amp;rsquo;t know how to do anything in tic, so I&amp;rsquo;ve opened up a &lt;a href=&#34;https://tic80.com/learn&#34; target=&#34;_blank&#34;&gt;manual&lt;/a&gt;.
The manual is minimalist, to say the least, and doesn&amp;rsquo;t provide a lot of info beyond essential things.
So I&amp;rsquo;ve picked up the &lt;code&gt;circ&lt;/code&gt; &lt;code&gt;rect&lt;/code&gt; and &lt;code&gt;rectb&lt;/code&gt; functions and started working.
This was my first result:&lt;/p&gt;
&lt;p&gt;&lt;video autoplay loop muted&gt;&lt;source src=&#34;https://andreyor.st/2022-06-12-fennel-game-jam-2022/day1.mp4&#34; type=&#34;video/mp4&#34;&gt;
Your browser does not support the video tag.&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;This has very basic hard-coded physics, meaning that I&amp;rsquo;ve literally defined a vector of all ball velocities and just cycled through it when the ball collided with any world object.
But it already has some interesting stuff done, which I haven&amp;rsquo;t changed much afterward.&lt;/p&gt;
&lt;p&gt;The first thing is that It has a proper world to screen coordinate transformation, which I&amp;rsquo;ve kinda never done before.
It&amp;rsquo;s a simple thing, I just have a world X and Y offsets that made the game world, e.g. the box rest, not in the top left corner but 10 pixels to the right and down.
All game physics was calculated with the top left corner in &lt;code&gt;0,0&lt;/code&gt; and then translated before drawing.&lt;/p&gt;
&lt;p&gt;The platform tracks its position and makes sure not to go outside the world boundaries.
And the ball is checked for collisions with everything but the lower boundary.
There, instead of a collision a basic &lt;code&gt;game-over?&lt;/code&gt; flag is set to interrupt the game loop.&lt;/p&gt;
&lt;p&gt;I was pretty satisfied for day one, especially since it wasn&amp;rsquo;t really a full day of me programming this, but only 3 hours after work.
The jam started at 10:00 AM in my time zone, and my work day also starts at the same time, so I had to begin working on a game 9 hours after the start of the jam.
I&amp;rsquo;m sure this is a common situation for most other participants, though perhaps they have had time before work too.&lt;/p&gt;
&lt;h2 id=&#34;day-2&#34;&gt;Day 2&lt;/h2&gt;
&lt;p&gt;I knew that I&amp;rsquo;ll not be able to move forward with the current physics system I&amp;rsquo;ve added to the game, so I spent most of the second day fighting with the collision system.
This was the result I got:&lt;/p&gt;
&lt;p&gt;&lt;video autoplay loop muted&gt;&lt;source src=&#34;https://andreyor.st/2022-06-12-fennel-game-jam-2022/day2.mp4&#34; type=&#34;video/mp4&#34;&gt;
Your browser does not support the video tag.&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;This had really wonky surface normal calculations, and you can see that the ball isn&amp;rsquo;t particularly happy with the results, as it just decides to leave the game.
I wasn&amp;rsquo;t happy with it either, but it was a move in the right direction.&lt;/p&gt;
&lt;p&gt;In addition to &lt;em&gt;improved&lt;/em&gt; physics, I&amp;rsquo;ve added destructible bricks with a random amount of health represented by a color.
The color was an accident, as I used brick health in place of the brick color when bricks were drawn on the screen, but I actually liked it.
The health was distributed randomly, but I&amp;rsquo;ve been focused on physics, so I&amp;rsquo;ve left it as is.&lt;/p&gt;
&lt;p&gt;There were two main problems.
First, I&amp;rsquo;ve re-used some linear algebra code from my raymarching project, mainly the calculation of the distance to the box and the calculation of the normal.
However, the calculation of a normal was done for a 3D world and wasn&amp;rsquo;t as meaningful for 2D space.
I&amp;rsquo;m not sure whether I&amp;rsquo;ll be able to explain the general method, but the idea is that I&amp;rsquo;ve found an intersection point, and picked two more points one below the surface and to the left and another above the surface and to the right.
Then I used some vector math to find a normal based on distance estimation from these points to the intersection point.
This works quite well for 3D, given that all reflections in the raymarching demo were correct, but in 2D it resulted in weird unexpected reflections (not in the video).&lt;/p&gt;
&lt;p&gt;Unfortunately, I have this kind of problem that once I&amp;rsquo;ve fixated on some solution I can&amp;rsquo;t see another one until I step away from the problem for a bit.
So I&amp;rsquo;ve kept the current physics and ended the day 2 session.&lt;/p&gt;
&lt;h2 id=&#34;day-3&#34;&gt;Day 3&lt;/h2&gt;
&lt;p&gt;This day was mostly spent polishing and rewriting the collision system.
I&amp;rsquo;ve almost fully fixed bugs with unexpected angles, but the ball still managed to find its way inside the platform.
I couldn&amp;rsquo;t spend too much time on it, so I&amp;rsquo;ve decided to leave it as is, and maybe fix it after everything else is done.&lt;/p&gt;
&lt;p&gt;In addition to that, I&amp;rsquo;ve made it such that the block health depends on the row it was spawned at.
So the lower blocks had 1 health, the next row above it had 2 health, and so on.
This can be seen with this nice color transition from purple to orange.&lt;/p&gt;
&lt;p&gt;&lt;video autoplay loop muted&gt;&lt;source src=&#34;https://andreyor.st/2022-06-12-fennel-game-jam-2022/day3.mp4&#34; type=&#34;video/mp4&#34;&gt;
Your browser does not support the video tag.&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve also done some basic point systems that added 100 points when you destroy a brick, and 10 points upon collision.
There are now lives, so you can lose the ball several times before the &amp;ldquo;game over&amp;rdquo;.
Satisfied with that I&amp;rsquo;ve ended the third day, realizing that theirs not that much time left, but also not too far til the game will be complete.&lt;/p&gt;
&lt;p&gt;For the next two days, I was planning to add graphics and a small twist that will hopefully make the game a bit more interesting.&lt;/p&gt;
&lt;h2 id=&#34;day-4&#34;&gt;Day 4&lt;/h2&gt;
&lt;p&gt;Up until this day I&amp;rsquo;ve drawn everything with basic rectangles and this wasn&amp;rsquo;t going to cut for the jam in my opinion.
So for the fourth day, I&amp;rsquo;ve decided to focus on some graphics and sounds.&lt;/p&gt;
&lt;p&gt;The inbuilt sprite editor is quite good, actually.
I&amp;rsquo;ve only tried the &lt;a href=&#34;https://github.com/LibreSprite/LibreSprite&#34; target=&#34;_blank&#34;&gt;LibreSprite&lt;/a&gt;, an open-source fork of aseprite sprite editor, and it was a bit sluggish, perhaps because it was using a software cursor, which felt unresponsive.
But with TIC&amp;rsquo;s sprite editor it wasn&amp;rsquo;t a problem and I quickly drew basic sprites for bricks, the platform, and the ball:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2022-06-12-fennel-game-jam-2022/sprites.gif&#34;
         alt=&#34;Figure 1: Sprites&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 1: &lt;/span&gt;Sprites&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Then I decided to add power-ups.&lt;/p&gt;
&lt;p&gt;There are three classic power-ups that affect the size of the ball or the platform - the big ball, the long platform, and the short platform.
All these powers are timer-based, with a small exception for the big ball - if you lose the ball while it&amp;rsquo;s big, the power-up is also lost.
In addition to that, there are two speed-related power-ups, one that increases the ball&amp;rsquo;s speed, and one that decreases it.&lt;/p&gt;
&lt;p&gt;Speaking of speed, I&amp;rsquo;ve also made it so that the speed of the ball gradually grows during the game up to twice the initial speed.
And there&amp;rsquo;s a mentioned power-up to increase and decrease the value by a quarter.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s a demonstration of various power-ups:&lt;/p&gt;
&lt;p&gt;&lt;video autoplay loop muted&gt;&lt;source src=&#34;https://andreyor.st/2022-06-12-fennel-game-jam-2022/day4.mp4&#34; type=&#34;video/mp4&#34;&gt;
Your browser does not support the video tag.&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;As can be seen, the ball still can act weirdly, almost spinning around the platform, but I&amp;rsquo;ve already spent most of my time on graphics and sounds, so I&amp;rsquo;ve decided to left it for the last day.&lt;/p&gt;
&lt;h2 id=&#34;day-5&#34;&gt;Day 5&lt;/h2&gt;
&lt;p&gt;The last day of the jam!
I&amp;rsquo;ve added more graphics, as I wasn&amp;rsquo;t able to figure out how to measure things in seconds, as the values of the &lt;code&gt;time&lt;/code&gt; function were kinda &lt;em&gt;weird&lt;/em&gt;.
So I&amp;rsquo;ve opted out of colored bars that gradually decrease in length.
I&amp;rsquo;ve also decided to add some effects, like screen shake when the ball is big.
Here&amp;rsquo;s how it looks:&lt;/p&gt;
&lt;p&gt;&lt;video autoplay loop muted&gt;&lt;source src=&#34;https://andreyor.st/2022-06-12-fennel-game-jam-2022/day5.mp4&#34; type=&#34;video/mp4&#34;&gt;
Your browser does not support the video tag.&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;At this point, I&amp;rsquo;ve started working on the &lt;em&gt;twist&lt;/em&gt; and polishing things out.
For the twist I&amp;rsquo;ve decided to do a boss battle at the end of the game, essentially turning the Breakout game into Pong when the last brick is destroyed:&lt;/p&gt;
&lt;p&gt;&lt;video autoplay loop muted&gt;&lt;source src=&#34;https://andreyor.st/2022-06-12-fennel-game-jam-2022/boss-battle.mp4&#34; type=&#34;video/mp4&#34;&gt;
Your browser does not support the video tag.&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;The boss has a fixed amount of health, and each hit with the ball removes some amount of it.
If the big ball power-up is active the ball deals twice the damage.
I&amp;rsquo;ve actually made it that this damage multiplier also affects bricks, so bricks are destroyed a bit faster now too.
And if you score the boss, it&amp;rsquo;ll lose 5 times hp of a single hit, although it&amp;rsquo;s almost impossible, unless you picked a lot of speed power-ups.&lt;/p&gt;
&lt;p&gt;Boss&amp;rsquo; health is represented with another bar that changes color depending on the health range, going from green at full to red near the end.
To win the game you must defeat the boss, which is actually a bit tricky and I can&amp;rsquo;t do it consistently myself either.
Speaking of power-ups, there&amp;rsquo;s a random chance to spawn a power-up in a random location during the boss battle.
The chance of spawning is very low though.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve uploaded the game to itch as a web build, and noticed a weird problem.
All power-ups were wearing off too fast!
I couldn&amp;rsquo;t understand what the problem is, because to my knowledge I did a proper way of handling power-up times - I obtained the current game-time with the call to the &lt;code&gt;time&lt;/code&gt; function, added a fixed amount to it, and checked on each frame if the value returned by &lt;code&gt;time&lt;/code&gt; surpassed it.
To simplify, upon activation of a timer based power-up, I did this &lt;code&gt;end = time() + powerup_duration&lt;/code&gt;, and checked for &lt;code&gt;end &amp;lt; time()&lt;/code&gt; to disable the power-up.
Given that it is based on &lt;code&gt;time&lt;/code&gt; and not on some ticking mechanism, I&amp;rsquo;ve thought that it should work equally well regardless of frames per second.
Even more weird was that the ball speed was the same as on the desktop.
So in short - power-ups ended a lot faster, yet the rest of the speed was the same.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve decided to do it &amp;ldquo;properly&amp;rdquo; and calculated the delta time.
Then I multiplied ball movement by newly calculated &lt;code&gt;dt&lt;/code&gt; and reworked power-ups to work based on ticks, meaning they weren&amp;rsquo;t tied to &lt;code&gt;time&lt;/code&gt; directly.
Checked that all works well on my desktop I&amp;rsquo;ve made a fresh web build, uploaded it to itch, and it was way too fast!
The ball speed now was superfast, power-ups ended almost immediately.
After a ton of debugging, and trying to make any sense out of the phrase that the main &lt;code&gt;TIC&lt;/code&gt; function is called 60 times per second, when it &lt;em&gt;clearly&lt;/em&gt; wasn&amp;rsquo;t, as the game speed was different between the web and Linux builds.
Then I made a Windows build, and it worked with the same speed as the web build, and I thought that maybe it was a bug in the Linux build.
I&amp;rsquo;ve checked what value of &lt;code&gt;dt&lt;/code&gt; was calculated on each platform, and the Linux build had a 10-fold difference from other platforms:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2022-06-12-fennel-game-jam-2022/tic-bug.png&#34;
         alt=&#34;Figure 2: Delta time differences between platforms&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 2: &lt;/span&gt;Delta time differences between platforms&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;The Linux build had a delta time value of approximately &lt;code&gt;0.001&lt;/code&gt; while the web and Windows build had &lt;code&gt;0.02&lt;/code&gt;.
I&amp;rsquo;ve tried an older version of TIC, and it had no such issue but didn&amp;rsquo;t support the Fennel version I was using for the game.
So I had to distribute the game only as a web build until the &lt;a href=&#34;https://github.com/nesbox/TIC-80/issues/1904&#34; target=&#34;_blank&#34;&gt;issue&lt;/a&gt; is fixed.
I&amp;rsquo;ve tweaked the speed by adding a &lt;code&gt;game_speed&lt;/code&gt; parameter that I could tweak around inside the web build to make the speed feel right.
After that, I pushed a final web build with these tweaks and submitted the game.&lt;/p&gt;
&lt;h2 id=&#34;jam-results&#34;&gt;Jam results&lt;/h2&gt;
&lt;p&gt;Because of my time zone, I was the first who submitted a game, but I couldn&amp;rsquo;t do any more work because the last hours of the jam were at nighttime here.
Out of 21 participants, only seven games were submitted, which actually a pretty great result, in my opinion, it&amp;rsquo;s a solid third!
Funnily enough, we have about 60 people in our &lt;code&gt;#fennel&lt;/code&gt; IRC channel on &lt;a href=&#34;https://libera.chat/&#34; target=&#34;_blank&#34;&gt;Libera.Chat&lt;/a&gt;, so 21 people is a third too.
The results can be viewed &lt;a href=&#34;https://itch.io/jam/fennel-game-jam-1/results&#34; target=&#34;_blank&#34;&gt;here&lt;/a&gt;, and I suggest you try all games, as there are pretty cool entries!&lt;/p&gt;
&lt;p&gt;I managed to score third place, which actually surprised me a bit, given how simple the concept of my game was.
But I&amp;rsquo;m glad, and I think it&amp;rsquo;s a solid result for the first game.&lt;/p&gt;
&lt;p&gt;In retrospect, I think I could do some things better, especially in the user interface department.
Adding a proper menu, maybe an intro, making the interface look more like an arcade cabinet, which I&amp;rsquo;ve originally attempted, but my pixel-art skills are not that great yet.
But I still like the result, I feel that for a first game it turned out pretty great.
And the process was quite fun, which is the most important thing for me.&lt;/p&gt;
&lt;p&gt;I hope I&amp;rsquo;ll participate in more lisp-themed jams, maybe in a lisp game jam or the next Fennel jam.
I&amp;rsquo;ve always wanted to make games, and I had some ideas about the game I want to make in the Metroidvania genre.
Game jams are perfect for experiments, and you can learn a lot by doing things you never did before.
I&amp;rsquo;m not going to make a whole game during the jam as I want it to be a more complete thing, but the jam can help me to flesh out some main mechanics, be it the movement, or world-building practice.
So I&amp;rsquo;m looking forward to the upcoming events!&lt;/p&gt;
&lt;p&gt;This was a lot of fun, and I hope more people will join next time!
Thanks to everyone who participated, &lt;a href=&#34;https://www.mattroelle.com/&#34; target=&#34;_blank&#34;&gt;Matt Roelle&lt;/a&gt; for organizing the Jam, and everyone involved in Fennel and TIC-80 development.&lt;/p&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: Fennel Game Jam 2022&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Sun, 12 Jun 2022 12:37:00 +0300</pubDate>
    </item><item>
      <title>Naive async implementation in Fennel</title>
      <link>https://andreyor.st/posts/2021-10-27-naive-async-implementation-in-fennel/</link>
      <guid>https://andreyor.st/posts/2021-10-27-naive-async-implementation-in-fennel/</guid>
      <description>&lt;p&gt;Lately, I&amp;rsquo;ve been into understanding asynchronous programming.
Since my background is mostly bare metal C, which has no asynchronous programming whatsoever (apart from running on multiple chips, and communicating via shared memory), and I did only a little bit of C++ and Rust, it&amp;rsquo;s fair to say, that async is pretty new for me.
And because I now work in Clojure, I sometimes have to use asynchronous programming libraries like &lt;a href=&#34;https://github.com/clojure/core.async&#34; target=&#34;_blank&#34;&gt;core.async&lt;/a&gt;, and &lt;a href=&#34;https://github.com/clj-commons/manifold&#34; target=&#34;_blank&#34;&gt;manifold&lt;/a&gt;.
Both are great libraries, providing ways to write asynchronous applications and stay sane.&lt;/p&gt;
&lt;p&gt;Clojure has really good facilities for writing concurrent programs, as it was designed with that in mind.
Fennel, on the other hand, wasn&amp;rsquo;t, as it targets Lua, and Lua doesn&amp;rsquo;t have multithreading capabilities at all.
Because of that, there are no concurrency primitives in the Lua language, besides coroutines.
Coroutines, however, provide a certain degree of multitasking but run on a single thread.
It is possible to implement some kind of multitasking via coroutines, but it requires writing a program in a certain way.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve decided to try implementing something similar to Clojure&amp;rsquo;s &lt;code&gt;core.async&lt;/code&gt; for Fennel, but probably naive and much simpler, and see where I can get with it.
This article will go into detail on how to implement a rather simple event loop, with a way of spawning concurrent tasks, which rely only on coroutines.&lt;/p&gt;
&lt;h2 id=&#34;writing-an-event-loop&#34;&gt;Writing an event loop&lt;/h2&gt;
&lt;p&gt;The event loop in our case will be an infinite loop, that cycles through all tasks over and over, executing each in a blocking way.
The only way of writing a non-blocking code in Lua is to use &lt;code&gt;coroutine.create&lt;/code&gt; and then &lt;code&gt;coroutine.yield&lt;/code&gt; to temporarily stop the execution.
Let&amp;rsquo;s start with a task queue:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;queue&lt;/span&gt; [])
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;For our purposes, just a sequential table will do.
The &lt;code&gt;queue&lt;/code&gt; will hold coroutines, and we need to check their statuses in the loop.
Let&amp;rsquo;s write the loop itself:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;worker&lt;/span&gt; []
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;while&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;each&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;task&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ipairs&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;queue&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;match&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;coroutine.status&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;task&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:suspended&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;coroutine.resume&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;task&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;table.remove&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;queue&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If the coroutine is &lt;code&gt;suspended&lt;/code&gt;, we &lt;code&gt;resume&lt;/code&gt; it, and go to the next one, once it yields.
If the coroutine has died, we remove it from the task queue to keep the queue clean.&lt;/p&gt;
&lt;p&gt;Now we need a way to spawn coroutines.
Let&amp;rsquo;s write a function, that accepts a function, creates the coroutine, and puts it in our queue:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;spawn&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;task&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;task&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;coroutine.create&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;task&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;table.insert&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;queue&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;task&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;task&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That&amp;rsquo;s pretty much it!
Upon invocation, this function would return something like &lt;code&gt;#&amp;lt;thread: 0x564c2c5e2ae8&amp;gt;&lt;/code&gt;, which is a newly created &lt;em&gt;thread&lt;/em&gt; object.
Not to be confused with real threads, this is just the way Lua refers to coroutines.&lt;/p&gt;
&lt;p&gt;We now have a very, &lt;em&gt;very&lt;/em&gt; simple event loop, that we can use to spawn coroutines like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;spawn&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[] (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;for &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; 1 5] (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;print &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;foo&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;coroutine.yield&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; #(...) is the same as (fn [] ...) but shorter&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;spawn&lt;/span&gt;       #(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;for &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; 1 5] (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;print &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;bar&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;coroutine.yield&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Right now nothing happens, because we need to start the &lt;code&gt;worker&lt;/code&gt; to see the result.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;worker&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We should see something like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;foo 1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;bar 1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;foo 2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;bar 2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;foo 3
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;bar 3
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;foo 4
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;bar 4
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;foo 5
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;bar 5
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As can be seen, both tasks were executed &lt;em&gt;simultaneously&lt;/em&gt;, because each task pauses itself on each iteration step, so other tasks had a chance to run.
It is an example of collaborative (preemptive) multithreading.
We can&amp;rsquo;t spawn real threads in stock Lua runtime without special libraries that provide process-based multithreading.&lt;/p&gt;
&lt;p&gt;But these libraries spawn separate &lt;code&gt;lua&lt;/code&gt; instances that can communicate via message-passing.
Coroutines on the other hand can share states via global variables, which is a bit more performant, as you don&amp;rsquo;t have to serialize and deserialize data.
Although, because everything runs in a single process, there&amp;rsquo;s no real performance gain, when compared to real threading, so where the performance matters, message-passing between real threads is the way to go.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s leave a message passing out for now, as right now we don&amp;rsquo;t have a nice way of working with these tasks interactively.
Right now, since we&amp;rsquo;ve started the &lt;code&gt;worker&lt;/code&gt;, our tasks are completed, and the worker now loops in an infinite empty cycle, blocking our REPL.
Because of this, it is quite cumbersome to work, so let&amp;rsquo;s write a REPL that will work asynchronously in our event loop alongside other tasks.&lt;/p&gt;
&lt;h2 id=&#34;writing-an-asynchronous-repl&#34;&gt;Writing an asynchronous REPL&lt;/h2&gt;
&lt;p&gt;The REPL code below is based on &lt;a href=&#34;https://git.sr.ht/~technomancy/fennel/tree/2192c90383663664d0de57004cdbc6975f9a282d/item/test/repl.fnl#L4-23&#34; target=&#34;_blank&#34;&gt;Fennel&amp;rsquo;s REPL test code&lt;/a&gt; but slightly simplified for the purpose of this article.
For those unfamiliar with Lisps, REPL stands for Read Eval Print Loop and is something like an interactive shell for working with a running Lisp process.
Fennel has an inbuilt REPL, and we can reuse it, but we need to make sure, that its looping aspect doesn&amp;rsquo;t block our task queue when we wait for input.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s start by declaring prompt variables:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;prompt-ready&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;repl&amp;gt;&amp;gt; &amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;prompt-multi&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;.. &amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;var &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;prompt&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;prompt-ready&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I&amp;rsquo;m deliberately changing the standard &lt;code&gt;&amp;quot;&amp;gt;&amp;gt; &amp;quot;&lt;/code&gt; prompt to &lt;code&gt;&amp;quot;repl&amp;gt;&amp;gt; &amp;quot;&lt;/code&gt;, so we could see that we&amp;rsquo;re in our special kind of REPL a bit easier.
There are two separate prompts here, and we will change the type of our REPL receives an unfinished expression, indicating that the REPL still waits for input.
Next, let&amp;rsquo;s set up the REPL itself:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fennel&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;require&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:fennel&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;repl&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;options&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;send &lt;/span&gt;[]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;var &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;output&lt;/span&gt; []) &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;; ➊&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fennel.repl&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:readChunk&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[{&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;stack-size&lt;/span&gt;}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;prompt&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;&amp;lt; &lt;/span&gt;0 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;stack-size&lt;/span&gt;) &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;; ➋&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                   &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;prompt-multi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                   &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;prompt-ready&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;when &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;&amp;gt; &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;length&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;output&lt;/span&gt;) 0)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;io.write&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;table.concat&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;output&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\t&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\n&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chunk&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;coroutine.yield&lt;/span&gt;)] &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;; ➌&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                     (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;output&lt;/span&gt; [])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                     (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;and &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chunk&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chunk&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\n&amp;#34;&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:onValues&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;table.insert&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;output&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;table.concat&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\t&amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:onError&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;e&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;table.insert&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;output&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;error: &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;e&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:pp&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fennel.view&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;))}))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;send &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;coroutine.wrap&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;send&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;send&lt;/span&gt;) &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;; ➍&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;send&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Let&amp;rsquo;s look at it step by step.&lt;/p&gt;
&lt;p&gt;First, we define an &lt;code&gt;output&lt;/code&gt; variable ➊.
It will store the current output, which we will use in the &lt;code&gt;readChunk&lt;/code&gt; method, which we can see in the table, being passed to &lt;code&gt;fennel.repl&lt;/code&gt; call.&lt;/p&gt;
&lt;p&gt;This method accepts a table with REPL&amp;rsquo;s state, and we&amp;rsquo;re interested in the &lt;code&gt;stack-size&lt;/code&gt; value.
If it is greater than &lt;code&gt;0&lt;/code&gt;, we set the prompt to multiline prompt &lt;code&gt;..&lt;/code&gt;, and to &lt;code&gt;repl&amp;gt;&amp;gt;&lt;/code&gt; otherwise ➋.
Next, we check if the &lt;code&gt;output&lt;/code&gt; table contains anything.
If it does, we concatenate the elements and print it to standard out.
After which we &lt;code&gt;yield&lt;/code&gt; ➌ from the REPL until new input arrives.
This &lt;code&gt;yield&lt;/code&gt; right there is what allows us to use the REPL in a non-blocking way.&lt;/p&gt;
&lt;p&gt;The rest methods handle values and errors that happen in the REPL, and &lt;code&gt;pp&lt;/code&gt; pretty-prints values for display.&lt;/p&gt;
&lt;p&gt;Lastly, we &lt;code&gt;wrap&lt;/code&gt; our function, execute it to start the REPL ➍ and return the wrapped function.
The resulting function is called &lt;code&gt;send&lt;/code&gt;, which sends the input to the REPL for evaluation.
But how can we get input?
Especially since we don&amp;rsquo;t want to block other tasks from running.&lt;/p&gt;
&lt;h3 id=&#34;input-polling&#34;&gt;Input polling&lt;/h3&gt;
&lt;p&gt;We can get the input with the &lt;code&gt;io.read&lt;/code&gt; function, and luckily for us, this function works with the stdin buffer:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;gt;&amp;gt; (io.read 0)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;1234
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;#34;&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;gt;&amp;gt; (io.read &amp;#34;l*&amp;#34;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;#34;1234&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We&amp;rsquo;ve called &lt;code&gt;io.read(0)&lt;/code&gt; which reads &lt;code&gt;0&lt;/code&gt; characters from standard input.
It returned an empty string because that&amp;rsquo;s what zero characters are.
Next, we called it again but with the &lt;code&gt;&amp;quot;l*&amp;quot;&lt;/code&gt; argument, which means to read a complete line, and the result was &lt;code&gt;&amp;quot;1234&amp;quot;&lt;/code&gt; - the data that we&amp;rsquo;ve previously sent via stdin, and we&amp;rsquo;ve successfully read it back.&lt;/p&gt;
&lt;p&gt;But this has a problem - we don&amp;rsquo;t know if stdin already has something in the buffer, so if the buffer is empty, the &lt;code&gt;(io.read &amp;quot;l*&amp;quot;)&lt;/code&gt; call will block until the input is supplied.
Unfortunately, Lua runtime doesn&amp;rsquo;t have any kind of input polling, and its &lt;code&gt;io&lt;/code&gt; module is very minimalist.
So we need a way to check if &lt;code&gt;stdin&lt;/code&gt; has anything in the buffer.
For this task we can use &lt;code&gt;luaposix&lt;/code&gt; library which can be installed via &lt;code&gt;luarocks&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ luarocks install --local luaposix
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This library provides the &lt;code&gt;rpoll&lt;/code&gt; function, which can be used to check if a file descriptor contains anything ready to be read.
Let&amp;rsquo;s write a task for our &lt;code&gt;worker&lt;/code&gt; that will first set up a REPL, and then go into an infinite loop, polling for the input:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;p&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;require&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:posix&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;async-repl&lt;/span&gt; []
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;send &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;repl&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;io.write&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;prompt&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;io.flush&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;while&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;when &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;&amp;lt; &lt;/span&gt;0 (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;p.rpoll&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;p.STDIN_FILENO&lt;/span&gt; 0))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;send &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;io.read&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;l*&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;io.write&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\r&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;prompt&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;io.flush&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;coroutine.yield&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;spawn&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;async-repl&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;worker&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;p.rpool&lt;/code&gt; function checks if &lt;code&gt;p.STDIN_FILENO&lt;/code&gt; has any data in the buffer.
When this function returns a non-zero value, we &lt;code&gt;read&lt;/code&gt; the whole line from stdio, and &lt;code&gt;send&lt;/code&gt; it to the REPL.
Then we display the &lt;code&gt;prompt&lt;/code&gt;, &lt;code&gt;flush&lt;/code&gt;, and finally &lt;code&gt;yield&lt;/code&gt; so other spawned processes could cooperate.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s try it out.
The code up to this point can be saved to a file, called &lt;code&gt;async.fnl&lt;/code&gt; so we could easier run it from the shell:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ fennel async.fnl
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;repl&amp;gt;&amp;gt; (+ 1 2 3)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;6
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;repl&amp;gt;&amp;gt; (+ 1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;..  2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;..  3)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;6
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;repl&amp;gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now, when we have the REPL, and it&amp;rsquo;s working we can &lt;code&gt;spawn&lt;/code&gt; some processes!&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;repl&amp;gt;&amp;gt; (spawn #(for [i 1 5] (print i) (coroutine.yield)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;error: global &amp;#39;spawn&amp;#39; is not callable (a nil value)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Uh oh, the &lt;code&gt;spawn&lt;/code&gt; function is not known by our REPL.
But that&amp;rsquo;s easy to fix.
As you may remember, coroutines can access the global state, and we just need to make &lt;code&gt;spawn&lt;/code&gt; function and the &lt;code&gt;queue&lt;/code&gt; globals:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;global&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;queue&lt;/span&gt; [])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_G.spawn&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;task&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;task&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;coroutine.create&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;task&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;table.insert&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;queue&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;task&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;task&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With this change we can start spawning processes from our REPL:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ fennel async.fnl
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;repl&amp;gt;&amp;gt; (spawn #(for [i 1 5] (print i) (for [i 1 1000000] (coroutine.yield))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#&amp;lt;thread: 0x56055ef88ae8&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;repl&amp;gt;&amp;gt; 1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;3
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(print :foo)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;foo
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;repl&amp;gt;&amp;gt; 4
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;5
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;repl&amp;gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As you can see, I&amp;rsquo;ve added an empty loop with &lt;code&gt;coroutine.yield&lt;/code&gt; call to slow down the process, so I could input the &lt;code&gt;(print :foo)&lt;/code&gt; expression.
Because our system toggles between processes, we were able to input the expression and see the result without waiting until the first task completes.
This basically means that our non-blocking REPL works.&lt;/p&gt;
&lt;p&gt;Though, unfortunately, the prompt gets in the way when printing from different threads.
As a workaround, the &lt;code&gt;print&lt;/code&gt; function can be redefined to clear the line before printing, but it&amp;rsquo;s not a proper solution either.&lt;/p&gt;
&lt;h2 id=&#34;communicating-between-threads&#34;&gt;Communicating between threads&lt;/h2&gt;
&lt;p&gt;The last missing point for our system is a way to communicate between tasks/threads.
While global variables can be used by coroutines as a way of sharing the state, it is a really poor choice.
Global variables don&amp;rsquo;t have any concurrency semantics and are especially very hard to debug.
Another problem is that we will have to implement synchronization primitives ourselves each time we interact with globals, which is not good.&lt;/p&gt;
&lt;p&gt;There are two things that can help us solve this problem.
First are so-called promises, which can be blocked upon reading if they weren&amp;rsquo;t realized, and the other one is a channel.
Promises are easy to implement, and we can actually write one like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_G.promise&lt;/span&gt; []
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:val&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:deliver&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;val&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self.val&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  (&lt;span style=&#34;font-weight:bold&#34;&gt;do &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self.val&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;val&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                      &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;true&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;false&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:deref&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;while&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self.val&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;coroutine.yield&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self.val&lt;/span&gt;)})
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It&amp;rsquo;s a really simple implementation, but we can see that it works as expected:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;repl&amp;gt;&amp;gt; (local p (promise))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;nil
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;repl&amp;gt;&amp;gt; (spawn #(print (.. &amp;#34;promise: &amp;#34; (p:deref))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#&amp;lt;thread: 0x561ae3b49568&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;repl&amp;gt;&amp;gt; (p:deliver 42)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;true
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;repl&amp;gt;&amp;gt; promise: 42
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;repl&amp;gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As we can see, we&amp;rsquo;ve created a thread, that parked itself when it tried to dereference the promise, and the moment we delivered the promise, we saw the message from that thread.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: Once again, &lt;code&gt;repl&amp;gt;&amp;gt;&lt;/code&gt; prompt got in the way, and it will be a common thing in all following examples.
I&amp;rsquo;ve thought about removing the prompt from output manually but decided not to, as if someone will try this code, they might think that something is wrong, as the output will differ from the one in this article.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This is a handy construct when we need to deliver value from one thread to another, without blocking our program, but after the delivery is complete, the promise becomes useless.
Because we can&amp;rsquo;t deliver a promise twice - once it was delivered, the value is set in stone&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;.
What if we need to pass several values from one thread to another?
Of course, we can &lt;code&gt;deliver&lt;/code&gt; a table with values to our promise, but what if we don&amp;rsquo;t have all the necessary data to produce these values right now?&lt;/p&gt;
&lt;p&gt;Channels are really good for this - we can put as many values as we want to a named channel and take from it in another thread, parking the reading thread, if the channel is empty, or putting a thread if the channel is full in case of backpressure.
Let&amp;rsquo;s create the &lt;code&gt;chan&lt;/code&gt;, &lt;code&gt;take&lt;/code&gt; and &lt;code&gt;put&lt;/code&gt; functions:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_G.chan&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;size&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:size&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;size&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;math.huge&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:buf&lt;/span&gt; []})
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;For now, &lt;code&gt;chan&lt;/code&gt; will simply create a table with our channel buffer &lt;code&gt;buf&lt;/code&gt; stored as a sequential table, and optional &lt;code&gt;size&lt;/code&gt;, indicating channel size and acting as back pressure.
Now we can write a non-blocking &lt;code&gt;put&lt;/code&gt; and &lt;code&gt;take&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_G.put&lt;/span&gt; [{&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buf&lt;/span&gt; &lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;size&lt;/span&gt;} &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;assert &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;not= &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;value must not be nil&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;while&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;= &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;length&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buf&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;size&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;coroutine.yield&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;table.insert&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buf&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;true&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_G.take&lt;/span&gt; [{&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buf&lt;/span&gt;}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;while&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;= &lt;/span&gt;0 (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;length&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buf&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;coroutine.yield&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;table.remove&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buf&lt;/span&gt; 1))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You can see, that our &lt;code&gt;put&lt;/code&gt; will wait until the &lt;code&gt;length&lt;/code&gt; of the channel&amp;rsquo;s buffer is less than its maximum &lt;code&gt;size&lt;/code&gt;.
Similarly, &lt;code&gt;take&lt;/code&gt; will wait for elements to appear.
These operations are non-blocking, which means, that they must be used only in the processes we&amp;rsquo;re created via the &lt;code&gt;spawn&lt;/code&gt; function.
Let&amp;rsquo;s try this out:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;repl&amp;gt;&amp;gt; (local c (chan 3))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;nil
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;repl&amp;gt;&amp;gt; (spawn #(for [i 1 10] (put c i) (print (.. &amp;#34;put: &amp;#34; i))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#&amp;lt;thread: 0x564b48408608&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;repl&amp;gt;&amp;gt; put: 1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;put: 2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;put: 3
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;First, we&amp;rsquo;ve created a channel &lt;code&gt;c&lt;/code&gt; with a size of 3.
Next, we&amp;rsquo;ve spawned a numeric for loop, that will try putting indexes to the channel, and printing the values afterward.
You can see that right after that the &lt;code&gt;put: 1&lt;/code&gt; to &lt;code&gt;put: 3&lt;/code&gt; messages appeared, indicating that we&amp;rsquo;ve successfully put 3 values to our channel &lt;code&gt;c&lt;/code&gt;.
However, the values &lt;code&gt;4&lt;/code&gt; to &lt;code&gt;10&lt;/code&gt; were not put into the channel, because of the backpressure.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s spawn a single &lt;code&gt;take&lt;/code&gt; from the channel:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;repl&amp;gt;&amp;gt; (spawn #(print (.. &amp;#34;take: &amp;#34; (take c))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#&amp;lt;thread: 0x564b483f0ae8&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;repl&amp;gt;&amp;gt; take: 1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;put: 4
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As can be seen, we&amp;rsquo;ve taken the value &lt;code&gt;1&lt;/code&gt; from the channel, and immediately the next value was put to it, as shown by &lt;code&gt;put: 4&lt;/code&gt; message.
Let&amp;rsquo;s spawn another loop, that repeatedly takes values from our channel and prints them:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;repl&amp;gt;&amp;gt; (spawn #(while true (print &amp;#34;take: &amp;#34; (take c))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#&amp;lt;thread: 0x564b483dbeb8&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;repl&amp;gt;&amp;gt; take: 2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;take: 3
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;take: 4
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;put: 5
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;put: 6
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;put: 7
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;take: 5
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;take: 6
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;take: 7
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;put: 8
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;put: 9
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;put: 10
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;take: 8
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;take: 9
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;take: 10
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Aha!
Now we can see that this spawned task took 3 elements from the channel and parked itself, waiting for elements.
Then our other loop inserted values 5, 6, and 7 into the channel, and parked itself because of the back pressure.
And the cycle repeated itself until the putting loop was exhausted.&lt;/p&gt;
&lt;p&gt;We can spawn another &lt;code&gt;put&lt;/code&gt;, and we&amp;rsquo;ll immediately see &lt;code&gt;take&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;repl&amp;gt;&amp;gt; (spawn #(put c 42))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#&amp;lt;thread: 0x564b48408608&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;repl&amp;gt;&amp;gt; take: 42
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;repl&amp;gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Because the size of the channel was set to &lt;code&gt;3&lt;/code&gt;, we saw puts and takes in groups of three.
If we create a channel with unlimited buffer size, we can potentially block our program if some process would decide to put an infinite amount of values to the channel.
So it is better to have channels with some buffering, to prevent that from happening.&lt;/p&gt;
&lt;p&gt;We can create two more channels to illustrate that:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;repl&amp;gt;&amp;gt; (local c-no-bp (chan))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;nil
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;repl&amp;gt;&amp;gt; (do (spawn #(for [i 1 5] (put c-no-bp i) (print (.. &amp;#34;put: &amp;#34; i))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;..         (spawn #(while true (print (.. &amp;#34;take: &amp;#34; (take c-no-bp))))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#&amp;lt;thread: 0x5607d13a0eb8&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;repl&amp;gt;&amp;gt; put: 1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;put: 2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;put: 3
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;put: 4
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;put: 5
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;take: 1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;take: 2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;take: 3
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;take: 4
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;take: 5
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;repl&amp;gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As can be seen, the first &lt;code&gt;for&lt;/code&gt; loop puts all of its elements into a channel &lt;code&gt;c-no-bp&lt;/code&gt;, which has no backpressure, and only then the next loop takes each of these elements.
On the other hand, if we create a channel with the size of &lt;code&gt;1&lt;/code&gt;, we&amp;rsquo;ll get this output:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;repl&amp;gt;&amp;gt; (local c1 (chan 1))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;nil
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;repl&amp;gt;&amp;gt; (do (spawn #(for [i 1 5] (put c1 i) (print (.. &amp;#34;put: &amp;#34; i))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;..         (spawn #(while true (print (.. &amp;#34;take: &amp;#34; (take c1))))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#&amp;lt;thread: 0x5607d1365f78&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;repl&amp;gt;&amp;gt; put: 1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;take: 1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;put: 2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;take: 2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;put: 3
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;take: 3
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;put: 4
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;take: 4
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;put: 5
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;take: 5
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;repl&amp;gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Channel with a fixed size can act as a synchronization primitive to your program.
Alternatively, if you really need an unlimited buffer, you could use &lt;code&gt;coroutine.yield&lt;/code&gt; directly in the putting loop, to put one value at a time.&lt;/p&gt;
&lt;h2 id=&#34;practical-example&#34;&gt;Practical example&lt;/h2&gt;
&lt;p&gt;Now, when our system is mostly ready, let&amp;rsquo;s create a practical example with our channels!&lt;/p&gt;
&lt;p&gt;For this, I&amp;rsquo;ve decided to use Love2d - a game engine, that can run Lua directly.
Love2d actually has its own implementation of threads, that work similarly to what I&amp;rsquo;ve described at the beginning of this article - by passing messages, serializing, and deserializing data.
The real reason is that I want to draw something using collaborative multitasking, and I could as well take Fengari, but I don&amp;rsquo;t want to mess with the web until necessary.&lt;/p&gt;
&lt;p&gt;So let&amp;rsquo;s put all our code to the file, and set up the LÖVE project, we&amp;rsquo;ll only need one file &lt;code&gt;main.fnl&lt;/code&gt; for this.&lt;/p&gt;
&lt;p&gt;First let&amp;rsquo;s add our &lt;code&gt;spawn&lt;/code&gt;, &lt;code&gt;worker&lt;/code&gt;, and channel-related code to the &lt;code&gt;main.fnl&lt;/code&gt; file:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;queue&lt;/span&gt; [])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;spawn&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;task&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;task&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;coroutine.create&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;task&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;table.insert&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;queue&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;task&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;task&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chan&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;size&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:size&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;size&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;math.huge&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:buf&lt;/span&gt; []})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;put&lt;/span&gt; [{&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buf&lt;/span&gt; &lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;size&lt;/span&gt;} &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;assert &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;not= &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;value must not be nil&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;while&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;= &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;length&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buf&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;size&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;coroutine.yield&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;table.insert&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buf&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;true&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;take &lt;/span&gt;[{&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buf&lt;/span&gt;}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;while&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;= &lt;/span&gt;0 (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;length&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buf&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;coroutine.yield&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;table.remove&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buf&lt;/span&gt; 1))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;worker&lt;/span&gt; []
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;each&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;task&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ipairs&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;queue&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;match&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;coroutine.status&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;task&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:suspended&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;coroutine.resume&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;task&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;table.remove&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;queue&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Note that the &lt;code&gt;worker&lt;/code&gt; no longer has the &lt;code&gt;while&lt;/code&gt; loop in it, because it will be handled by &lt;code&gt;love.draw&lt;/code&gt; function.&lt;/p&gt;
&lt;p&gt;Now, let&amp;rsquo;s set up our channel, and some threads:&lt;/p&gt;
&lt;p&gt;&lt;a id=&#34;code-snippet--love-threads&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chan&lt;/span&gt; 1))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;width&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;height&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.graphics.getDimensions&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;for &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; 0 (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;/ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;width&lt;/span&gt; 8)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;for &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;j&lt;/span&gt; 0 (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;/ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;height&lt;/span&gt; 8)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;spawn&lt;/span&gt; #(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;while&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;put&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt; [(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;math.random&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;math.random&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;math.random&lt;/span&gt;)])))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;spawn&lt;/span&gt; #(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;while&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.graphics.setColor&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;take &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.graphics.rectangle&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:fill&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;j&lt;/span&gt; 1 1))))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We&amp;rsquo;ve created a channel with a buffer of size &lt;code&gt;1&lt;/code&gt;.
Next, for each point on the canvas, we &lt;code&gt;spawn&lt;/code&gt; a thread, that will try to put a random color to the channel.
Our channel will refuse to take more than 1 color at a time, so these threads will park once it&amp;rsquo;s full.
The next thread reads one color from the channel and draws a rectangle with this color.&lt;/p&gt;
&lt;p&gt;Next, we need to draw all of this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.load&lt;/span&gt; []
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.window.setTitle&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Async&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.window.setMode&lt;/span&gt; 640 480 {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:resizable&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;false&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:vsync&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;false&lt;/span&gt;}))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.draw&lt;/span&gt; []
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.graphics.scale&lt;/span&gt; 8 8)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;worker&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;love.load&lt;/code&gt; simply sets the window parameters and &lt;code&gt;love.draw&lt;/code&gt; sets the scaling and calls our &lt;code&gt;worker&lt;/code&gt;, which handles our threads.
Compiling this code with &lt;code&gt;fennel -c main.fnl &amp;gt; main.lua&lt;/code&gt; and running &lt;code&gt;love .&lt;/code&gt; in this directory should result in something like this:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2021-10-27-naive-async-implementation-in-fennel/async.gif&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;The color for each square is set by a separate thread, and the squares are also drawn by separate threads.
As you can see &lt;a href=&#34;#code-snippet--love-threads&#34;&gt;here&lt;/a&gt;, each thread is a &lt;code&gt;while&lt;/code&gt; loop, that is being parked by calls to &lt;code&gt;put&lt;/code&gt; and &lt;code&gt;take&lt;/code&gt;, each time our channel &lt;code&gt;c&lt;/code&gt; is full.
Thus, we&amp;rsquo;ve almost fully abstracted coroutines away.&lt;/p&gt;
&lt;h2 id=&#34;further-up&#34;&gt;Further up&lt;/h2&gt;
&lt;p&gt;This was a very basic implementation that can be expanded upon if one wants to.
Obviously, it&amp;rsquo;s far from being complete, but even in the current state, you can write code with some sort of multitasking in mind.
One thing to improve is our implementation of the &lt;code&gt;worker&lt;/code&gt; function, which loops over all threads.
Right now it&amp;rsquo;s just an &lt;code&gt;each&lt;/code&gt; loop, but a proper scheduler might reorder tasks in a more efficient way, depending on how tasks perform.&lt;/p&gt;
&lt;p&gt;The key problem with this system is that your main application must be running inside this worker as well as one of the threads.
Because if you want to block on waiting for a promise, you can&amp;rsquo;t use a conventional while loop, as it will stop &lt;code&gt;worker&lt;/code&gt; from running, and your program will hang.
This is something that just needed to be kept in mind though, and I believe it is possible to write programs in such a way.&lt;/p&gt;
&lt;p&gt;Additionally to parking on channel or promise operations, a set of macros can be created to replace &lt;code&gt;while&lt;/code&gt;, &lt;code&gt;for&lt;/code&gt;, &lt;code&gt;each&lt;/code&gt;, and other blocking things with non-blocking variants.
Such macros will allow running loops in threads without blocking other threads:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;macro&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pwhile&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;condition&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  `(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;while&lt;/span&gt; ,&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;condition&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;font-weight:bold&#34;&gt;do &lt;/span&gt;,&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;coroutine.yield&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;macro&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pfor&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bindings&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  `(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;for &lt;/span&gt;,&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bindings&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;font-weight:bold&#34;&gt;do &lt;/span&gt;,&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;coroutine.yield&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;macro&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;peach&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bindings&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  `(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;each&lt;/span&gt; ,&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bindings&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;font-weight:bold&#34;&gt;do &lt;/span&gt;,&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;coroutine.yield&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Alternatively, a single macro, that wraps user code can be created, that will analyze code for iteration constructs, and &lt;em&gt;upgrade&lt;/em&gt; them to use &lt;code&gt;coroutine.yield&lt;/code&gt;.
This is somewhat similar to what Clojure&amp;rsquo;s &lt;code&gt;core.async&lt;/code&gt; does with its &lt;code&gt;go&lt;/code&gt; macro, which transforms the code.&lt;/p&gt;
&lt;p&gt;Overall, I think it is an interesting topic to explore, and I might create a library like this if there will be enough interest.&lt;/p&gt;
&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;
&lt;p&gt;Nothing is really set in stone, as this is a mutable object, and you can break this guarantee by mutating it.
This can be avoided by using proxy tables with special &lt;code&gt;__newindex&lt;/code&gt; metamethod, but I&amp;rsquo;ve left this out for the purpose of this article.&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: Naive async implementation in Fennel&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Wed, 27 Oct 2021 09:58:00 +0300</pubDate>
    </item><item>
      <title>Lazy sequences and iterators</title>
      <link>https://andreyor.st/posts/2021-10-09-lazy-sequences-and-iterators/</link>
      <guid>https://andreyor.st/posts/2021-10-09-lazy-sequences-and-iterators/</guid>
      <description>&lt;p&gt;Today’s topic will be about lazy sequences and how these are different from iterators.
I’ve wanted to make an article on this topic for some time, but unfortunately, there was no good way to show the differences using a single language (that I know), because usually, languages stick to one of those things.
But since I’ve been into library writing lately, I wrote a lazy sequence library for the Fennel language, and because Fennel compiles to Lua, it makes Lua a great candidate for this article.&lt;/p&gt;
&lt;p&gt;Lua has first-class support for iterators, as it is kind of a central paradigm very closely related to tables.
And because iterators are so common in Lua, &lt;a href=&#34;https://lunarmodules.github.io/Penlight/libraries/pl.seq.html&#34; target=&#34;_blank&#34;&gt;some libraries&lt;/a&gt; even treat them as sequences.
However, iterators are not sequences, even though they can be used similarly.
And proper sequences also can be created from tables much like iterators and would have similar use cases, without some problems that iterators have.
So today we’ll look into Lua iterators, and lazy sequences, and will try to understand their differences.&lt;/p&gt;
&lt;h2 id=&#34;iterators-in-lua&#34;&gt;Iterators in Lua&lt;/h2&gt;
&lt;p&gt;Let&amp;rsquo;s begin by understanding what iterators are, and what key features they provide.&lt;/p&gt;
&lt;p&gt;In Lua, iterators are usually higher-order functions, produced by another function, based on its input.
A standard way to get an iterator over a table is to call &lt;code&gt;pairs&lt;/code&gt; function:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;get_next, t, k = pairs({a = 1, b = 2, c = 3})
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Lua supports multiple return values, so calling pairs returns us the iterator function as the first value, a table (our original table in this case), that we&amp;rsquo;re going to iterate as the second value, and the starting key, which in our case is &lt;code&gt;nil&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Calling this &lt;code&gt;get_next&lt;/code&gt; function, and passing it our table &lt;code&gt;t&lt;/code&gt;, and the key &lt;code&gt;k&lt;/code&gt;, we get back a pair of values, representing the key and a value associated with that key:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;get_next(t, k) &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- b	2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We then can use the returned key as an input to the next call to &lt;code&gt;get_next&lt;/code&gt; and get the next key-value pair, repeating the process until &lt;code&gt;get_next&lt;/code&gt; returns &lt;code&gt;nil&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;get_next(t, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;b&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- c	3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;get_next(t, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;c&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- a	1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;get_next(t, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;a&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;nil&lt;/code&gt; means our table is exhausted, and no more keys are present in it.
The order may be different for you, as it depends on hashing.&lt;/p&gt;
&lt;p&gt;This &lt;code&gt;get_next&lt;/code&gt; is a &lt;em&gt;stateless iterator&lt;/em&gt; - it doesn&amp;rsquo;t have any hidden state inside it, which means, that it can be reused.
For example, we can pass a different table to the &lt;code&gt;get_next&lt;/code&gt; function, and it will work on it without any problem:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;get_next({f = 42, g = 27}, &lt;span style=&#34;font-weight:bold&#34;&gt;nil&lt;/span&gt;) &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- g	27&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This pattern is quite common, so Lua has such a function in its standard library, it is called &lt;code&gt;next&lt;/code&gt; and is a basis for all table iterators created with &lt;code&gt;pairs&lt;/code&gt;.
In addition to &lt;code&gt;pairs&lt;/code&gt;, Lua provides another iterator constructor called &lt;code&gt;ipairs&lt;/code&gt;, which is used to iterate over sequential tables, and it works similarly to &lt;code&gt;pairs&lt;/code&gt; except uses integers as input keys.&lt;/p&gt;
&lt;p&gt;While stateless iterators are good, it&amp;rsquo;s not always efficient, and sometimes not even possible to create a stateless iterator.
For example, opening a file in Lua and calling &lt;code&gt;lines&lt;/code&gt; method on it creates an iterator over this file, which is a stateful iterator that can be exhausted, i.e. you can call it only so many times as there are lines in the file.
Let&amp;rsquo;s create a file &lt;code&gt;example.txt&lt;/code&gt; with the following contents, and create an iterator over it:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;line 1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;line 2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;line 3
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;file = io.open(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;example.txt&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;r&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;get_next_line = file:lines()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;get_next_line() &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- line 1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;get_next_line() &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- line 2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;get_next_line() &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- line 3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;get_next_line() &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Note that even though we&amp;rsquo;re calling the &lt;code&gt;get_next_line&lt;/code&gt; function without any arguments, like the file, or the line number, it always returns the next line of the file.
This is an example of a stateful iterator, which we can only use once - even if we call the &lt;code&gt;lines&lt;/code&gt; method on the file object again, the returned iterator will be exhausted:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;new_get_next_line = file:lines()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;new_get_next_line() &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This happens because the state is held in the file handle itself, so we need to reopen the file to get a new iterator.
Because of this you usually want to open the file, walk it, use or cache needed lines, and close the resource, ideally doing all of this in a protected call.&lt;/p&gt;
&lt;p&gt;And lastly, let&amp;rsquo;s create our own stateful iterator, that keeps its state in the closure.
For the purposes of this example, let&amp;rsquo;s create a &lt;code&gt;range&lt;/code&gt; iterator, that can create various ranges based on initial input:&lt;/p&gt;
&lt;p&gt;&lt;a id=&#34;code-snippet--range-iterator&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;range&lt;/span&gt;(lower, upper, step)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; lower, upper, step = lower &lt;span style=&#34;font-weight:bold&#34;&gt;or&lt;/span&gt; 0, upper &lt;span style=&#34;font-weight:bold&#34;&gt;or&lt;/span&gt; math.huge, step &lt;span style=&#34;font-weight:bold&#34;&gt;or&lt;/span&gt; 1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; ()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; tmp = lower
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    lower = lower + step
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; tmp &amp;lt; upper &lt;span style=&#34;font-weight:bold&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; tmp
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To keep it simple I&amp;rsquo;ve left some corner cases out, but this is basically the idea for a range iterator.
When we call &lt;code&gt;range&lt;/code&gt;, local variables &lt;code&gt;lower&lt;/code&gt;, &lt;code&gt;upper&lt;/code&gt;, and &lt;code&gt;step&lt;/code&gt; are created based on given arguments or their default values.
Then an anonymous function is returned, which refers to these local variables as closures, and sets the &lt;code&gt;lower&lt;/code&gt; variable to a new value each time it is called:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;r = range(1, 4)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;r() &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- 1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;r() &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- 2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;r() &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- 3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;r() &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As you can see, when we exhaust our iterator it returns &lt;code&gt;nil&lt;/code&gt;, similarly to iterators created with &lt;code&gt;pairs&lt;/code&gt; or file iterators.
Thanks to this, we can use it in Lua&amp;rsquo;s &lt;code&gt;for&lt;/code&gt; statement:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;for&lt;/span&gt; x &lt;span style=&#34;font-weight:bold&#34;&gt;in&lt;/span&gt; range(1, 10, 3) &lt;span style=&#34;font-weight:bold&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  print(x)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- 1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- 4&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- 7&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So now, when we more or less know what iterators are, and how they&amp;rsquo;re defined, let&amp;rsquo;s discuss their key properties:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Iterators are lazy,&lt;/li&gt;
&lt;li&gt;Stateless iterators accept some kind of state (usually an object and a key) as arguments to produce the next key-value pair, and hence can be reused,&lt;/li&gt;
&lt;li&gt;Stateful iterators are like cursors, and can&amp;rsquo;t be reused unless created anew.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Laziness is a very good property of iterators - it allows us to create actual infinite streams of data, computed on demand.
For example, we can open really huge, or even infinite files, and read those line by line without consuming more memory than is actually needed to hold a single line.
Alternatively, as was shown with the &lt;code&gt;range&lt;/code&gt; iterator above, we can create an infinite range, by not supplying an upper border for it, and it will use the &lt;code&gt;math.huge&lt;/code&gt; value, which is &lt;code&gt;inf&lt;/code&gt; in Lua.
So if Lua had arbitrary precision math, the range would grow to infinity, but in the case of this function, it will just overflow again and again.&lt;/p&gt;
&lt;p&gt;However, while laziness is an extremely handy and important part of iterators, their benefits pretty much end on it.
Iterator is basically a one-shot thing - you create it, use it until it is exhausted, or you&amp;rsquo;ve accomplished what you wanted to do with them, and then you never use the same iterator again.
This is due to the fact, that iterators were not meant to be shared - you can&amp;rsquo;t tell if an iterator is stateless or stateful, and if it is a stateful iterator, there&amp;rsquo;s no safe way to share it.
Someone can exhaust it, and later users will not get any values.
Stateless iterators are less dangerous to share, but the usefulness of this is also significantly lower, as you need to pass the context along with an iterator.&lt;/p&gt;
&lt;p&gt;All of this can be summarized to one point - iterators are not a data structure.
And while this is not a bad thing, the usefulness of the iterator is limited because of this.
So what if we wanted to share an iterator, and also make sure, that it doesn&amp;rsquo;t have problems with stateful iterators, and can be used as a data structure?
That&amp;rsquo;s where lazy sequences come in handy!&lt;/p&gt;
&lt;h2 id=&#34;lazy-sequences&#34;&gt;Lazy Sequences&lt;/h2&gt;
&lt;p&gt;What are sequences?
Think of a lazy sequence as a &lt;a href=&#34;https://en.wikipedia.org/wiki/Linked_list#Singly_linked_list&#34; target=&#34;_blank&#34;&gt;singly-linked list&lt;/a&gt;, with the difference that the tail may not be an actual cell, but a special kind of lazily evaluated cell.
In order to create a sequence, we need to implement a so-called &lt;code&gt;cons&lt;/code&gt; cell:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cons&lt;/span&gt; (head, tail)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; (ht)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; ht &lt;span style=&#34;font-weight:bold&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; head
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; tail
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Conses are an old term that comes from the LISP language and basically represents a pair.
It&amp;rsquo;s a data structure that holds two elements - a value and a pointer to the next value or a cons cell.
This is usually illustrated with these boxes:&lt;/p&gt;
&lt;figure class=&#34;invertable&#34;&gt;&lt;img src=&#34;https://andreyor.st/2021-10-09-lazy-sequences-and-iterators/cons-list.svg&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;These stacked boxes represent a single cons cell - a pair of boxes, each referring to a value.
The first box refers to &lt;code&gt;1&lt;/code&gt;, and the second box refers to another cons cell, which in turn refers to &lt;code&gt;2&lt;/code&gt;, and finally to nothing, indicating the end of the list.
This data structure suits our task quite well, but you may notice that our implementation isn&amp;rsquo;t exactly a data structure, but a function.
So how do we work with it then?&lt;/p&gt;
&lt;p&gt;We need two primitive operations.
In LISP these are historically called &lt;code&gt;car&lt;/code&gt; and &lt;code&gt;cdr&lt;/code&gt;, but it&amp;rsquo;s not meaningful to use these names in the context of Lua, so let&amp;rsquo;s call them &lt;code&gt;first&lt;/code&gt; and &lt;code&gt;rest&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;first&lt;/span&gt; (cell)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; cell(&lt;span style=&#34;font-weight:bold&#34;&gt;true&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rest&lt;/span&gt; (cell)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; cell(&lt;span style=&#34;font-weight:bold&#34;&gt;false&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Since our cons cell is a function of one argument with &lt;code&gt;if&lt;/code&gt; statement in it, &lt;code&gt;first&lt;/code&gt; will pass &lt;code&gt;true&lt;/code&gt; to it, to get the first element, and &lt;code&gt;rest&lt;/code&gt; will pass &lt;code&gt;false&lt;/code&gt; to get the other element of a cons cell.
Here&amp;rsquo;s a quick demonstration:&lt;/p&gt;
&lt;p&gt;&lt;a id=&#34;code-snippet--non-lazy-list&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;list = cons(1, cons(2, cons(3, &lt;span style=&#34;font-weight:bold&#34;&gt;nil&lt;/span&gt;))) &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- 1 -&amp;gt; 2 -&amp;gt; 3 -&amp;gt; nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;first(list) &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- 1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;first(rest(rest(list))) &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- 3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We&amp;rsquo;ve created a &lt;code&gt;list&lt;/code&gt; variable, that holds a single-linked list with values &lt;code&gt;1&lt;/code&gt;, &lt;code&gt;2&lt;/code&gt;, &lt;code&gt;3&lt;/code&gt;.
And the final value is &lt;code&gt;nil&lt;/code&gt;, which is needed to indicate the end of the list since the last cons cell must refer to nothing.
However, this list is not lazy just yet.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s recap how iterators achieve laziness.
Iterators produce the next value only when you call them, which makes them very similar to generators by nature.
However, the key difference from lazy sequences is that all previous results are thrown away and not kept with the iterator.&lt;/p&gt;
&lt;p&gt;So how we can achieve laziness in our sequences?
We can try a naive approach of wrapping arguments into functions, and realizing them when a value is requested:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lazy_cons&lt;/span&gt; (headf, tailf)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; (ht)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; ht &lt;span style=&#34;font-weight:bold&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; headf()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; tailf()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now, when constructing a list, instead of passing the elements directly, we need to pass some functions that will return the list&amp;rsquo;s elements:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;lazy_list = lazy_cons(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; () print &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;realize head&amp;#34;&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; 1 &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; () print &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;realize tail&amp;#34;&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; 2 &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Because the interface is the same, we can use &lt;code&gt;first&lt;/code&gt; and &lt;code&gt;rest&lt;/code&gt; to get values:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;first(lazy_list)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- realize head&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- 1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;rest(lazy_list)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- realize tail&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- 2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You can see, that when we&amp;rsquo;re calling &lt;code&gt;first&lt;/code&gt; on our &lt;code&gt;lazy_list&lt;/code&gt; it realizes the value, and then returns it.
This is very close to our goal, but we&amp;rsquo;re not there yet.
The problem is, that if we call &lt;code&gt;first&lt;/code&gt; on &lt;code&gt;lazy_list&lt;/code&gt; again, it will call the realization function again and again without caching the result, which is not right:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;first(lazy_list)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- realize head&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- 1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;first(lazy_list)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- realize head&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- 1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To solve this issue, we&amp;rsquo;ll need to rewrite &lt;code&gt;lazy_cons&lt;/code&gt; in a such way, that it will realize our cell only once, and cache the result somehow.
This can be done by creating mutable closures, but I think there&amp;rsquo;s a better way, that will also allow us to do more interesting stuff later.
And it is also kinda hard to differentiate if the closure is uninitialized or the realization set it to &lt;code&gt;nil&lt;/code&gt;.
So instead we can use a clever metatable trick to realize cons cell contents upon access:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lazy_cons&lt;/span&gt; (headf, tailf)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; cell = {}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;realize&lt;/span&gt; ()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; head, tail = headf(), tailf()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;realized&lt;/span&gt; (_, ht)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; ht &lt;span style=&#34;font-weight:bold&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; head
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;font-weight:bold&#34;&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; tail
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; setmetatable(cell, {__call = realized})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; setmetatable(cell, {__call = &lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; (_, ht) &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; realize()(ht) &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Basically, we create a table &lt;code&gt;cell&lt;/code&gt;, to which we set a metamethod &lt;code&gt;__call&lt;/code&gt; that works similarly to the function that is returned by &lt;code&gt;cons&lt;/code&gt;, except not quite.
Note the &lt;code&gt;realize()(ht)&lt;/code&gt; call in this metamethod - it calls the &lt;code&gt;realize&lt;/code&gt; function first, then invokes the resulting function.
The &lt;code&gt;realize&lt;/code&gt; function is defined above, and this function resets the &lt;code&gt;__call&lt;/code&gt; metamethod to another function, that uses cached values.
Now using &lt;code&gt;first&lt;/code&gt; on a such cell will work as expected:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;lazy_list = lazy_cons(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; () print &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;realize head&amp;#34;&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; 1 &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; () print &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;realize tail&amp;#34;&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; 2 &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;first(lazy_list)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- realize head&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- realize tail&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- 1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;first(lazy_list)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- 1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;rest(lazy_list)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- 2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It realizes the cell and then caches the results in a closure, so when we call &lt;code&gt;first&lt;/code&gt; on this cell later, we get the same values every time.
Now we can create and manipulate lazy sequences with only these three basic functions!
Here&amp;rsquo;s our &lt;code&gt;list&lt;/code&gt; &lt;a href=&#34;#code-snippet--non-lazy-list&#34;&gt;example from above&lt;/a&gt;, but now lazy:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;lazy_list = lazy_cons(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; () print &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;first&amp;#34;&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; 1 &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; ()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; lazy_cons(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; () print &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;second&amp;#34;&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; 2 &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; ()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; lazy_cons (
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; () print &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;third&amp;#34;&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; 3 &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; () &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        )
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    )
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And we can inspect it with the same &lt;code&gt;first&lt;/code&gt; and &lt;code&gt;rest&lt;/code&gt; functions:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;first(lazy_list)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- first&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- 1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;first(rest(rest(lazy_list)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- second&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- third&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- 3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;first(lazy_list)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- 1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That&amp;rsquo;s pretty much it!
We have a way of constructing lazy sequences via a very primitive &lt;code&gt;lazy_cons&lt;/code&gt; function, and anonymous functions as arguments.
The usefulness of this may not be obvious, so let&amp;rsquo;s see some more examples of how this can be utilized before we move on.&lt;/p&gt;
&lt;h3 id=&#34;more-examples&#34;&gt;More examples&lt;/h3&gt;
&lt;p&gt;Let&amp;rsquo;s create a lazy sequence that works similarly to the &lt;code&gt;range&lt;/code&gt; &lt;a href=&#34;#code-snippet--range-iterator&#34;&gt;iterator we did earlier&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;range_seq&lt;/span&gt;(lower, upper, step)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; lower, upper, step = lower &lt;span style=&#34;font-weight:bold&#34;&gt;or&lt;/span&gt; 0, upper &lt;span style=&#34;font-weight:bold&#34;&gt;or&lt;/span&gt; math.huge, step &lt;span style=&#34;font-weight:bold&#34;&gt;or&lt;/span&gt; 1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; lazy_cons(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; () &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; lower &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; ()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; tmp = lower + step
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; tmp &amp;lt; upper &lt;span style=&#34;font-weight:bold&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; range_seq(tmp, upper, step)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;font-weight:bold&#34;&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; cons(&lt;span style=&#34;font-weight:bold&#34;&gt;nil&lt;/span&gt;, &lt;span style=&#34;font-weight:bold&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  )
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;A bit more verbose, but notice that this is no longer a stateful thing!
Instead, it is a recursive function, which returns a self-referencing cons cell, which calls itself with changed arguments.&lt;/p&gt;
&lt;p&gt;A recursion?
How&amp;rsquo;s it lazy then?&lt;/p&gt;
&lt;p&gt;The thing is, that it&amp;rsquo;s not even a recursion!
The next recursion step will only happen when a cell is realized, and it will simply produce another lazy cell, which will not go to the next recursion step immediately.
And even if Lua had no tail call optimization it would still work just fine, as it acts more like a trampoline, and the call stack never actually grows.
Here&amp;rsquo;s how we can see that our &lt;code&gt;range_seq&lt;/code&gt; is working:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;r = range_seq(1, 4)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;first(rest(rest(r)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- 3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;first(rest(rest(rest(r))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And for infinite ranges we can drop as many values before working with the range:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;r = range_seq()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;for&lt;/span&gt; i=1,1000000 &lt;span style=&#34;font-weight:bold&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- let&amp;#39;s drop some elements&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  r = rest(r)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;first(r) &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- 1000000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;first(rest(r)) &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- 1000001&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It&amp;rsquo;s a quite common pattern when working with infinite sequences to drop some values before working with them.
So if we want to create an infinite range, that starts from a given value,  we can write a &lt;code&gt;drop&lt;/code&gt; function, which will produce a new lazy sequence without first &lt;code&gt;n&lt;/code&gt; elements in it.&lt;/p&gt;
&lt;p&gt;Another thing to note is that it is a bit tedious to write nested &lt;code&gt;rest&lt;/code&gt; calls every time, so let&amp;rsquo;s iterate over this range instead, with the power of recursion:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;loop&lt;/span&gt; (seq, f)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; head, tail = first(seq), rest(seq)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  f(head)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; tail &lt;span style=&#34;font-weight:bold&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    loop(tail, f)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;loop(range_seq(0, 10, 2), print)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- 0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- 2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- 4&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- 6&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- 8&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This &lt;code&gt;loop&lt;/code&gt; function accepts a sequence and calls a supplied &lt;code&gt;f&lt;/code&gt; function on each element for side effects.
A very similar concept exists in most functional languages, and it is called mapping, so let&amp;rsquo;s create a lazy map function:&lt;/p&gt;
&lt;p&gt;&lt;a id=&#34;code-snippet--lazy-map&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;map&lt;/span&gt; (seq, f)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; first(seq) &lt;span style=&#34;font-weight:bold&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; lazy_cons(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; () &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; f(first(seq)) &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; () &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; map(rest(seq), f) &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    )
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold&#34;&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; cons(&lt;span style=&#34;font-weight:bold&#34;&gt;nil&lt;/span&gt;, &lt;span style=&#34;font-weight:bold&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now with this &lt;code&gt;map&lt;/code&gt; function, we can not only apply a function to every element of the sequence, but we can also collect the results into another sequence.
Let&amp;rsquo;s write a function that prints every element of the given sequence, and pass the result of the &lt;code&gt;map&lt;/code&gt; call to it:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;print_seq&lt;/span&gt; (seq)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  io.stdout:write(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;[&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;print_seq&lt;/span&gt; (seq)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; first(seq) &lt;span style=&#34;font-weight:bold&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      io.stdout:write(first(seq), &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;, &amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      print_seq(rest(seq))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  print_seq(seq)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  io.stdout:write(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;\b\b&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;]&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;\n&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;square&lt;/span&gt; (x) &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; x * x &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;print_seq(map(range_seq(0, 10), square))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now, to demonstrate that this is really a lazy &lt;code&gt;map&lt;/code&gt;, let&amp;rsquo;s add a &lt;code&gt;print&lt;/code&gt; call to &lt;code&gt;square&lt;/code&gt;, and store the resulting sequence to a variable:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;square&lt;/span&gt; (x)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  print(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;square of &amp;#34;&lt;/span&gt;..x..&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; is &amp;#34;&lt;/span&gt;..x * x)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; x * x
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;squares = map(range_seq(0, 10), square)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Nothing is printed until we realize some elements of our sequence:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;first(squares)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- prints: square of 0 is 0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;first(rest(rest(squares)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- prints: square of 2 is 4&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;first(rest(rest(squares)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- prints nothing, as the result was already realized&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Note that while this is still just a (kinda special) function, it behaves just like a real linked list, and thus represents a proper data structure.
Although it&amp;rsquo;s &lt;em&gt;a bit&lt;/em&gt; clumsy to use directly, as shown with the &lt;code&gt;map&lt;/code&gt; example, we can build a library around this concept, that will abstract the construction of a lazy sequence away from the user.
And that&amp;rsquo;s exactly what I did.&lt;/p&gt;
&lt;h2 id=&#34;lazy-seq-library&#34;&gt;Lazy-seq library&lt;/h2&gt;
&lt;p&gt;It should be pointed out that the code above is a very rough example of a lazy sequence implementation.
I think it&amp;rsquo;s fine for explaining the idea, but there are some edge cases that are not handled properly.
For example, the &lt;a href=&#34;#code-snippet--lazy-map&#34;&gt;&lt;code&gt;map&lt;/code&gt; function we&amp;rsquo;ve written is not fully lazy&lt;/a&gt;, as it actually realizes its first element, and the &lt;code&gt;range_seq&lt;/code&gt; will not properly work for negative ranges.
And the &lt;code&gt;lazy_cons&lt;/code&gt; is not really the most useful abstraction - instead of using it directly, a much more handy &lt;code&gt;lazy_seq&lt;/code&gt; function should be created, that would accept another function, which in turn would return any kind of sequence.
To address these shortcomings I&amp;rsquo;ve created a &lt;a href=&#34;https://gitlab.com/andreyorst/lazy-seq&#34; target=&#34;_blank&#34;&gt;lazy-seq&lt;/a&gt; library, which has a lot of functions to create and manipulate lazy sequences.&lt;/p&gt;
&lt;p&gt;Now, it&amp;rsquo;s a &lt;a href=&#34;https://fennel-lang.org/&#34; target=&#34;_blank&#34;&gt;Fennel&lt;/a&gt; library, written in Fennel, and aimed toward it first.
That is, mainly due to the fact that this library mimics Clojure&amp;rsquo;s vision of lazy sequences and ports a lot of functions from its core namespace.
But the core principles are exactly the same as described above, and you still can use the library from Lua, just like we did earlier!&lt;/p&gt;
&lt;p&gt;Except the semantics are expanded a bit - there are handy constructors for creating lazy sequences from tables or strings, supporting both sequential and associative tables.
And, as you may remember from the previous section since our cons cells are secretly tables underneath, sequences defined by this library also implement various metamethods, like &lt;code&gt;__len&lt;/code&gt;, &lt;code&gt;__index&lt;/code&gt;, and so on, for more convenient usage.&lt;/p&gt;
&lt;p&gt;Proper versions of &lt;code&gt;map&lt;/code&gt; and &lt;code&gt;range&lt;/code&gt; already exist in this library, along with other functions, which can be used as building blocks for creating all kinds of sequences.
For example, here&amp;rsquo;s how one would create an infinite Fibonacci sequence using the lazy variant of the &lt;code&gt;map&lt;/code&gt; function in Lua:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;lazy = require &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;lazy-seq&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;first, rest, map = lazy.first, lazy.rest, lazy.map
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;concat, drop, lazy_seq = lazy.concat, lazy.drop, lazy[&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;lazy-seq&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;bc = require &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;bc&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;add&lt;/span&gt; (a, b) &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; a + b &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;fib = concat(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  {bc.new(0), bc.new(1)},
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  lazy_seq(&lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; () &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; map(add, rest(fib), fib) &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;first(drop(400, fib))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- 176023680645013966468226945392411250770384383304492191886725992896575345044216019675&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In the example above I&amp;rsquo;m also using the &lt;a href=&#34;https://web.tecgraf.puc-rio.br/~lhf/ftp/lua/#lbc&#34; target=&#34;_blank&#34;&gt;&lt;code&gt;lbc&lt;/code&gt; library&lt;/a&gt; which provides arbitrary precision math for Lua to illustrate that you can compute as many Fibonacci numbers as you want (try dropping the first 100000 elements for example)
That&amp;rsquo;s a bit verbose still, but not as verbose as the manually created lazy linked list from previous sections.
And note that the &lt;code&gt;concat&lt;/code&gt; function, which is used to concatenate sequences, also works with tables, as shown in the example above.
All sequence manipulating functions in the &lt;code&gt;lazy-seq&lt;/code&gt; library work with tables, as tables are implicitly converted to sequences.&lt;/p&gt;
&lt;p&gt;In Fennel, the same code is even more compact because we can use the &lt;code&gt;lazy-cat&lt;/code&gt; macro instead of using &lt;code&gt;concat&lt;/code&gt; and &lt;code&gt;lazy-seq&lt;/code&gt;, and thanks to anonymous function shorthand:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; {&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;first &lt;/span&gt;&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;rest &lt;/span&gt;&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;map &lt;/span&gt;&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;drop&lt;/span&gt;} (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;require&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;lazy-seq&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;import-macros&lt;/span&gt; {&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lazy-cat&lt;/span&gt;} &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;lazy-seq&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bc&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;require&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;bc&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;global&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fib&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;lazy-cat &lt;/span&gt;[(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bc.new&lt;/span&gt; 0) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bc.new&lt;/span&gt; 1)] (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;map &lt;/span&gt;#(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;$1&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;$2&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;rest &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fib&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fib&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;first &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;drop &lt;/span&gt;400 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fib&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; 176023680645013966468226945392411250770384383304492191886725992896575345044216019675&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Note however that macros are a Fennel-only feature, not available in Lua, so where in Fennel you would write:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;import-macros&lt;/span&gt; {&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;lazy-cat &lt;/span&gt;&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lazy-seq&lt;/span&gt;} &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;lazy-seq&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;lazy-cat &lt;/span&gt;[1 2 3] [4 5 6])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lazy-seq&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;do &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;print &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;I&amp;#39;m lazy&amp;#34;&lt;/span&gt;) [1 2 3]))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In Lua it would be:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;lazy = require &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;lazy-seq&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;concat, lazy_seq = lazy.concat, lazy[&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;lazy-seq&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;concat(lazy_seq(&lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; () &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; {1, 2, 3} &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;), lazy_seq(&lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; () &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; {4, 5, 6} &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;lazy_seq(&lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; () print &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;I&amp;#39;m lazy&amp;#34;&lt;/span&gt; {1, 2, 3} &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This code is fully equivalent to fennel code, except that macros write all these anonymous functions for you.&lt;/p&gt;
&lt;p&gt;But macros are not the only unique feature in Fennel, the other one is destructuring.
I&amp;rsquo;ll not go into details here, but destructuring is kinda similar to pattern matching, and it allows specifying data structure shape and binding values of the data structure to variables defined by that shape.
So similarly to how you would destructure a table, thanks to &lt;code&gt;__len&lt;/code&gt; and &lt;code&gt;__index&lt;/code&gt; metamethods, destructuring works on lazy sequences:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; {&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;range&lt;/span&gt;} (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;require&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;lazy-seq&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt; &amp;amp; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rest&lt;/span&gt;] (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;range &lt;/span&gt;10)] (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;print &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rest&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; 0 1 2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; [3 4 5 6 7 8 9]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Just make sure you don&amp;rsquo;t use &lt;code&gt;&amp;amp;&lt;/code&gt; destructuring with infinite sequences&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;.
And more than that, sequences define the &lt;code&gt;__pairs&lt;/code&gt; metamethod, and thus support creating stateless iterators created with &lt;code&gt;pairs&lt;/code&gt;!&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;fennel = require &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;fennel&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- for pretty printer&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;lazy = require &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;lazy-seq&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;squares = lazy.map(&lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; (x) &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; x * x &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;, {1, 2, 3, 4, 5})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;for&lt;/span&gt; k,v &lt;span style=&#34;font-weight:bold&#34;&gt;in&lt;/span&gt; pairs(squares) &lt;span style=&#34;font-weight:bold&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  print(fennel.view(k), v)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- @seq(4 9 16 25) 1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- @seq(9 16 25)   4&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- @seq(16 25)     9&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- @seq(25)        16&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- @seq()          25&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We&amp;rsquo;ve come a full circle.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve required the &lt;code&gt;fennel&lt;/code&gt; library, to provide the pretty-printed representation of a sequence for a better illustration.
You can see that on each step of iteration we see the shorter and shorter sequence.
Sequence automatically pretty-printed in the REPL like this, but that&amp;rsquo;s one of Fennel&amp;rsquo;s features, that I&amp;rsquo;ve &lt;a href=&#34;https://andreyor.st/posts/2021-01-09-pretty-printing-for-fennel-language/&#34;&gt;previously written about&lt;/a&gt;, and implemented a very similar linked list there, so if you&amp;rsquo;re interested in that, you can find some more info there.
And viewing such a sequence in this way really shows us that it is nothing else but a data structure!&lt;/p&gt;
&lt;p&gt;Unlike tables, a stateless iterator over a sequence uses the tail of the sequence as the key to getting the next element, because the iterator is simply built on top of &lt;code&gt;first&lt;/code&gt; and &lt;code&gt;rest&lt;/code&gt;.
It ends when it reaches the empty cons cell, which is at the end of each sequence.
The only exceptions are infinite sequences, which don&amp;rsquo;t have empty cons at the end as, well, they&amp;rsquo;re infinite.
So calling &lt;code&gt;pairs&lt;/code&gt; and iterating over infinite sequences should have another guard for terminating iteration.
Or, you can limit the size of the sequence with &lt;code&gt;take&lt;/code&gt;, &lt;code&gt;take-while&lt;/code&gt;, and other filtering functions.&lt;/p&gt;
&lt;p&gt;There are also various functions like &lt;code&gt;line-seq&lt;/code&gt; which accepts a file handle, so here&amp;rsquo;s what happens when we call it on a file:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; {&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;line-seq &lt;/span&gt;&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;doall&lt;/span&gt;} (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;require&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;lazy-seq&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;with-open &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;io.open&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;example.txt&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:r&lt;/span&gt;)] (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;doall &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;line-seq &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; @seq(&amp;#34;line 1&amp;#34; &amp;#34;line 2&amp;#34; &amp;#34;line 3&amp;#34;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We have to realize the whole sequence before &lt;code&gt;with-open&lt;/code&gt; automatically closes the file handle, but you can lazily work with this sequence while you&amp;rsquo;re inside of the &lt;code&gt;with-open&lt;/code&gt; block without any issues.
In contrary to the iterator, we can re-use this sequence of lines, as no results have been thrown away.&lt;/p&gt;
&lt;p&gt;Finally, as I&amp;rsquo;ve mentioned, lazy sequences can be generated from tables with the &lt;code&gt;seq&lt;/code&gt; function:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; {&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;seq&lt;/span&gt;} (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;require&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;lazy-seq&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;seq &lt;/span&gt;[1 2 3])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; @seq(1 2 3)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;seq &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;abc&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; @seq(&amp;#34;a&amp;#34; &amp;#34;b&amp;#34; &amp;#34;c&amp;#34;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If we pass in an associative table we get a bit different representation:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;seq &lt;/span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:a&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:b&lt;/span&gt; 2 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:c&lt;/span&gt; 3})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; @seq([&amp;#34;a&amp;#34; 1] [&amp;#34;c&amp;#34; 3] [&amp;#34;b&amp;#34; 2])&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;These sequences are all lazy because &lt;code&gt;seq&lt;/code&gt; creates a wrapper around an iterator over the table.
This means, that if you change the table before the sequence is fully realized, your resulting sequence will have updated elements much like an iterator would produce them.
This is not recommended, and instead &lt;a href=&#34;https://gitlab.com/andreyorst/itable&#34; target=&#34;_blank&#34;&gt;immutable tables&lt;/a&gt; a better be used to produce sequences, and in general.
And since sequences themselves are immutable and persistent this is a win-win.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;lazy-seq&lt;/code&gt; library also provides a lot of other functions, like filtering, restructuring, modifying, and combining infinite sequences.
It&amp;rsquo;ll take a lot of time to list all of them here, so I&amp;rsquo;d recommend you to read the documentation if you&amp;rsquo;re interested.
But as an example of what you can do, here we create an infinite sequence of random numbers, filter out only those which are perfect squares, and group those by 2:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; {&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;take &lt;/span&gt;&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;filter &lt;/span&gt;&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;repeatedly&lt;/span&gt; &lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;partition&lt;/span&gt;} (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;require&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;lazy-seq&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rands&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;repeatedly&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;math.random&lt;/span&gt; 0 64))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;perfect-squares&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;filter &lt;/span&gt;#(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;= &lt;/span&gt;0 (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;%&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;math.sqrt&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;$&lt;/span&gt;) 2)) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rands&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rand-square-pairs&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;partition&lt;/span&gt; 2 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;perfect-squares&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;take &lt;/span&gt;10 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rand-square-pairs&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; @seq(@seq(64 16)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;;      @seq(4 0)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;;      @seq(64 4)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;;      @seq(4 0)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;;      @seq(0 4)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;;      @seq(4 64)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;;      @seq(16 0)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;;      @seq(0 64)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;;      @seq(16 4)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;;      @seq(16 36))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Note that we did all operations on an infinite sequence, and then only used &lt;code&gt;take&lt;/code&gt; to get the first 10 elements of it.
This is a common pattern when working with infinite sequences - create something infinite, filter or modify it, and take the needed amount of elements.&lt;/p&gt;
&lt;h2 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;That&amp;rsquo;s all I wanted to say about lazy sequences and their relationship with iterators.
But of course, there&amp;rsquo;s much more to it, as there are a lot more functions for sequence manipulation I&amp;rsquo;ve left uncovered because it would simply be too long for an article.
The main point I&amp;rsquo;ve wanted to share is that sequences are similar to iterators, but don&amp;rsquo;t have some downsides that iterators have.
Someone can argue that these downsides are features, but I think sequences still have their uses.&lt;/p&gt;
&lt;p&gt;So let&amp;rsquo;s recap what we have learned about sequences:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Sequences are a data structure, with very important properties of persistence and immutability.&lt;/li&gt;
&lt;li&gt;Sequences are lazy, much like iterators, but they cache their values for later re-use.&lt;/li&gt;
&lt;li&gt;Things that required stateful iterators, can be done with stateless sequences by using laziness and recursion.&lt;/li&gt;
&lt;li&gt;Sequences, implemented by &lt;code&gt;lazy-seq&lt;/code&gt; library, support common table operations, making it easy to integrate lazy computation into existing Lua code.&lt;/li&gt;
&lt;li&gt;Operations on infinite sequences can be easily composed.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I hope you got a good understanding of lazy sequences, and I got you interested in at least trying them out!
Despite being a Fennel library, &lt;a href=&#34;https://gitlab.com/andreyorst/lazy-seq&#34; target=&#34;_blank&#34;&gt;lazy-seq&lt;/a&gt; can be used from Lua just fine, you only need to compile it to Lua first, which is not hard to do, given that Fennel itself is also just a library.
But I suggest using this library with Fennel, as it adds a bit more facilities, like pretty-printing of your data structures, and provides macros for a more concise code.&lt;/p&gt;
&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;
&lt;p&gt;: As of &lt;a href=&#34;https://git.sr.ht/~technomancy/fennel/tree/HEAD/changelog.md#100--2021-11-14&#34; target=&#34;_blank&#34;&gt;Fennel v1.0.0&lt;/a&gt; the &lt;code&gt;__fennelrest&lt;/code&gt; metamethod was added, and &lt;code&gt;&amp;amp;&lt;/code&gt; destructuring works on infinite sequences.&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: Lazy sequences and iterators&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Sat, 09 Oct 2021 21:34:00 +0300</pubDate>
    </item><item>
      <title>Condition system for Fennel language and Lua runtime</title>
      <link>https://andreyor.st/posts/2021-08-08-condition-system-for-fennel-language-and-lua-runtime/</link>
      <guid>https://andreyor.st/posts/2021-08-08-condition-system-for-fennel-language-and-lua-runtime/</guid>
      <description>&lt;p&gt;Not long ago I posted a small article on a &lt;a href=&#34;https://andreyor.st/posts/2021-04-17-condition-system-in-clojure/&#34;&gt;Condition System in Clojure language&lt;/a&gt;.
In that article, I was mostly trying to understand what a condition system is, and how it can enhance error handling in the code I write.
Since that time, I’ve understood this system a lot better, by actually trying it in the Common Lisp language, the place where it came from, as far as I know.
And you know what it means (because you’ve read the title) - it’s time to implement such a system for Fennel!&lt;/p&gt;
&lt;p&gt;I like Fennel a lot, it’s a really cool language to tinker with - it’s small, slick, Lua runtime is actually really versatile, and can be bent to your needs without a lot of extra work.
But the reason I’ve decided to implement this library for Fennel, and not for Lua itself, is because of a feature that is not available in Lua but is available in Fennel - lisp macros.
The library is already available for everyone to use: &lt;a href=&#34;https://gitlab.com/andreyorst/fennel-conditions&#34; target=&#34;_blank&#34;&gt;fennel-conditions&lt;/a&gt;, and in this article, I’ll do a deep dive into the details behind the implementation.&lt;/p&gt;
&lt;h2 id=&#34;condition-system&#34;&gt;Condition system?&lt;/h2&gt;
&lt;p&gt;First, let&amp;rsquo;s actually explain what the condition system is.&lt;/p&gt;
&lt;p&gt;Condition system is a feature of the Common Lisp language, that can be very roughly described as resumable exceptions.
Though, while this isn&amp;rsquo;t the only way you can use the condition system, it is the main reason I&amp;rsquo;ve decided to port this system into Fennel, as Lua error handling is not the best, and we can do better.
You still can use a condition system for basic control flow to some extent, though not as versatile as in Common Lisp, I don&amp;rsquo;t think that Fennel really needs these features.&lt;/p&gt;
&lt;p&gt;In Common Lisp, a condition is an object, which represents a &lt;em&gt;certain event&lt;/em&gt;.
You can bind handlers for particular events, and trigger these handlers by &lt;em&gt;raising&lt;/em&gt; a condition.
This may sound similar to the classic exception model found in languages like Java, but it has one major difference.
Exceptions are a two-part system, while the condition system is three-part.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s really hard to come up with a small example to show what condition the system has to offer that exceptions don&amp;rsquo;t, and I don&amp;rsquo;t really know Common Lisp well enough to write it.
So I encourage you to read &lt;a href=&#34;https://gigamonkeys.com/book/beyond-exception-handling-conditions-and-restarts.html&#34; target=&#34;_blank&#34;&gt;Chapter 19 from the Practical Common Lisp book&lt;/a&gt; which covers this topic in detail before continuing reading.
There&amp;rsquo;s also a good article on the &lt;a href=&#34;http://wiki.c2.com/?CommonLispConditionSystem&#34; target=&#34;_blank&#34;&gt;wiki.c2.com&lt;/a&gt;.
If you&amp;rsquo;ve read that before or just now, and didn&amp;rsquo;t understand what the condition system is, hopefully, you&amp;rsquo;ll get the idea in this post, but I can&amp;rsquo;t guarantee that.&lt;/p&gt;
&lt;p&gt;If I were to describe the main difference between this system from classic exceptions, I would say that when you write a code that throws an exception, you have to deal with this exception &lt;em&gt;somewhere else&lt;/em&gt;.
And the place where you handle that exception is the place where the program would continue running after the handling is done.&lt;/p&gt;
&lt;p&gt;In the condition system, the place where you&amp;rsquo;ve thrown such an exception can be the place where the program continues running if you use some special constructs, that allow you to return to that place.&lt;/p&gt;
&lt;h3 id=&#34;an-example&#34;&gt;An example&lt;/h3&gt;
&lt;p&gt;In the spirit of the Practical Common Lisp book example mentioned above, here&amp;rsquo;s a rather naive Clojure code that parses a log file, and uses exceptions to indicate that parsing failed:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;ns &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;log-parser&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:require&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure.java.io&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:as&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;io&lt;/span&gt;])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:import&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure.lang&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ExceptionInfo&lt;/span&gt;]))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;well-formed?&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Checks if the line contains basic date-time, a service name, and a message
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;separated by colons.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;date-re&lt;/span&gt; #&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;([12]\d\d\d-[01]\d-[0-3]\d)&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;time-re&lt;/span&gt; #&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;([01]\d:[0-5]\d:[0-5]\d\.\d+)&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;service-re&lt;/span&gt; #&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;([^:]+)&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message-re&lt;/span&gt; #&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;(.*)&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;re-matches &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;re-pattern &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;str &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;date-re&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;T&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;time-re&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;:&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;service-re&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;:&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message-re&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parse-line&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Extract `date`, `time`, `service` name, and a `message` from a `line`.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;if-let &lt;/span&gt;[[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;date&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;time &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;service&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt;] (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;well-formed?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:date&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;date&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:time&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;time&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:service&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;service&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:message&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;throw&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ex-info&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;malformed log entry&amp;#34;&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:line&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt;}))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parse&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Return a vector of parsed lines, each element being a map with the
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;  following keys: `:date`, `:time`, `:service`, `:message`.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lines&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;try&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mapv&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parse-line&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lines&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;catch&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ExceptionInfo&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;e&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;binding &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;*out*&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;*err*&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;prn &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;format&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;%s:%s&amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ex-message&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;e&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:line&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ex-data&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;e&lt;/span&gt;))))))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parse-log&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;file&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;with-open &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;io/reader&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;file&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;parse &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;line-seq &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: Yes, there are more idiomatic ways of doing this task in Clojure, but for the purposes of demonstrating the difference between exceptions and conditions this will do.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So this code checks if the line has a valid format, and if not it will throw an exception.
And here&amp;rsquo;s a problem - if a single line is invalid, we will get no results at all.
We can avoid that by moving &lt;code&gt;try&lt;/code&gt; into our iteration:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parse&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Return a vector of parsed lines, each element being a map with the
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;  following keys: `:date`, `:time`, `:service`, `:message`.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lines&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mapv&lt;/span&gt; #(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;try&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parse-line&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;%&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;catch&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ExceptionInfo&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;e&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;binding &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;*out*&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;*err*&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;prn &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;format&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;%s: %s&amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ex-message&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;e&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:line&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ex-data&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;e&lt;/span&gt;)))))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lines&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This will correctly parse our log, but we will have &lt;code&gt;nil&lt;/code&gt; in place of each malformed line.
This can once again be fixed by using &lt;code&gt;keep&lt;/code&gt; instead of &lt;code&gt;mapv&lt;/code&gt;, but what if we can&amp;rsquo;t afford to lose any lines?
Maybe we can fix the line and parse it one more time?
This again can be done by modifying our anonymous function, so it would catch the exception, try to fix the line, and then call &lt;code&gt;parse-line&lt;/code&gt; again.
And if we can&amp;rsquo;t fix the line, we will log it as before, and don&amp;rsquo;t add it to the resulting vector:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fix-line&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;We don&amp;#39;t care when this happened, just want to know what happened.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;when-let &lt;/span&gt;[[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;service&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt;] (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;re-matches &lt;/span&gt;#&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;.*:([^:]+):([^:]+)$&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;str &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;1970-01-01T00:00:00.000:&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;service&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;:&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parse&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Return a vector of parsed lines, each element being a map with the
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;  following keys: `:date`, `:time`, `:service`, `:message`.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lines&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;into &lt;/span&gt;[]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;keep&lt;/span&gt; #(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;try&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parse-line&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;%&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;catch&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ExceptionInfo&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;e&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;if-let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fixed-line&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fix-line&lt;/span&gt; (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:line&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ex-data&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;e&lt;/span&gt;)))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parse-line&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fixed-line&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                     (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;binding &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;*out*&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;*err*&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                       (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;prn &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;format&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;%s: %s&amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ex-message&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;e&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:line&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ex-data&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;e&lt;/span&gt;)))))))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lines&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;But then again, when we will use &lt;code&gt;parse-line&lt;/code&gt; in some other part of the program we will need to do all this stuff over and over.
The main problem here is that we&amp;rsquo;re building concrete ways to recover from error as a part of the calling function that is meaningful only in the context of the &lt;code&gt;parse-line&lt;/code&gt; and the responsibility for recovering should really be on it.
Condition system can help us write more generic code, that knows how it can recover from the error, but let the recovery happen on the calling side.
Consider the following Fennel code that uses &lt;a href=&#34;https://gitlab.com/andreyorst/fennel-conditions&#34; target=&#34;_blank&#34;&gt;fennel-conditions&lt;/a&gt; library:&lt;/p&gt;
&lt;p&gt;&lt;a id=&#34;code-snippet--fennel-example&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; {&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;error&lt;/span&gt; &lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;make-condition&lt;/span&gt; &lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;invoke-restart&lt;/span&gt;} (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;require&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:fennel-conditions&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;import-macros&lt;/span&gt; {&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;handler-bind&lt;/span&gt; &lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;restart-case&lt;/span&gt; &lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;define-condition&lt;/span&gt;} &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:fennel-conditions&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;define-condition&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;MalformedLogEntry&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;well-formed?&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Checks if the line starts with basic date-time followed by a colon and a word.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;date-pat&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;([12]%d%d%d%-[01]%d%-[0-3]%d)&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;time-pat&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;([01]%d:[0-5]%d:[0-5]%d%.%d%d%d)&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;service-pat&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;([^:]+)&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message-pat&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;(.*)&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;string.match&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;date-pat&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;T&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;time-pat&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;:&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;service-pat&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;:&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message-pat&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parse-line&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Extract `date`, `time`, `service` name, and a `message` from a `line`.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;restart-case&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;match&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;well-formed?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;date&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;time &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;service&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt;) {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:date&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;date&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                     &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:time&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;time&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                     &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:service&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;service&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                     &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:message&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;do &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;print &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;error&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;make-condition&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;MalformedLogEntry&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:line&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt;}))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:use-value&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;] &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:reparse-line&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fixed-line&lt;/span&gt;] (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parse-line&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fixed-line&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:ignore&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ignore-val&lt;/span&gt;] &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ignore-val&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fix-line&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;We don&amp;#39;t care when this happens, just want to know what happened.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;match&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;string.match&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;:([^:]+):([^:]+)$&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;service&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;1970-01-01T00:00:00.000:&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;service&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;:&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;parse &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lines&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Return a vector of parsed lines, each element being a map with the
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;following keys: `:date`, `:time`, `:service`, `:message`.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;handler-bind&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;MalformedLogEntry&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;e&lt;/span&gt; {&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt;}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;match&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fix-line&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                     &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fixed-line&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;invoke-restart&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:reparse-line&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fixed-line&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;MalformedLogEntry&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;e&lt;/span&gt; {&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt;}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;io.stderr&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:write&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;malformed log entry: &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\n&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;invoke-restart&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:ignore&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;icollect&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ipairs&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lines&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parse-line&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parse-log&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;file&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;with-open &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;io.open&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;file&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:r&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;when &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;parse &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;icollect&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:lines&lt;/span&gt;)] &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;For those unfamiliar with condition system special forms or Fennel itself, &lt;code&gt;handler-bind&lt;/code&gt; is something similar to &lt;code&gt;try&lt;/code&gt; with the difference that the only way to recover from the error is by calling &lt;code&gt;invoke-restart&lt;/code&gt; &lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;.
&lt;code&gt;with-open&lt;/code&gt; is the same thing as in Clojure or Common Lisp, and &lt;code&gt;icollect&lt;/code&gt; is something similar to &lt;code&gt;mapv&lt;/code&gt; in Clojure, but it&amp;rsquo;s a macro, that accepts body form instead of function.&lt;/p&gt;
&lt;p&gt;So what&amp;rsquo;s different about this code from the code in Clojure&amp;rsquo;s example?
Let&amp;rsquo;s look at &lt;code&gt;parse-line&lt;/code&gt; functions in Clojure and in Fennel:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; Clojure&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parse-line&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Extract `date`, `time`, `service` name, and a `message` from a `line`.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;if-let &lt;/span&gt;[[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;date&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;time &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;service&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt;] (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;well-formed?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:date&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;date&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:time&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;time&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:service&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;service&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:message&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;throw&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ex-info&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;malformed log entry&amp;#34;&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:line&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt;}))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; Fennel&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parse-line&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Extract `date`, `time`, `service` name, and a `message` from a `line`.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;restart-case&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;match&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;well-formed?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;date&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;time &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;service&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt;) {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:date&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;date&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                     &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:time&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;time&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                     &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:service&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;service&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                     &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:message&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;error&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;make-condition&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;MalformedLogEntry&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:line&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt;})))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:use-value&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;] &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:reparse-line&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fixed-line&lt;/span&gt;] (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parse-line&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fixed-line&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:ignore&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ignore-val&lt;/span&gt;] &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ignore-val&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Apart from some syntactic differences, you can see that both functions are throwing an error - by using &lt;code&gt;throw&lt;/code&gt; in Clojure, and &lt;code&gt;error&lt;/code&gt; in Fennel.
However, while the Clojure version only throws the error, the Fennel version does some additional things.
What we&amp;rsquo;re interested in here is the &lt;code&gt;restart-case&lt;/code&gt; macro, which is a special macro from the condition system, that allows us to return to its location when we want to handle the error.&lt;/p&gt;
&lt;p&gt;So when &lt;code&gt;parse-line&lt;/code&gt; throws an error in Clojure, JWM unwinds the stack, and we basically leave this function completely.
We then catch the exception in the &lt;code&gt;parse-log&lt;/code&gt; function, which can&amp;rsquo;t do anything about it but handle it right there or let it fall through.&lt;/p&gt;
&lt;p&gt;However, when &lt;code&gt;parse-line&lt;/code&gt; throws an error in Fennel, we don&amp;rsquo;t actually unwind the stack at all.
Instead, we travel up the dynamic scope, in search of a handler bound to this error by the &lt;code&gt;handler-bind&lt;/code&gt; macro in the &lt;code&gt;parse&lt;/code&gt; function:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; ---- 8&amp;lt; ----&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;handler-bind&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;MalformedLogEntry&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;e&lt;/span&gt; {&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt;}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;match&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fix-line&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fixed-line&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;invoke-restart&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:reparse-line&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fixed-line&lt;/span&gt;)))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; ---- 8&amp;lt; ----&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  )
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This handler tries to fix the line, and calls &lt;code&gt;(invoke-restart :reparse-line fixed-line)&lt;/code&gt;.
&lt;code&gt;invoke-restart&lt;/code&gt; is another special function in condition system - it once again travels through the second dynamic scope, and finds that there&amp;rsquo;s a restart named &lt;code&gt;:reparse-line&lt;/code&gt; bound by &lt;code&gt;restart-case&lt;/code&gt; in the &lt;code&gt;parse-line&lt;/code&gt; function.
This restart is executed right there, despite the fact that we&amp;rsquo;ve &amp;ldquo;left&amp;rdquo; the lexical scope of that function to find a handler, and its value is used in the original &lt;code&gt;parse-line&lt;/code&gt; call.&lt;/p&gt;
&lt;p&gt;So the order in which all functions are called looks something like that:&lt;/p&gt;
&lt;figure class=&#34;invertable&#34;&gt;&lt;img src=&#34;https://andreyor.st/2021-08-08-condition-system-for-fennel-language-and-lua-runtime/calls.svg&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;In other words, when we wrote &lt;code&gt;parse-line&lt;/code&gt; in Clojure, we only defined how to detect malformed lines and how to signal an error.
When we wrote &lt;code&gt;parse-line&lt;/code&gt; in Fennel, we not only specified what to do if the line is malformed but also provided concrete ways to recover, that are meaningful in the context of this function.&lt;/p&gt;
&lt;p&gt;When we caught the exception in Clojure, we had no choice but to handle it right there.
In Fennel, when we caught the exception we could decide whether we can handle the error, and how we can handle it without &lt;em&gt;leaving&lt;/em&gt; the original call.&lt;/p&gt;
&lt;p&gt;I hope this illustration is clear enough to demonstrate the main difference between exception and condition.
Again, yes, there are better ways of dealing with this particular error in Clojure, but what I wanted to illustrate is that there&amp;rsquo;s no way of achieving the same flexibility of the condition system with just exceptions.
I&amp;rsquo;ve covered possible ways of implementing a rather basic condition system in pure Clojure in my previous post &lt;a href=&#34;https://andreyor.st/posts/2021-04-17-condition-system-in-clojure/&#34;&gt;Condition System in Clojure language&lt;/a&gt;, so it&amp;rsquo;s not entirely impossible, but has its own shortcomings.
With that in mind let&amp;rsquo;s talk about the implementation of this system.&lt;/p&gt;
&lt;h2 id=&#34;the-implementation&#34;&gt;The implementation&lt;/h2&gt;
&lt;p&gt;As I&amp;rsquo;ve mentioned previously, the dynamic scope is what allows us to travel through our code without transferring the control.
However, Lua doesn&amp;rsquo;t have a dynamic scope builtin into the language.
So how is this possible?&lt;/p&gt;
&lt;p&gt;Well, as you might know, Lua has tables, and these tables are dynamic and mutable.
So theoretically, we could create a table, that is available globally, properly encapsulate it, and use it as our dynamic scope.
And that&amp;rsquo;s exactly what the fennel-conditions library does.&lt;/p&gt;
&lt;p&gt;However, implementing dynamic scope via tables is not enough.
First of all, we need to manage the dynamic scope in a sensible way.
Second, we need some way of actually traveling through the lexical scope to the point where the dynamic scope was created, once we know where we need to move after all handling has been done.
And finally, the scope should be thread-local, and even though Lua doesn&amp;rsquo;t have threads, it has coroutines, which can act as threads, so we should maintain dynamic scope with respect to this aspect of the language.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s begin by listing things that will be implemented in the condition system:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;condition objects - conditions are objects, that can have inheritance, and can embed additional information inside to convey more info about a conditional situation when needed.
Condition objects are defined with &lt;code&gt;define-condition&lt;/code&gt; macro, and a particular instance is created from a base condition object with &lt;code&gt;make-condition&lt;/code&gt; function.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;handler-case&lt;/code&gt;, &lt;code&gt;handler-bind&lt;/code&gt;, &lt;code&gt;restart-case&lt;/code&gt; - macros for creating new frame of the dynamic scope, in which the handlers, and restarts are bound to condition objects.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As well as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;cerror&lt;/code&gt; - a macro for raising a condition that can be ignored by invoking special &lt;code&gt;continue&lt;/code&gt; restart.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ignore-errors&lt;/code&gt; - a macro for suppressing all errors, similarly to &lt;code&gt;try&lt;/code&gt; with a catchall clause that does nothing.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;unwind-protect&lt;/code&gt; - a macro for catching all errors, similar to &lt;code&gt;try&lt;/code&gt; with just a &lt;code&gt;finally&lt;/code&gt; clause.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All these macros share the very common part about setting up and cleaning the dynamic scope, as well as some &lt;code&gt;pcall&lt;/code&gt; trickery to make it all work, which makes it a good entry point to understand what&amp;rsquo;s happening under the hood.&lt;/p&gt;
&lt;h3 id=&#34;the-dynamic-scope&#34;&gt;The dynamic scope&lt;/h3&gt;
&lt;p&gt;Beware, this is going to get really messy.
Dynamic scoping is a foreign concept for Lua, so we have to deal with it ourselves, and ensure that it is correct.
But before we begin, I should illustrate the structure of the library:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;fennel-conditions/
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;├─ impl/
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;│  ├─ condition-system.fnl
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;│  ├─ debugger.fnl
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;│  └─ utils.fnl
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;├─ init.fnl
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;└─ init-macros.fnl
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;init.fnl&lt;/code&gt;, and &lt;code&gt;init-macros.fnl&lt;/code&gt; at the top level are the main entry points for runtime functions, and macros.
These modules depend on the &lt;code&gt;impl/condition-system.fnl&lt;/code&gt; module - the library&amp;rsquo;s private API.
Which in turn uses &lt;code&gt;impl/debugger.fnl&lt;/code&gt; that holds implementation of the interactive debugger, and &lt;code&gt;impl/utils.fnl&lt;/code&gt; which stores common functions, used by condition system and debugger.
The main things we&amp;rsquo;re interested in are &lt;code&gt;init.fnl&lt;/code&gt;, &lt;code&gt;init-macros.fnl&lt;/code&gt;, and &lt;code&gt;impl/condition-system.fnl&lt;/code&gt; - the meat and bones of the library.&lt;/p&gt;
&lt;p&gt;The dynamic scope is stored in the &lt;code&gt;impl.condition-system&lt;/code&gt; module and this module is required every time we need to access the dynamic scope.
Lua has a system for caching required modules, so this is a rather cheap operation and this way we don&amp;rsquo;t need to expose dynamic scope in the global scope.&lt;/p&gt;
&lt;p&gt;This is how the dynamic scope table is defined in &lt;code&gt;impl.utils&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; {&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;metadata&lt;/span&gt; &lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;view&lt;/span&gt;} (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;require&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:fennel&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dynamic-scope&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;metadata&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:set&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   {}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:fnl/docstring&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Dynamic scope for the condition system.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;Dynamic scope is a maintained table where handlers and restarts are
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;stored thread-locally.  Thread name is obtained with
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;`coroutine.running` call and each thread holds a table with the
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;following keys `:handlers`, `:restarts`, and `:current-context`.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;Handlers and restarts itselves are tables.&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It&amp;rsquo;s nothing special really, just an ordinary table, but the documentation string mentions several interesting points.
First, that this is a maintained table, meaning that it should not be modified manually.
Second, that it stores scopes in thread-local contexts, meaning that each thread will have its own dynamic scope table.
Each such table in turn has a table for handlers, a separate table for restarts, and some &lt;code&gt;current-context&lt;/code&gt; field, which we will cover a bit later.&lt;/p&gt;
&lt;p&gt;So, to illustrate how the dynamic scope may look at some point of the program running:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;thread: 0x564cab9a12a8&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:handlers&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:handler&lt;/span&gt; {#&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;condition&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;MalformedLogEntry&lt;/span&gt;&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; 0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x564caba2c6e0&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                       #&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;function&lt;/span&gt;&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; 0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x564cabb01500&amp;gt;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:handler-type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;handler-bind&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:parent&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:handler&lt;/span&gt; {#&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;condition&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;MalformedLogEntry&lt;/span&gt;&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; 0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x564caba2c6e0&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                #&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;function&lt;/span&gt;&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; 0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x564caba5ccf0&amp;gt;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                      &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:handler-type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;handler-bind&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                      &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:parent&lt;/span&gt; {}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                      &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:target&lt;/span&gt; {}}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:target&lt;/span&gt; {}}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:restarts&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:parent&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:parent&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:parent&lt;/span&gt; {}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                               &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:restart&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:args&lt;/span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;ignore-val&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                         &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;ignore&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                         &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:restart&lt;/span&gt; #&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;function&lt;/span&gt;&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; 0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x564cabb01580&amp;gt;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                               &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:target&lt;/span&gt; {}}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                      &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:restart&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:args&lt;/span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;fixed-line&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;reparse-line&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:restart&lt;/span&gt; #&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;function&lt;/span&gt;&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; 0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x564cabaa7a10&amp;gt;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                      &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:target&lt;/span&gt; {}}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:restart&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:args&lt;/span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;x&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                       &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;use-value&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                       &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:restart&lt;/span&gt; #&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;function&lt;/span&gt;&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; 0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x564caba5cd30&amp;gt;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:target&lt;/span&gt; {}}}}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This is the state of the dynamic scope when we enter the &lt;code&gt;restart-case&lt;/code&gt; macro and do all setups, in the &lt;a href=&#34;#code-snippet--fennel-example&#34;&gt;fennel&lt;/a&gt; code from the example section.
There&amp;rsquo;s quite a lot happening here - lots of nested tables with similar internal structures, and even some empty tables.&lt;/p&gt;
&lt;p&gt;First thing you can spot is that the outermost table has a key &lt;code&gt;&amp;quot;thread: 0x564cab9a12a8&amp;quot;&lt;/code&gt; which holds the table with &lt;code&gt;handlers&lt;/code&gt; and &lt;code&gt;restarts&lt;/code&gt;.
This is the thread-local dynamic scope, representing the main thread.
Inside of it in the table under the &lt;code&gt;handlers&lt;/code&gt; key, we see a table with a &lt;code&gt;handler&lt;/code&gt; key holding a table with a condition, (which is actually just another table&lt;sup id=&#34;fnref:2&#34;&gt;&lt;a href=&#34;#fn:2&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;2&lt;/a&gt;&lt;/sup&gt;), and a function:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:handler&lt;/span&gt; {#&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;condition&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;MalformedLogEntry&lt;/span&gt;&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; 0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x564caba2c6e0&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           #&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;function&lt;/span&gt;&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; 0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x564cabb01500&amp;gt;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:handler-type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;handler-bind&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:parent&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:handler&lt;/span&gt; {#&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;condition&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;MalformedLogEntry&lt;/span&gt;&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; 0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x564caba2c6e0&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    #&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;function&lt;/span&gt;&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; 0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x564caba5ccf0&amp;gt;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:handler-type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;handler-bind&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:parent&lt;/span&gt; {}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:target&lt;/span&gt; {}}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:target&lt;/span&gt; {}}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This table corresponds to all dynamic scopes set up with &lt;code&gt;handler-bind&lt;/code&gt; macros.
But as you can see here, it has a &lt;code&gt;parent&lt;/code&gt; key, that holds another very similar table, but as you might remember, there was only one &lt;code&gt;handler-bind&lt;/code&gt; instance in the &lt;a href=&#34;#code-snippet--fennel-example&#34;&gt;example code&lt;/a&gt; - why there are two tables?
Here&amp;rsquo;s a quick refresher of how &lt;code&gt;handler-bind&lt;/code&gt; was used:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;handler-bind&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;MalformedLogEntry&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;e&lt;/span&gt; {&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt;}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;match&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fix-line&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fixed-line&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;invoke-restart&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:reparse-line&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fixed-line&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;MalformedLogEntry&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;e&lt;/span&gt; {&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt;}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;io.stderr&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:write&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;malformed log entry: &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\n&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;invoke-restart&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:ignore&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; ---- 8&amp;lt; ----&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  )
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Note that there are two separate entries for &lt;code&gt;MalformedLogEntry&lt;/code&gt; condition.
Each such entry creates a separate frame in the dynamic scope, which results in two nested tables as shown above.
This is done this way because the handlers are bound sequentially, and their order in the handler bind determines the order of how they will be called.
We directly use this property, by writing the first handler in such a way, that if the line can&amp;rsquo;t be fixed with &lt;code&gt;fix-line&lt;/code&gt; function, we are not calling &lt;code&gt;invoke-restart&lt;/code&gt; and the condition falls through to the next handler.
This handler in turn calls &lt;code&gt;:ignore&lt;/code&gt; restart, and successfully recovers from the error.
Now let&amp;rsquo;s look at the dynamic scope stored under &lt;code&gt;:restarts&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:parent&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:parent&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:parent&lt;/span&gt; {}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:restart&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:args&lt;/span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;ignore-val&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                             &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;ignore&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                             &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:restart&lt;/span&gt; #&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;function&lt;/span&gt;&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; 0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x564cabb01580&amp;gt;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:target&lt;/span&gt; {}}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:restart&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:args&lt;/span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;fixed-line&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;reparse-line&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:restart&lt;/span&gt; #&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;function&lt;/span&gt;&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; 0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x564cabaa7a10&amp;gt;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:target&lt;/span&gt; {}}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:restart&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:args&lt;/span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;x&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;use-value&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:restart&lt;/span&gt; #&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;function&lt;/span&gt;&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; 0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x564caba5cd30&amp;gt;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:target&lt;/span&gt; {}}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Very similarly, each level stores a &lt;code&gt;:restart&lt;/code&gt; table, with an argument list, name, and the function itself.
Under the &lt;code&gt;:parent&lt;/code&gt; key, the very similar table is stored, holding the next restart.
Since our code defined three restarts, we get a table of the depth of three.
One might wonder, why this is necessary, restarts are selected and not tried in order.
While this is true, nothing prevents you from creating two restarts with the same name:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;restart-case&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;/ &lt;/span&gt;1 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:use-value&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;] &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:use-value&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;] &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This will create the following table:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:parent&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:parent&lt;/span&gt; {}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:restart&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:args&lt;/span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;x&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;use-value&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:restart&lt;/span&gt; #&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;function&lt;/span&gt;&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; 0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x564cabb01380&amp;gt;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:target&lt;/span&gt; {}}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:restart&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:args&lt;/span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;x&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;use-value&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:restart&lt;/span&gt; #&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;function&lt;/span&gt;&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; 0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x564cabaa5b40&amp;gt;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:target&lt;/span&gt; {}}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You then will be able to choose which restart to call via the interactive debugger interface.
But more about that later.&lt;/p&gt;
&lt;p&gt;Now that we have a rough understanding of how dynamic scopes are composed inside, let&amp;rsquo;s look at how those are really constructed.&lt;/p&gt;
&lt;h3 id=&#34;constructing-dynamic-scope-for-handlers&#34;&gt;Constructing dynamic scope for handlers&lt;/h3&gt;
&lt;p&gt;Let&amp;rsquo;s look at the &lt;code&gt;handler-bind&lt;/code&gt; macro invocation once again:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;handler-bind&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;MalformedLogEntry&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;e&lt;/span&gt; {&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt;}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;match&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fix-line&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fixed-line&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;invoke-restart&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:reparse-line&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fixed-line&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;MalformedLogEntry&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;e&lt;/span&gt; {&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt;}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;io.stderr&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:write&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;malformed log entry: &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\n&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;invoke-restart&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:ignore&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; ---- 8&amp;lt; ----&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  )
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Much like &lt;code&gt;let&lt;/code&gt;, it accepts a vector of bindings - a condition object, and a function that will be called.
Similarly to &lt;code&gt;let&lt;/code&gt; it binds sequentially, but doesn&amp;rsquo;t override bindings, but creates a set of nested scope frames to store each binding.
Then it executes the body in the context of this dynamic scope.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s look at the actual implementation and break it down:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;handler-bind&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;binding-vec&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;target&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;gensym &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:target&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;scope&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;gensym &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:scope&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;binding-len&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;length&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;binding-vec&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;setup&lt;/span&gt; &amp;#39;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;do&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;assert-compile&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;= &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;%&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;binding-len&lt;/span&gt; 2) 0)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;expected even number of signal/handler bindings&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;binding-vec&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;for &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;binding-len&lt;/span&gt; 1 -2]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;condition-object&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;binding-vec&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;- &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; 1))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;handler&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;binding-vec&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;assert-compile&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sym?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;handler&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;function-form?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;handler&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;handler must be a function&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;handler&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;table.insert&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;setup&lt;/span&gt; `(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;assert &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;not= &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt; ,&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;condition-object&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                     &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;condition object must not be nil&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;table.insert&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;setup&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         `(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tset&lt;/span&gt; ,&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;scope&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:handlers&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:parent&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;. &lt;/span&gt;,&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;scope&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:handlers&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:target&lt;/span&gt; ,&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;target&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:handler-type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:handler-bind&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:handler&lt;/span&gt; {,&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;condition-object&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                            ,&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;handler&lt;/span&gt;}}))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    `(&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[,&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;target&lt;/span&gt; {}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:pack&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pack#&lt;/span&gt;} (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;require&lt;/span&gt; ,&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;utils&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:pcall-handler-bind&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pcall-handler-bind#&lt;/span&gt;} (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;require&lt;/span&gt; ,&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;condition-system&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           ,&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;scope&lt;/span&gt; ,(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;current-scope&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;orig-handlers#&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;. &lt;/span&gt;,&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;scope&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:handlers&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       ,&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;setup&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pcall-handler-bind#&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        #(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pack#&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;do &lt;/span&gt;,&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;)) ,&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;scope&lt;/span&gt; ,&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;target&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;orig-handlers#&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This is the entirety of &lt;code&gt;handler-bind&lt;/code&gt; macro, minus the docstring and some comments, and while the actual body that gets spliced into the program&amp;rsquo;s source code is not very big, the setup looks somewhat complicated.
So let&amp;rsquo;s break it down.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;handler-bind&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;binding-vec&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;target&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;gensym &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:target&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;scope&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;gensym &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:scope&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;binding-len&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;length&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;binding-vec&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;setup&lt;/span&gt; &amp;#39;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;do&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;assert-compile&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;= &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;%&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;binding-len&lt;/span&gt; 2) 0)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;expected even number of signal/handler bindings&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;binding-vec&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; ---- 8&amp;lt; ----&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;First, we create some unique names that we will use both at compile-time, and then at runtime.
You might remember the &lt;code&gt;:target&lt;/code&gt; key in tables, that represented the dynamic scope.
This key is holding this &lt;code&gt;target&lt;/code&gt; symbol, which we define at run time, but we need a way of putting it into the dynamic scope at compile-time, that&amp;rsquo;s why it&amp;rsquo;s defined here.
I&amp;rsquo;ll explain why it&amp;rsquo;s an important key soon.&lt;/p&gt;
&lt;p&gt;Next up is the &lt;code&gt;scope&lt;/code&gt;, this is an instance of dynamic scope we&amp;rsquo;re going to construct at compile time.
&lt;code&gt;binding-len&lt;/code&gt; is just to avoid small pieces of code duplication, and the last one - &lt;code&gt;setup&lt;/code&gt; is the code that will fill the missing bits of our dynamic scope at runtime.&lt;/p&gt;
&lt;p&gt;After &lt;code&gt;let&lt;/code&gt;, we&amp;rsquo;re doing a check, that the &lt;code&gt;binding-vec&lt;/code&gt;, a vector that holds condition objects and their handlers, has an even amount of values.
We can&amp;rsquo;t properly construct the dynamic scope if a handler is missing, so it&amp;rsquo;s a compile-time error.&lt;/p&gt;
&lt;p&gt;Now for the main part - the &lt;code&gt;for&lt;/code&gt; loop, which creates a set of instructions that will construct the dynamic scope:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; ---- 8&amp;lt; ----&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;for &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;binding-len&lt;/span&gt; 1 -2]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;condition-object&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;binding-vec&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;- &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; 1))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;handler&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;binding-vec&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;assert-compile&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sym?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;handler&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;function-form?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;handler&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;handler must be a function&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;handler&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;table.insert&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;setup&lt;/span&gt; `(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;assert &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;not= &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt; ,&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;condition-object&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;condition object must not be nil&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;table.insert&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;setup&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     `(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tset&lt;/span&gt; ,&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;scope&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:handlers&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:parent&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;. &lt;/span&gt;,&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;scope&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:handlers&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                              &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:target&lt;/span&gt; ,&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;target&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                              &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:handler-type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:handler-bind&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                              &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:handler&lt;/span&gt; {,&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;condition-object&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                        ,&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;handler&lt;/span&gt;}}))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; ---- 8&amp;lt; ----&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It does several things - first, it checks that the handler is either a symbol or a function form, i.e. a list that will evaluate a function definition.
Next it inserts the runtime assertion, that verifies that the &lt;code&gt;condition-object&lt;/code&gt; is not &lt;code&gt;nil&lt;/code&gt;.
And finally, the &lt;code&gt;tset&lt;/code&gt; call is inserted, that will populate current &lt;code&gt;scope&lt;/code&gt;&amp;rsquo;s &lt;code&gt;:handlers&lt;/code&gt; table with a new table, that refers to the original table via the &lt;code&gt;:parent&lt;/code&gt; key.&lt;/p&gt;
&lt;p&gt;You&amp;rsquo;ve might notice that the loop actually goes backward.
This is done to preserve the correct order when constructing nested tables.
As the dynamic scope is constructed as a set of nested tables, the order of construction has to be reversed, so the travel order gets preserved.
But this code doesn&amp;rsquo;t actually construct the scope, it just describes how to construct it.
The last portion of the macro is what gets spliced into the user&amp;rsquo;s code, so let&amp;rsquo;s look at it:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; ---- 8&amp;lt; ----&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;`(&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[,&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;target&lt;/span&gt; {}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:pack&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pack#&lt;/span&gt;} (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;require&lt;/span&gt; ,&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;utils&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:pcall-handler-bind&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pcall-handler-bind#&lt;/span&gt;} (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;require&lt;/span&gt; ,&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;condition-system&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       ,&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;scope&lt;/span&gt; ,(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;current-scope&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;orig-handlers#&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;. &lt;/span&gt;,&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;scope&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:handlers&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   ,&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;setup&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pcall-handler-bind#&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    #(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pack#&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;do &lt;/span&gt;,&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;)) ,&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;scope&lt;/span&gt; ,&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;target&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;orig-handlers#&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We&amp;rsquo;re finally setting some of those symbols, we&amp;rsquo;ve defined before!
The &lt;code&gt;,target {}&lt;/code&gt; thing, is a way to make sure we get a unique object address that we can later compare, to determine if we&amp;rsquo;ve reached the correct destination when &amp;ldquo;unwinding&amp;rdquo;.
Next, we import some helper functions, like &lt;code&gt;pack#&lt;/code&gt; and &lt;code&gt;pcall-handler-bind#&lt;/code&gt; - the first one is a portable &lt;code&gt;table.pack&lt;/code&gt; implementation, and the last one is a runtime part of &lt;code&gt;handler-bind&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;After that, we&amp;rsquo;re calling something like &lt;code&gt;current-scope&lt;/code&gt;.
It is a commonly used part of all macros, so I&amp;rsquo;ve put it into another macro.
In short, it just returns the current thread&amp;rsquo;s dynamic scope or creates it if it doesn&amp;rsquo;t exist yet.
And right after that, you can see that we&amp;rsquo;re caching original handlers right before &lt;code&gt;,setup&lt;/code&gt;.
This &lt;code&gt;,setup&lt;/code&gt; will splice in all that setup we&amp;rsquo;ve been constructing at compile, that will populate the current scope with new tables.
And then we&amp;rsquo;re calling &lt;code&gt;pcall-handler-bind#&lt;/code&gt; function with all necessary info.&lt;/p&gt;
&lt;p&gt;So this code from &lt;a href=&#34;#code-snippet--fennel-example&#34;&gt;the example&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;handler-bind&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;MalformedLogEntry&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;e&lt;/span&gt; {&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt;}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;match&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fix-line&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fixed-line&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;invoke-restart&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:reparse-line&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fixed-line&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;MalformedLogEntry&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;e&lt;/span&gt; {&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt;}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;io.stderr&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:write&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;malformed log entry: &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\n&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;invoke-restart&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:ignore&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;icollect&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:lines&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parse-line&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;uses &lt;code&gt;handler-bind&lt;/code&gt; macro we&amp;rsquo;ve just examined.
Let&amp;rsquo;s look at what this code expands to:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;target_1_&lt;/span&gt; {}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:pack&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pack_10_auto&lt;/span&gt;} (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;require&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;fennel-conditions.impl.utils&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:pcall-handler-bind&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pcall-handler-bind_11_auto&lt;/span&gt;} (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;require&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;fennel-conditions.impl.condition-system&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;scope_2_&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cs_3_auto&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;require&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;fennel-conditions.impl.condition-system&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                     &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;thread_4_auto&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;and &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;coroutine&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                            &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;coroutine.running&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                            (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tostring&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;coroutine.running&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                       &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;main&amp;#34;&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;match&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cs_3_auto&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;dynamic-scope&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;thread_4_auto&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;scope_5_auto&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;scope_5_auto&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;scope_5_auto&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:handlers&lt;/span&gt; {} &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:restarts&lt;/span&gt; {}}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                       (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tset&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cs_3_auto&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;dynamic-scope&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;thread_4_auto&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;scope_5_auto&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                       &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;scope_5_auto&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;orig-handlers_12_auto&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;scope_2_&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;handlers&amp;#34;&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;do &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;assert &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;not= &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;MalformedLogEntry&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;condition object must not be nil&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tset&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;scope_2_&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;handlers&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:handler&lt;/span&gt; {&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;MalformedLogEntry&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                       (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;e&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:line&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt;}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                         (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;io.stderr&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:write&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;malformed log entry: &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\n&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                         (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;invoke-restart&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;ignore&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;))}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:handler-type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;handler-bind&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:parent&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;scope_2_&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;handlers&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:target&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;target_1_&lt;/span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;assert &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;not= &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;MalformedLogEntry&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;condition object must not be nil&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tset&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;scope_2_&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;handlers&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:handler&lt;/span&gt; {&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;MalformedLogEntry&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                       (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;e&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:line&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt;}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                         (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;match&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fix-line&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                           &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fixed-line&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;invoke-restart&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;reparse-line&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fixed-line&lt;/span&gt;)))}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:handler-type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;handler-bind&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:parent&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;scope_2_&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;handlers&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:target&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;target_1_&lt;/span&gt;}))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pcall-handler-bind_11_auto&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;hashfn&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pack_10_auto&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;do &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;icollect&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:lines&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                               (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parse-line&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;scope_2_&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;target_1_&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;orig-handlers_12_auto&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Quite a lot of code, and there are even more things going on when we&amp;rsquo;re calling the &lt;code&gt;pcall-handler-bind&lt;/code&gt; function!
But you can see that it does exactly what I&amp;rsquo;ve described above - requires some API functions, creates a thread-local scope, sets it up, and wraps our code with the &lt;code&gt;pack&lt;/code&gt; function, for later execution.
Let&amp;rsquo;s now look at what &lt;code&gt;pcall-handler-bind&lt;/code&gt; does.&lt;/p&gt;
&lt;h3 id=&#34;implementing-control-transfer-via-protected-calls&#34;&gt;Implementing control transfer via protected calls&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;pcall-handler-bind&lt;/code&gt; function is defined in the library&amp;rsquo;s private API:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pcall-handler-bind&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;scope&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;target&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;orig-handlers&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Call `f` in given `scope` and pass result up to `target`.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;Restore dynamic scope handlers to `orig-handlers`.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ok&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pcall&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;doto &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;scope&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tset&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:current-context&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tset&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:handlers&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;orig-handlers&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ok&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;unpack&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;match&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:state&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:handled&lt;/span&gt; &lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;target&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;raise&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res.type&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res.condition-object&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:state&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:error&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:message&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;msg&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;scope.handlers.parent&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;scope.restarts.parent&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;error&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;error&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;msg&lt;/span&gt; 2))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;error&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Looks pretty simple, but this is because we delegate most of the work to other functions.&lt;/p&gt;
&lt;p&gt;It starts with calling &lt;code&gt;f&lt;/code&gt; in a protected call and immediately removes &lt;code&gt;current-context&lt;/code&gt; from the scope, and sets &lt;code&gt;handlers&lt;/code&gt; to the original handlers, which we&amp;rsquo;ve stored back at the macro side.
Then, if the function exited successfully, we just return the results by unpacking those (for keeping &lt;code&gt;nils&lt;/code&gt; in multiple value returns).
But when the function didn&amp;rsquo;t succeed, we expect a set of certain things as a return.&lt;/p&gt;
&lt;p&gt;For those unfamiliar with &lt;code&gt;match&lt;/code&gt; - it&amp;rsquo;s a pattern-matching macro from Fennel standard library.
It accepts an expression, and a pair of patterns and their respective bodies to run, if the result of an expression matches this pattern.
The first pattern here is &lt;code&gt;{:state :handled :target target}&lt;/code&gt;, meaning that the function &lt;code&gt;f&lt;/code&gt; returned a table with a key &lt;code&gt;:state&lt;/code&gt; holding a &lt;code&gt;:handled&lt;/code&gt; value, and a non-nil &lt;code&gt;:target&lt;/code&gt; key that is equal to the value of &lt;code&gt;target&lt;/code&gt;, passed as function argument.
The table returned in this case usually looks like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:state&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:handled&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:target&lt;/span&gt; {}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:error&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:condition-object&lt;/span&gt; #&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;condition&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;MalformedLogEntry&lt;/span&gt;&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; 0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x564caba2c6e0&amp;gt;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In this case, we &lt;code&gt;raise&lt;/code&gt; the condition object stored in the result from calling &lt;code&gt;f&lt;/code&gt;, with a correct type, meaning that the type is &lt;code&gt;:error&lt;/code&gt;, we raise it as an error, or if it&amp;rsquo;s a &lt;code&gt;:warning&lt;/code&gt;, as a warning and so on.
We&amp;rsquo;ll look at &lt;code&gt;raise&lt;/code&gt; in a moment, but for now, all you need to know is that it will throw the condition object further up.&lt;/p&gt;
&lt;p&gt;If the pattern contained &lt;code&gt;:state&lt;/code&gt; &lt;code&gt;:error&lt;/code&gt; we check if we have more handlers up the dynamic scope, and if we do, we throw the result as is, so it could be handled.
If not, that means that we&amp;rsquo;re already at a top level, so we convert this to Lua error with a message.&lt;/p&gt;
&lt;p&gt;In all other cases this is an error that we want to throw up, as we can&amp;rsquo;t do anything about it because it is either not a conditional situation or &lt;code&gt;target&lt;/code&gt; doesn&amp;rsquo;t match the expected one.&lt;/p&gt;
&lt;p&gt;So the basic idea here is that we&amp;rsquo;re ensuring that the function will either succeed or fail as we expect, and if it fails in an unexpected way, we just rethrow the error.
Lua doesn&amp;rsquo;t have a way to rethrow the stack traces, but it&amp;rsquo;s a small price to pay here.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s look at &lt;code&gt;raise&lt;/code&gt; now:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;raise&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;condition-type&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;condition-object&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Raises `condition-object&amp;#39; as a condition of `condition-type&amp;#39;.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;`condition-object&amp;#39; must not be `nil&amp;#39;.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;assert &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;not= &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;condition-object&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;condition must not be nil&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;thread&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;current-thread&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;thread-scope&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;do &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;when &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;not &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dynamic-scope&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;thread&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                           (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tset&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dynamic-scope&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;thread&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:handlers&lt;/span&gt; {} &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:restarts&lt;/span&gt; {}}))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                         (&lt;span style=&#34;font-weight:bold&#34;&gt;. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dynamic-scope&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;thread&lt;/span&gt;))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;when &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;thread-scope.handlers.handler-type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:handler-bind&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;match&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;thread-scope.current-context&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;scope&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;target&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;scope.target&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                     (&lt;span style=&#34;font-weight:bold&#34;&gt;var &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;scope&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;scope.parent&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;while&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;and &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;scope&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;target&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;scope.target&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                       (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;scope&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;scope.parent&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tset&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;thread-scope&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:handlers&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;scope&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;match&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;condition-type&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:condition&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;raise-condition&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;condition-object&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:warning&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;raise-warning&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;condition-object&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:error&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;raise-error&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;condition-object&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This function does something interesting with &lt;code&gt;current-context&lt;/code&gt;.
As you saw in &lt;code&gt;pcall-handler-bind&lt;/code&gt;, we&amp;rsquo;ve set the &lt;code&gt;current-context&lt;/code&gt; to &lt;code&gt;nil&lt;/code&gt;, but &lt;code&gt;raise&lt;/code&gt; actually check it.
Why?&lt;/p&gt;
&lt;p&gt;This is because the condition can be raided inside the handler.
In such a case, we need to unwind the stack to the point where we were in the handler.
So each invocation of the &lt;code&gt;handle&lt;/code&gt; function sets the &lt;code&gt;current-context&lt;/code&gt; field, and this field is cleared when we exit the handler.
This stack unwinding needs to be done in order to avoid infinite recursion, which will result in a stack overflow error.&lt;/p&gt;
&lt;p&gt;After that is done, we branch on the condition type and raise the condition accordingly.
For the purposes of this article let&amp;rsquo;s look at conditions of error type only, by looking at the &lt;code&gt;raise-error&lt;/code&gt; function:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;raise-error&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;condition-object&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;match&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;raise-condition&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;condition-object&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:error&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_G.condition-system-use-debugger?&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;invoke-debugger&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;condition-object&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;error&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;compose-error-message&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;condition-object&lt;/span&gt;) 2))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In case the condition is not handled it&amp;rsquo;s raised as a Lua error unless the debugger feature was enabled.
The condition itself is raised with the &lt;code&gt;raise-condition&lt;/code&gt; function:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;raise-condition&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;condition-object&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;type*&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;match&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;handle&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;condition-object&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;type*&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:condition&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;where&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or &lt;/span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:state&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:handled&lt;/span&gt; &amp;amp;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;as&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:state&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:restarted&lt;/span&gt; &amp;amp;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;as&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt;}))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;error&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt; 2)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Here&amp;rsquo;s the &lt;code&gt;handle&lt;/code&gt; innovation, mentioned above.
The result can be either a table with &lt;code&gt;:handled&lt;/code&gt; or &lt;code&gt;:restarted&lt;/code&gt; states, each of which tells the condition system what to do next.
Even though the condition is handled this result gets thrown up as an error because we actually need to tell the condition system that the condition was handled, and differentiate it from a successful return from the function.&lt;/p&gt;
&lt;p&gt;So let&amp;rsquo;s look at how conditions are handled.&lt;/p&gt;
&lt;h3 id=&#34;handling-conditions&#34;&gt;Handling conditions&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;handle&lt;/code&gt; function looks like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;handle&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;condition-object&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;type*&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;?scope&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Handle the `condition-object&amp;#39; of `type*&amp;#39; and optional `?scope`.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;Finds the `condition-object&amp;#39; handler in the dynamic scope.  If found,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;calls the handler, and returns a table with `:state` set to
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;`:handled`, and `:handler` bound to an anonymous function that calls
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;the restart.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;thread&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;current-thread&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;thread-scope&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dynamic-scope&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;thread&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;match&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;find-handler&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;condition-object&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;type*&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;?scope&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;thread-scope.handlers&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      {&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;handler&lt;/span&gt; &lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;scope&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;do &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tset&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;thread-scope&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:current-context&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;scope&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;match&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;scope.handler-type&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:handler-case&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:state&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:handled&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:handler&lt;/span&gt; #(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;handler&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;condition-object&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;unpack&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;get-data&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;condition-object&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:target&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;scope.target&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:condition-object&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;condition-object&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;type*&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:handler-bind&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;do &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;handler&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;condition-object&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;unpack&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;get-data&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;condition-object&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                              (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;handle&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;condition-object&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;type*&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;scope.parent&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:state&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:error&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:message&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;wrong handler-type: &amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;view&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:condition&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;condition-object&lt;/span&gt;}))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:state&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:error&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:message&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;no handler bound for condition: &amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;get-name&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;condition-object&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:condition&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;condition-object&lt;/span&gt;})))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Let&amp;rsquo;s dive into it.&lt;/p&gt;
&lt;p&gt;After getting the current thread and the scope, we call &lt;code&gt;find-handler&lt;/code&gt;.
For now, it&amp;rsquo;s enough to know, that it takes a condition object, and walks the dynamic scope comparing this object to handlers.
Next up, if the handler were found, we set the &lt;code&gt;current-context&lt;/code&gt; to the handler&amp;rsquo;s scope.
This will ensure that we know where we last were before actually executing a handler, so we could unwind the stack to this point in case an error happens inside the handler.
This was a very painful thing to figure out when I worked on the implementation.&lt;/p&gt;
&lt;p&gt;After that, we branch on the handler type.
The &lt;code&gt;handler-case&lt;/code&gt; macro allows handling without calling &lt;code&gt;invoke-restart&lt;/code&gt;, so we just return a table with &lt;code&gt;:state&lt;/code&gt; set to &lt;code&gt;:handled&lt;/code&gt;, and a handler that actually does the handling.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;handler-bind&lt;/code&gt; is different - it requires handling with &lt;code&gt;invoke-restart&lt;/code&gt;, which, as you might remember throws an error to transfer control flow.
So if the &lt;code&gt;handler&lt;/code&gt; function exited normally, we go to the next &lt;code&gt;handle&lt;/code&gt; invocation, which will propagate the condition object to another handler up the stack.
This ensures that we can decline to handle a condition.&lt;/p&gt;
&lt;p&gt;If no handler is found the error is returned.&lt;/p&gt;
&lt;figure class=&#34;invertable&#34;&gt;&lt;img src=&#34;https://andreyor.st/2021-08-08-condition-system-for-fennel-language-and-lua-runtime/handling.svg&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;A similar pattern occurs for other condition types, with the difference being that some may not return an actual error when unhandled.&lt;/p&gt;
&lt;p&gt;So how handlers are found?
The &lt;code&gt;find-handler&lt;/code&gt; function, which accepts a condition object and a handler type, will walk the scope comparing the given condition object to bound handlers.
However, condition objects actually support inheritance, so this gets a bit more complicated.
We need to look for a handler in the current scope, and if no handler is found, we need to get the parent from the condition object and search its handler in the same scope.
If no handler and no parent handler are to be found, we go to the next scope frame.&lt;/p&gt;
&lt;p&gt;Additionally, conditions may not be of the condition-object type, but be an arbitrary Lua value:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;handler-case&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;signal&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;math.random&lt;/span&gt; 5))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (0 [] &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:zero&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (1 [] &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:one&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (2 [] &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:two&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Condition&lt;/span&gt; [] &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:else&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; an unnecessarily complicated equivalent of&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;match&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;math.random&lt;/span&gt; 5)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  0 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:zero&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:one&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  2 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:two&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:else&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Notice, that while I&amp;rsquo;m handling conditions as numbers, the catch-all condition object is specified as &lt;code&gt;Condition&lt;/code&gt;.
Let&amp;rsquo;s talk more about condition inheritance.&lt;/p&gt;
&lt;h3 id=&#34;condition-inheritance&#34;&gt;Condition inheritance&lt;/h3&gt;
&lt;p&gt;As was already mentioned, condition objects can have parent condition objects.
A parent can be explicitly set by using the &lt;code&gt;:parent&lt;/code&gt; key when defining a condition:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;define-condition&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;MathError&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;define-condition&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;DivideByZero&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:parent&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;MathError&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;define-condition&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;NegSquareRoot&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:parent&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;MathError&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sqrt&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;&amp;lt; &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; 0)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;error&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;make-condition&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;NegSquareRoot&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;math.sqrt&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;div&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt; 0)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;error&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;make-condition&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;DivideByZero&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;/ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;main&lt;/span&gt; []
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;handler-case&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sqrt&lt;/span&gt; -1)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;MathError&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;] (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;io.stderr&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:write&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Can&amp;#39;t take square root of &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\n&amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;handler-case&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;div&lt;/span&gt; 2 0)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;MathError&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;] (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;io.stderr&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:write&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Can&amp;#39;t divide by zero\n&amp;#34;&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Here&amp;rsquo;s an example of handling different errors through their common parent.
You can create hierarchical errors, which then can be handled with more granularity, or as a whole class of errors.&lt;/p&gt;
&lt;p&gt;But there are a bit more rules regarding inheritance.
All conditions raised with &lt;code&gt;error&lt;/code&gt; function will by default inherit from the &lt;code&gt;Error&lt;/code&gt; condition.
All conditions raised with &lt;code&gt;warn&lt;/code&gt; will inherit from a &lt;code&gt;Warning&lt;/code&gt; condition.
Both &lt;code&gt;Warning&lt;/code&gt; and &lt;code&gt;Error&lt;/code&gt; are inherited from the &lt;code&gt;Condition&lt;/code&gt; condition.&lt;/p&gt;
&lt;p&gt;This also applies to any arbitrary data you can throw with &lt;code&gt;error&lt;/code&gt;, &lt;code&gt;warn&lt;/code&gt;, or &lt;code&gt;signal&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;raise-random-condition&lt;/span&gt; []
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;match&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;math.random&lt;/span&gt; 2)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    0 (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;error&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;an error&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    1 (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;signal&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;a signal&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    2 (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;warn&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;a warning&amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;handler-case&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;raise-random-condition&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Error&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;msg&lt;/span&gt;] (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;print &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;caught an error&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;msg&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Warning&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;msg&lt;/span&gt;] (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;print &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;caught a warning&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;msg&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Condition&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;msg&lt;/span&gt;] (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;print &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;caught a condition&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;msg&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Here all conditions are just Lua strings, but we still have some hierarchy.
Note that the order of handlers here is very important - placing the &lt;code&gt;(Condition [msg] (print &amp;quot;caught a condition&amp;quot; msg))&lt;/code&gt; as the first handler will prevent &lt;code&gt;Error&lt;/code&gt; and &lt;code&gt;Warning&lt;/code&gt; handlers from ever running.
It is very similar to &lt;code&gt;match&lt;/code&gt; in that regard - placing &lt;code&gt;_&lt;/code&gt; as the first pattern will make all other patterns unreachable.&lt;/p&gt;
&lt;p&gt;Another thing to point out is that Lua errors also inherit from &lt;code&gt;Error&lt;/code&gt; condition:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;handler-case&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;/ &lt;/span&gt;1 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Error&lt;/span&gt; [] 0))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This is done for seamless integration with libraries that don&amp;rsquo;t use the condition system, or if your code did something wrong by mistake.&lt;/p&gt;
&lt;p&gt;However, the integration is not as seamless as it could be.
The point where it get&amp;rsquo;s not as good as it could be is when interfacing with the interactive debugger, provided by the library.&lt;/p&gt;
&lt;h3 id=&#34;the-debugger&#34;&gt;The debugger&lt;/h3&gt;
&lt;p&gt;Speaking of which, the debugger is not as featureful as in Common Lisp, but still provides a way to recover from an error, when the current scope allows for it.
Consider this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;restart-case&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cs.error&lt;/span&gt; 10)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:use-value&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;] &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Executing this code will raise a condition, which is not handled, so it gets propagated to a Lua error:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;runtime error: condition 10 was raised
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;However, if we set &lt;code&gt;_G.condition-system-use-debugger?&lt;/code&gt; to &lt;code&gt;true&lt;/code&gt;, we&amp;rsquo;ll get this instead:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Debugger was invoked on unhandled condition: 10
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;restarts (invokable by number or by name):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  1: [use-value] use-value
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  2: [throw    ] Throw condition as a Lua error
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;debugger&amp;gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now every unhandled condition will invoke the debugger, which will provide you with available recovery options.
In the case of this example, there are two restarts bound - &lt;code&gt;use-value&lt;/code&gt;, bound by the &lt;code&gt;restart-case&lt;/code&gt; macro, and the other one is an automatically bound &lt;code&gt;throw&lt;/code&gt; restart, that will exit the debugger.&lt;/p&gt;
&lt;p&gt;By typing &lt;code&gt;1&lt;/code&gt; or &lt;code&gt;use-value&lt;/code&gt; in the prompt, we&amp;rsquo;ll enter the next prompt, that asks for a value to use for a selected restart:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;debugger&amp;gt;&amp;gt; 1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Provide inputs for use-value (args: [x]) (^D to cancel)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;debugger:use-value&amp;gt;&amp;gt; 5
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;5
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Thus making the result of the expression to be &lt;code&gt;5&lt;/code&gt;, accordingly to the restart&amp;rsquo;s body.&lt;/p&gt;
&lt;p&gt;This debugger has no runtime penalty unless the condition was not handled.
So only When an unhandled condition pops to the top of the dynamic scope stack, the debugger begins its work.&lt;/p&gt;
&lt;p&gt;Debugger again traverses the scope, gathering all available restarts, and forms this interactive prompt, with each restart in order of their definition:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;restart-case&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;restart-case&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;restart-case&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;/ &lt;/span&gt;1 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:use-value&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;] &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:use-value&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;] &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;use-value (impostor)&amp;#34;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;- &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:do-something&lt;/span&gt; [] (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;+ &lt;/span&gt;1 2 3)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:do-something-else&lt;/span&gt; [] (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;- &lt;/span&gt;3 2 1)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Note that the &lt;code&gt;use-value&lt;/code&gt; restart was specified twice.
I&amp;rsquo;ve mentioned that this is possible, but it is meaningless unless we use a debugger.
Here&amp;rsquo;s what will be prompted to the user, if this code is executed:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Debugger was invoked on unhandled condition: attempt to perform arithmetic on a nil value&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;restarts (invokable by number or by name):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  1: [use-value        ] use-value
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  2:                     use-value (impostor)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  3: [do-something     ] do-something
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  4: [do-something-else] do-something-else
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  5: [throw            ] Throw condition as a Lua error
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;debugger&amp;gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Note that the first restart is indeed named &lt;code&gt;use-value&lt;/code&gt;, but the second one has no name, only its docstring is displayed.
This restart can be manually called by typing &lt;code&gt;2&lt;/code&gt; in the prompt - it will ask for the argument similarly to &lt;code&gt;use-value&lt;/code&gt; restart, but will negate it.
Other restarts are self-explanatory.&lt;/p&gt;
&lt;h2 id=&#34;ending-thoughts&#34;&gt;Ending thoughts&lt;/h2&gt;
&lt;p&gt;This should provide some information about this library&amp;rsquo;s internals.&lt;/p&gt;
&lt;p&gt;Seeing how many &lt;code&gt;pcall&lt;/code&gt; calls it does to transfer control flow around, and how it manages the dynamic stack, can make you think that it has not a very good performance.
And in fact, I would agree, the performance could be better.
But it&amp;rsquo;s not that bad.
For example, here&amp;rsquo;s a 10000000 invocations of Lua&amp;rsquo;s &lt;code&gt;error&lt;/code&gt; function inside a &lt;code&gt;pcall&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;macro &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;time&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;expr&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;times&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  `(&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c#&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;os.clock&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s#&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c#&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;r#&lt;/span&gt; &lt;span style=&#34;&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;expr&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;e#&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c#&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;print &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Average time elapsed &amp;#34;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;/ &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;* &lt;/span&gt;1000 (&lt;span style=&#34;font-weight:bold&#34;&gt;- &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;e#&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s#&lt;/span&gt;)) &lt;span style=&#34;&#34;&gt;,&lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;times&lt;/span&gt; 1)) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; ms&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;r#&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;time&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;for &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; 1 10000000]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;pcall error &lt;/span&gt;10))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      10000000)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; Average time elapsed 0.0002025262 ms&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And here&amp;rsquo;s an equivalent using condition system&amp;rsquo;s &lt;code&gt;error&lt;/code&gt; and &lt;code&gt;ignore-errors&lt;/code&gt; macro:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;{&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;error&lt;/span&gt;} (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:condition-system&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;time&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;for &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; 1 10000000]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ignore-errors&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;error &lt;/span&gt;10)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      10000000)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; Average time elapsed 0.0051841138 ms&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;There&amp;rsquo;s one order of magnitude difference in performance here, meaning that &lt;code&gt;ignore-errors&lt;/code&gt; is ~10 times slower than pure &lt;code&gt;pcall&lt;/code&gt;.
But the benefits, that the condition system provides, out-weight this cost, in my opinion.&lt;/p&gt;
&lt;p&gt;Also, a note on why I didn&amp;rsquo;t port the rest of Common Lisp&amp;rsquo;s condition system.
While this library is not a full port, I think it has all the necessary parts in the context of the Fennel language.
What I mean by that is, that since Fennel, for example, deliberately chose to avoid Lua&amp;rsquo;s &lt;code&gt;return&lt;/code&gt; special, I don&amp;rsquo;t think a condition system should provide &lt;code&gt;block&lt;/code&gt; and &lt;code&gt;return&lt;/code&gt;, or &lt;code&gt;go&lt;/code&gt; specials.
I don&amp;rsquo;t have strong reasoning behind it, but I feel that the error handling part in Lua is what&amp;rsquo;s needed to be improved, thus this library is only aimed at fixing this part of the runtime.&lt;/p&gt;
&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;
&lt;p&gt;In Common Lisp there are more ways to recover from an error from the handler bound with &lt;code&gt;handler-bind&lt;/code&gt;, but &lt;code&gt;fennel-conditions&lt;/code&gt; library doesn&amp;rsquo;t implement all those ways.&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:2&#34;&gt;
&lt;p&gt;Tables, tables, tables, tables, tables&amp;hellip; tables, and tables - that&amp;rsquo;s Lua at its best.&amp;#160;&lt;a href=&#34;#fnref:2&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: Condition system for Fennel language and Lua runtime&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Sun, 08 Aug 2021 18:47:00 +0300</pubDate>
    </item><item>
      <title>Pretty-printing for Fennel Language</title>
      <link>https://andreyor.st/posts/2021-01-09-pretty-printing-for-fennel-language/</link>
      <guid>https://andreyor.st/posts/2021-01-09-pretty-printing-for-fennel-language/</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Update&lt;/strong&gt;:&lt;/p&gt;
&lt;p&gt;All the patches&lt;sup&gt;&lt;a href=&#34;https://git.sr.ht/~technomancy/fennel/commit/8cf5bb8eab82d80ffc2c135d32135d07f06ef61e&#34; target=&#34;_blank&#34;&gt;1​&lt;/a&gt;, &lt;a href=&#34;https://git.sr.ht/~technomancy/fennel/commit/9384d52c55b8b7076c067cf1b14bd025220e557d&#34; target=&#34;_blank&#34;&gt;2​&lt;/a&gt;&lt;/sup&gt; has been merged into the main branch of Fennel language, so expect to see improved fennelview in next stable release!
Some semantics have been altered, so I&amp;rsquo;ve updated the post a bit to reflect the changes.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;p&gt;&lt;a href=&#34;https://en.wikipedia.org/wiki/Prettyprint#Lisp_pretty-printer&#34; target=&#34;_blank&#34;&gt;Pretty-printing in Lisp&lt;/a&gt; is a way to represent data structures that we operate in our program in a human-readable way.
This technique is quite old and was part of many Lisp languages for a very long time.
Because Lisps usually are &lt;a href=&#34;https://en.wikipedia.org/wiki/Homoiconicity#In_Lisp&#34; target=&#34;_blank&#34;&gt;homoiconic&lt;/a&gt;, defining a pretty printer for Lisp&amp;rsquo;s main data structure in terms of the syntax expected by the &lt;a href=&#34;https://en.wikipedia.org/wiki/Lisp_reader&#34; target=&#34;_blank&#34;&gt;reader&lt;/a&gt;, we get a way to pretty-print Lisp&amp;rsquo;s code, thus making pretty-printer act as a formatter.
And as far as I know, this was originally the main purpose for pretty printer - code was written in a &amp;ldquo;compressed&amp;rdquo; form, e.g. no line breaks to save space, and then pretty-printed on some kind of display.
This was also handy to review outputs of programs that generate programs, another common property of Lisp languages.&lt;/p&gt;
&lt;p&gt;Fennel is a relatively young Lisp-like language, that compiles to Lua.
It uses Lua&amp;rsquo;s main data structure - a table, as its main data structure, and has its own pretty printer, called &lt;a href=&#34;https://git.sr.ht/~technomancy/fennel/tree/3dbee7d40bef802dcf58a07f2daea1db17e59dca/item/fennelview.fnl&#34; target=&#34;_blank&#34;&gt;fennelview&lt;/a&gt;.
It&amp;rsquo;s a pretty simple pretty printer, that is mostly based on another pretty printer for Lua, called &lt;a href=&#34;https://github.com/kikito/inspect.lua&#34; target=&#34;_blank&#34;&gt;inspect.lua&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Since &lt;code&gt;inspect.lua&lt;/code&gt; is oriented at producing Lua-style tables, &lt;code&gt;fennelview.fnl&lt;/code&gt; was altered to make it output tables in a Fennel&amp;rsquo;s syntax, so printed tables could be read back by the reader.
It is important to note, that &lt;code&gt;inspect.lua&lt;/code&gt; is not oriented at table serialization, hence this is not well suited for a Lisp-like language.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;fennelview.lua&lt;/code&gt; also shared some problems, most of which were inherited from &lt;code&gt;inspect.lua&lt;/code&gt;, and one of which is indentation handling.
In Fennel v0.7.0, tables were printed like this in the REPL:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:a&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:b&lt;/span&gt; 2 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:c&lt;/span&gt; 3}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:a&lt;/span&gt; 1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:b&lt;/span&gt; 2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:c&lt;/span&gt; 3
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Indentation seems to be correct from a C-like language standpoint, but Lisp hackers usually expect the following notation:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:a&lt;/span&gt; 1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:b&lt;/span&gt; 2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:c&lt;/span&gt; 3}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This is more concise and takes less horizontal space.
It may seem like not a big deal, however, the main issue is that &lt;code&gt;fennelview&lt;/code&gt; can&amp;rsquo;t properly deal with nested tables.
For example, if we put the table from above into a sequential table with some elements, and possibly other tables, we&amp;rsquo;ll get an unpleasant result:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; [1 {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:a&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:b&lt;/span&gt; 2} 2 3 {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:c&lt;/span&gt; 4 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:d&lt;/span&gt; 5 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:e&lt;/span&gt; 6 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:f&lt;/span&gt; 7 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:g&lt;/span&gt; 8} 9]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[1 {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:a&lt;/span&gt; 1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:b&lt;/span&gt; 2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  } 2 3 {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:c&lt;/span&gt; 4
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:d&lt;/span&gt; 5
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:e&lt;/span&gt; 6
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:f&lt;/span&gt; 7
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:g&lt;/span&gt; 8
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  } 6]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Indentation no longer makes any sense, and while this is not an issue for Fennel&amp;rsquo;s reader, it is hard to read such data structure from a human perspective.
There are two other Lisps languages with quite a similar syntax - Janet and Clojure, each of which formats the table from above like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[1 {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:a&lt;/span&gt; 1, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:b&lt;/span&gt; 2} 2 3 {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:c&lt;/span&gt; 4, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:d&lt;/span&gt; 5, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:e&lt;/span&gt; 6, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:f&lt;/span&gt; 7, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:g&lt;/span&gt; 8} 9]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;(Except in Janet parentheses are used in place of square brackets, and there are no commas in the table literal.)&lt;/p&gt;
&lt;p&gt;This is much better than the current behavior of &lt;code&gt;fennelview&lt;/code&gt;, however, I still find this kind of representation a bit hard to read, as we need to keep an eye on the inner object&amp;rsquo;s boundaries.
So I&amp;rsquo;ve decided to re-implement &lt;code&gt;fennelview&lt;/code&gt; from scratch, to make it smarter about indentation, and when to produce multi-line representations of the data structure it was passed.&lt;/p&gt;
&lt;h2 id=&#34;lua-tables-and-fennel-reader&#34;&gt;Lua tables, and Fennel reader&lt;/h2&gt;
&lt;p&gt;Tables in Lua are implemented as a combination of associative tables, and sequential array-like parts.
Lua actually has a single syntax for defining both kinds of tables, which uses curly braces:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- sequential table or array&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; t1 = {1, 2, 3}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- associative table&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; t2 = {a = 1, b = 2}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- sequential table with nested tables&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; t3 = {1, t2, 2, 3, {c = 4, d = 5}, 6}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- a combination of associative and sequential tables&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; t4 = {1, 1, 2, 3, 5, kind = &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Fibonacci&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Fennel defines different syntaxes for different table kinds - sequential tables are defined with &lt;code&gt;[]&lt;/code&gt;, and associative tables are defined with &lt;code&gt;{}&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t1&lt;/span&gt; [1 2 3])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t2&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:a&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:b&lt;/span&gt; 2})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t3&lt;/span&gt; [1 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t2&lt;/span&gt; 2 3 {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:c&lt;/span&gt; 4 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:d&lt;/span&gt; 5} 6])
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;However, combined tables are created as associative tables, by providing indexes as keys:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t4&lt;/span&gt; {1 1 2 1 3 2 4 3 5 5 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:kind&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Fibonacci&amp;#34;&lt;/span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; you can do the same in Lua, but it&amp;#39;s more verbose:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; local t4 = {[1] = 1, [2] = 1, [3] = 2, [4] = 3, [5] = 5, kind = &amp;#34;Fibonacci&amp;#34;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Another way of defining such a table is by using &lt;code&gt;set&lt;/code&gt; and mutating the existing sequential table:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t4&lt;/span&gt; [1 1 2 3 5])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t4&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[1 1 2 3 5]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t4.kind&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Fibonacci&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t4&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    1 1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    2 1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    3 2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    4 3
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    5 5
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:kind&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Fibonacci&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Note that until we&amp;rsquo;ve specified the non-sequential key in our table it was printed as a sequence.
However, when a table has non-sequential keys, it is printed as an associative table.
This has deep implications since the &lt;code&gt;ipairs&lt;/code&gt; function will only traverse the sequential part of the table, so by printing a table this way we also indicate that it has more to it than just the sequential part.&lt;/p&gt;
&lt;p&gt;But the indentation is not right.
I&amp;rsquo;ve thought about a small set of rules, which could be used to decide how to print tables.
This is what I got, and I&amp;rsquo;m pretty much pleased with the results:&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;Associative tables are printed within &lt;code&gt;{}&lt;/code&gt;
    &lt;ol&gt;
      &lt;li&gt;Opened and closed curly braces must stay at the same lines as the first and last key-value pair in the table respectively.&lt;/li&gt;
      &lt;li&gt;Associative tables printed as multi-line if a certain amount of key-value pairs are present. Currently the limit is &lt;code&gt;4&lt;/code&gt;.&lt;/li&gt;
      &lt;li style=&#34;text-decoration:line-through&#34;&gt;If any key or value itself is a table, multi-line output is produced.&lt;/li&gt;
      &lt;li value=&#34;3&#34;&gt;Strings in key position printed as colon-strings if possible.&lt;/li&gt;
    &lt;/ol&gt;
  &lt;/li&gt;
  &lt;li&gt;Sequential tables are printed within
    &lt;ol&gt;
      &lt;li&gt;Opened and closed square brackets must stay at the same lines as the first and last values in the table respectively.&lt;/li&gt;
      &lt;li&gt;Sequential tables printed as multi-line if a certain amount of key-value pairs is present. Optimal limit is &lt;code&gt;10&lt;/code&gt;.&lt;/li&gt;
      &lt;li style=&#34;text-decoration:line-through&#34;&gt;If any value itself is a table, multi-line output is produced.&lt;/li&gt;
    &lt;/ol&gt;
  &lt;/li&gt;
  &lt;li&gt;If the single-line representation of the current data structure and its indentation is greater than a certain amount, a multi-line representation is printed.  Optimal width is &lt;code&gt;80&lt;/code&gt; characters.&lt;/li&gt;
  &lt;li&gt;Nested tables share parent&#39;s indentation level.&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;:&lt;/p&gt;
&lt;p&gt;The scratched rules above were considered initially but changed in the process of integrating the new fennelview into the language.
Therefore, the next part of this post is now irrelevant, because most of these tables were examples of that scratched rule, but the current implementation only checks for the outermost third rule, e.g. for the resulting line width.
Most of these examples would be single-line ones now, the &lt;a href=&#34;#comparison-to-other-lisp-pretty-printers&#34;&gt;comparison section&lt;/a&gt; has a more up-to-date variant of the formatting.
I&amp;rsquo;ve highlighted irrelevant code with cursive.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Let&amp;rsquo;s manually apply these rules to the table that I&amp;rsquo;ve used before to visualize &lt;code&gt;fennelview&lt;/code&gt;&amp;rsquo;s problems:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:a&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:b&lt;/span&gt; 2}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; 2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; 3
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:c&lt;/span&gt; 4
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:d&lt;/span&gt; 5
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:e&lt;/span&gt; 6
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:f&lt;/span&gt; 7
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:g&lt;/span&gt; 8}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; 9]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We can see that the sequential table contains less than 10 elements, &lt;em&gt;but since the second associative table has more than 4 key-value pairs, we use multi-line output.&lt;/em&gt;
&lt;em&gt;On the other hand, the first associative table has only two key-value pairs in each, therefore is printed as a single line.&lt;/em&gt;
&lt;em&gt;And if the second associative table were to have fewer elements, the result would be printed as a one-liner:&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[1 {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:a&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:b&lt;/span&gt; 2} 2 3 {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:c&lt;/span&gt; 4 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:d&lt;/span&gt; 5 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:e&lt;/span&gt; 6 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:f&lt;/span&gt; 7} 9]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Because neither of the inner tables is multiline, and the total line length is less than &lt;code&gt;80&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;In my opinion, this is a very readable form for such kind of data structure - we can immediately see all sequential parts, and associative parts still stand out.
I&amp;rsquo;ve re-implemented &lt;code&gt;fenneview&lt;/code&gt; with these rules applied to sequential and associative tables, and with these changes whenever we pretty-print anything in the REPL we get a correctly indented result.
For example, here&amp;rsquo;s how the configuration file for &lt;a href=&#34;https://gitlab.com/andreyorst/fenneldoc&#34; target=&#34;_blank&#34;&gt;Fenneldoc&lt;/a&gt; is now printed:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fennel.dofile&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;.fenneldoc&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:fennel-path&lt;/span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;cljlib/?.fnl&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;src/?.fnl&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:function-signatures&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:insert-comment&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:insert-copyright&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:insert-license&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:insert-version&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:keys&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:copyright&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;_COPYRIGHT&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:description&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;_DESCRIPTION&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:doc-order&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;_DOC_ORDER&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:license&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;_LICENSE&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:module-name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;_MODULE_NAME&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:version&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;_VERSION&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:order&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;aplhabetic&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:out-dir&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;./doc&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:silent&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;false&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:toc&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;true&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This is the exact way I would write it by hand (and I actually &lt;a href=&#34;https://gitlab.com/andreyorst/fenneldoc/-/blob/16fe52418b4b36d2b8c00a8a1a956522e56a47d8/.fenneldoc&#34; target=&#34;_blank&#34;&gt;did&lt;/a&gt;), and I think this way it looks and reads much better than with default &lt;code&gt;fennelview&lt;/code&gt; implementation.&lt;/p&gt;
&lt;p&gt;However there are some quirks in Lua VM related to tables, and we also need a way to produce correctly indented user-defined data structures, that can be nested in other data structures.&lt;/p&gt;
&lt;h2 id=&#34;cyclic-tables&#34;&gt;Cyclic tables&lt;/h2&gt;
&lt;p&gt;In Lua, it is possible to define a table that contains itself, and Fennel is no exception here.
Current implementation of &lt;code&gt;fennelview&lt;/code&gt; has an option named &lt;code&gt;detect-cycles&lt;/code&gt;, which is set to &lt;code&gt;true&lt;/code&gt; by default.
This means that when we try to print a table that contains itself, we will not go into infinity recursion:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t1&lt;/span&gt; [])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;table.insert&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t1&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@1[#&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;table&lt;/span&gt; @1&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I&amp;rsquo;m not a big fan of this &lt;code&gt;#&amp;lt;table @1&amp;gt;&lt;/code&gt; thing, It mimics Lua&amp;rsquo;s internal string representation for a table for no reason.
More than that, if the table is associative, we&amp;rsquo;ll see exact same &lt;code&gt;#&amp;lt;table @id&amp;gt;&lt;/code&gt; notation, which is not ideal too.
I&amp;rsquo;ve re-implemented parts of the cycle detection algorithm, and now it can differentiate what table type the cycle appears in:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t1&lt;/span&gt; [])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;table.insert&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t1&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@1[@1[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;]]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Cycles are printed either as &lt;code&gt;@id[...]&lt;/code&gt; for sequential tables, or as &lt;code&gt;@id{...}&lt;/code&gt; for associative tables:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t&lt;/span&gt; {})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;v&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t&lt;/span&gt;])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t.v&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;v&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@1{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:v&lt;/span&gt; [@1{&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;}]}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;v&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@1[{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:v&lt;/span&gt; @1[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;]}]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We can disable this behavior by setting &lt;code&gt;:detect-cycles?&lt;/code&gt; option to &lt;code&gt;false&lt;/code&gt;, and if we encounter a cycle, we will go in until the depth limit is reached.
The depth limit is set to &lt;code&gt;128&lt;/code&gt; by default.&lt;/p&gt;
&lt;p&gt;This can also be done for user-defined data structures based on tables.
For example, I&amp;rsquo;ve &lt;a href=&#34;https://gitlab.com/andreyorst/fennel-cljlib/-/blob/d09ca41a9bd602028dda980a3ae4f36240959c24/init.fnl#L1063-1080&#34; target=&#34;_blank&#34;&gt;implemented this&lt;/a&gt; for &lt;code&gt;hash-set&lt;/code&gt; from &lt;a href=&#34;https://gitlab.com/andreyorst/fennel-cljlib&#34; target=&#34;_blank&#34;&gt;Cljlib&lt;/a&gt;, and now sets with cycles are printed as &lt;code&gt;@set1{...}&lt;/code&gt;, or with other IDs, depending on context.
This is done by specifying the custom implementation of &lt;code&gt;__fennelview&lt;/code&gt; metamethod in the table&amp;rsquo;s metatable.&lt;/p&gt;
&lt;h2 id=&#34;fennelview-metamethod&#34;&gt;&lt;code&gt;__fennelview&lt;/code&gt; metamethod&lt;/h2&gt;
&lt;p&gt;Set implementation from Cljlib is a bit overwhelming to explain here, so let&amp;rsquo;s instead define another non-existing data structure.
For example, Lua does not have linked lists, so we can implement &lt;a href=&#34;https://en.wikipedia.org/wiki/Cons&#34; target=&#34;_blank&#34;&gt;cons cells&lt;/a&gt; in terms of tables:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;recur-print-list&lt;/span&gt; [[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;head&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tail&lt;/span&gt;] &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;options&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;view&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;indent&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;elements&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;when &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;head&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;table.insert&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;elements&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;view&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;head&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;options&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;indent&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;match&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tail&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:table&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;?&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:cons&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;-?&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tail&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;getmetatable&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:__type&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;recur-print-list&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tail&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;options&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;view&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;indent&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;elements&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:nil&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;table.insert&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;elements&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;. &amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;view&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tail&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;options&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;indent&lt;/span&gt; 2)))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;elements&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pp-list&lt;/span&gt; [&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;list &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;view&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;options&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;indent&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;elements&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;recur-print-list&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;list &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;options&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;view&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;indent&lt;/span&gt; 1) [])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lines&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;icollect&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ipairs&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;elements&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; 1) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt;)))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;doto &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lines&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tset&lt;/span&gt; 1 (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;(&amp;#34;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lines&lt;/span&gt; 1) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tset&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;length&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lines&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;.. &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lines&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;length&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lines&lt;/span&gt;)) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;)&amp;#34;&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cons-mt&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:__fennelview&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pp-list&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:__type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:cons&lt;/span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;cons &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;h&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t&lt;/span&gt;] (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;setmetatable&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;h&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t&lt;/span&gt;] &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cons-mt&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This is a rather basic implementation for cons list pretty printer, but it already allows us to print lists with a traditional notation:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;cons &lt;/span&gt;1 2)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(1 &lt;span style=&#34;font-weight:bold&#34;&gt;. &lt;/span&gt;2)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;cons &lt;/span&gt;1 (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;cons &lt;/span&gt;2 3))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(1 2 &lt;span style=&#34;font-weight:bold&#34;&gt;. &lt;/span&gt;3)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;cons &lt;/span&gt;1 (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;cons &lt;/span&gt;2 (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;cons &lt;/span&gt;3)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(1 2 3)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;When we encounter multiline tables we force multi-line output for the whole list.
And we can actually see, that the rules of the indentation that we&amp;rsquo;ve defined for tables still apply:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;cons &lt;/span&gt;1 (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;cons &lt;/span&gt;2 (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;cons &lt;/span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:some-long-key&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:some-other-key&lt;/span&gt; 2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                          &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:another-long-key&lt;/span&gt; 3 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:and-yet-another-one&lt;/span&gt; 4})))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; 2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:and-yet-another-one&lt;/span&gt; 4
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:another-long-key&lt;/span&gt; 3
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:some-long-key&lt;/span&gt; 1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:some-other-key&lt;/span&gt; 2})
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The associative table is correctly indented, because we manipulate the &lt;code&gt;indent&lt;/code&gt; argument inside &lt;code&gt;recur-print-list&lt;/code&gt;, and this even works correctly when our list itself is inside of another table:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:list&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;cons &lt;/span&gt;1 (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;cons &lt;/span&gt;2 (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;cons &lt;/span&gt;3 {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:some-long-key&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:some-other-key&lt;/span&gt; 2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                   &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:another-long-key&lt;/span&gt; 3 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:and-yet-another-one&lt;/span&gt; 4})))}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:list&lt;/span&gt; (1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        3
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;. &lt;/span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:and-yet-another-one&lt;/span&gt; 4
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:another-long-key&lt;/span&gt; 3
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:some-long-key&lt;/span&gt; 1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:some-other-key&lt;/span&gt; 2})}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;More complex data structures may require additional logic put in the pretty-printer function, but this example illustrates the idea of control you can have.&lt;/p&gt;
&lt;h2 id=&#34;comparison-to-other-lisp-pretty-printers&#34;&gt;Comparison to other Lisp pretty-printers&lt;/h2&gt;
&lt;p&gt;This implementation may not be as general as the one available in, say, Clojure.
For example, I&amp;rsquo;ve mentioned a rule, that if any nested element of a table is multiline, &lt;code&gt;fennelview&lt;/code&gt; will output multi-line representation.
This rule makes it a lot easier to reason about indentation.
Consider:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user=&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure.pprint/pprint&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:seq&lt;/span&gt; [1 2 3 {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:some-long-key&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:some-other-key&lt;/span&gt; 2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                            &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:another-long-key&lt;/span&gt; 3}]})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:seq&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; [1 2 3 {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:some-long-key&lt;/span&gt; 1, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:some-other-key&lt;/span&gt; 2, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:another-long-key&lt;/span&gt; 3}]}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user=&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure.pprint/pprint&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:seq&lt;/span&gt; [1 2 3 {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:some-long-key&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:some-other-key&lt;/span&gt; 2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                            &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:another-long-key&lt;/span&gt; 3}]})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:seq&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; [1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  3
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:some-long-key&lt;/span&gt; 1,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:some-other-key&lt;/span&gt; 2,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:another-long-key&lt;/span&gt; 3,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:and-yet-another-one&lt;/span&gt; 4}]}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Clojure&amp;rsquo;s &lt;code&gt;pprint&lt;/code&gt; is smart enough to see that it can just put the second table on the second line, and not trigger the multi-line output of a vector.
My implementation of fennelview will print everything on a new line, because the length of single-line representation is big enough, and we can benefit from vertical alignment:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:seq&lt;/span&gt; [1 2 3 {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:some-long-key&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:some-other-key&lt;/span&gt; 2 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:another-long-key&lt;/span&gt; 3}]}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:seq&lt;/span&gt; [1 2 3 {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:another-long-key&lt;/span&gt; 3 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:some-long-key&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:some-other-key&lt;/span&gt; 2}]}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:seq&lt;/span&gt; [1 2 3 {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:some-long-key&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:some-other-key&lt;/span&gt; 2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:another-long-key&lt;/span&gt; 3 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:and-yet-another-one&lt;/span&gt; 4}]}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:seq&lt;/span&gt; [1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       3
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:and-yet-another-one&lt;/span&gt; 4
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:another-long-key&lt;/span&gt; 3
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:some-long-key&lt;/span&gt; 1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:some-other-key&lt;/span&gt; 2}]}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In practice, I find this easier to read, but this actually may make it a bit harder to implement code formatter on top of pretty-printer.
Also, I think that separating keys and values in associative data structure with newlines is a bad decision to make.
Clojure can use commas in printed representation, since they are completely ignored, which I think is a great way to indicate pairs, but does not justify newlines in this particular case at least for me.&lt;/p&gt;
&lt;p&gt;The source code of the formatter is available &lt;a href=&#34;https://gitlab.com/andreyorst/fennel-pprint&#34; target=&#34;_blank&#34;&gt;here&lt;/a&gt;, and I&amp;rsquo;ve submitted a patch to the Fennel language, so hopefully, we&amp;rsquo;ll see this implementation by default.
Thanks for reading!&lt;/p&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: Pretty-printing for Fennel Language&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Sat, 09 Jan 2021 23:07:00 +0300</pubDate>
    </item><item>
      <title>Raymarching with Fennel and LÖVE</title>
      <link>https://andreyor.st/posts/2020-10-15-raymarching-with-fennel-and-love/</link>
      <guid>https://andreyor.st/posts/2020-10-15-raymarching-with-fennel-and-love/</guid>
      <description>&lt;p&gt;Previously I decided to implement a rather basic &lt;a href=&#34;https://andreyor.st/posts/2020-06-04-simple-ray-casting-with-clojurescript/&#34;&gt;raycasting engine in ClojureScript&lt;/a&gt;.
It was a lot of fun, an interesting experience, and ClojureScript was awesome.
I&amp;rsquo;ve implemented a small &lt;a href=&#34;https://andreyor.st/posts/2020-06-04-simple-ray-casting-with-clojurescript/#labyrinth-game&#34;&gt;labyrinth game&lt;/a&gt; and thought about adding more features to the engine, such as camera shake, and wall height change.
But when I started working on these, I quickly understood, that I&amp;rsquo;d like to move on to something more interesting, like a real 3D rendering engine, that also uses rays.
&amp;lt;!&amp;ndash;more&amp;ndash;&amp;gt;
Obviously, my first thought was about writing a ray-tracer&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;.
This technique is widely known and gained a lot of traction recently.
With native hardware support for ray tracing, a lot of games are using it, and there are a lot of tutorials teaching how to implement one&lt;sup id=&#34;fnref:2&#34;&gt;&lt;a href=&#34;#fn:2&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;2&lt;/a&gt;&lt;/sup&gt;.
In short, we cast a bunch of rays in 3D space, and calculate their trajectories, looking for what ray will hit and bounce off.
Different materials have different bounce properties, and by tracing rays from the camera to the source of light, we can imitate illumination.
There are also a lot of different approaches how to calculating bouncing, e.g. for global illumination, and ambient light, but I&amp;rsquo;ve felt that it is a rather complicated task, for a weekend post.
And unlike raycasting, most ray-tracers require polygonal information in order to work, whereas raycasting only needs to know wall start and end points.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve wanted a similar approach for 3D rendering, where we specify an object in terms of its mathematical representation.
Like for a sphere, we&amp;rsquo;ll just specify coordinates of a center, and a radius, and our rays will find intersection points with it, providing us sufficient data to draw this sphere on screen.
And recently, I&amp;rsquo;ve read about a similar technique, that uses rays for drawing on the screen, but instead of casting infinite rays as in raycasting, it marches a ray in terms of steps.
And it also uses a special trick, to make this process very optimized, therefore we can use it for rendering real 3D objects.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve decided to structure this post similarly to the one about raycasting, so this will be another long-read, often more about Fennel rather than raymarching, but at the end, I promise that we&amp;rsquo;ll get something that looks like this:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2020-10-15-raymarching-with-lua-and-love/end-result.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;So, just as in raycasting, first we need to do is to understand how the raymarching engine works &lt;em&gt;on paper&lt;/em&gt;.&lt;/p&gt;
&lt;h2 id=&#34;raymarching-basics&#34;&gt;Raymarching basics&lt;/h2&gt;
&lt;p&gt;Raymarching can be illustrated similarly to raycaster, except it requires more steps until we could render our image.
First, we need a camera, and an object to look at:&lt;/p&gt;
&lt;figure class=&#34;invertable&#34;&gt;&lt;img src=&#34;https://andreyor.st/2020-10-15-raymarching-with-lua-and-love/camera-and-circle.svg&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;Our first step would be to cast a ray, however, unlike with raycasting, we&amp;rsquo;ll cast a portion of a ray:&lt;/p&gt;
&lt;figure class=&#34;invertable&#34;&gt;&lt;img src=&#34;https://andreyor.st/2020-10-15-raymarching-with-lua-and-love/camera-and-circle-short-ray.svg&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;We then check if the ray intersects with the sphere.
It&amp;rsquo;s not, so we do one more step:&lt;/p&gt;
&lt;figure class=&#34;invertable&#34;&gt;&lt;img src=&#34;https://andreyor.st/2020-10-15-raymarching-with-lua-and-love/camera-and-circle-two-steps.svg&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;It&amp;rsquo;s not intersecting yet, so we repeat again:&lt;/p&gt;
&lt;figure class=&#34;invertable&#34;&gt;&lt;img src=&#34;https://andreyor.st/2020-10-15-raymarching-with-lua-and-love/camera-and-circle-ray-overshoot.svg&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;Oops, the ray overshot and is now inside the sphere.
This is not really good option for us, as we want our rays to end directly at the object&amp;rsquo;s surface, without calculating the intersection point with the object itself.
We can fix this by casting a shorter ray:&lt;/p&gt;
&lt;figure class=&#34;invertable&#34;&gt;&lt;img src=&#34;https://andreyor.st/2020-10-15-raymarching-with-lua-and-love/camera-and-circle-small-rays.svg&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;However, this is very inefficient!
And besides, if we&amp;rsquo;ll change the angle a bit or move the camera, we will overshoot again.
This means that we&amp;rsquo;ll either have an incorrect result or require a very small step size, which will blow up the computation process.
How we can fix this?&lt;/p&gt;
&lt;h3 id=&#34;distance-estimation&#34;&gt;Distance estimation&lt;/h3&gt;
&lt;p&gt;The solution to this is a signed distance function or a so-called Distance Estimator.
Imagine if we knew how far we are from the object at any point in time?
This would mean that we can shoot a ray of this length in any direction and still don&amp;rsquo;t hit anything.
Let&amp;rsquo;s add another object to the scene:&lt;/p&gt;
&lt;figure class=&#34;invertable&#34;&gt;&lt;img src=&#34;https://andreyor.st/2020-10-15-raymarching-with-lua-and-love/scene-with-two-objects.svg&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;Now, let&amp;rsquo;s draw two circles, which will represent distances from the objects to the point from where we&amp;rsquo;ll cast rays:&lt;/p&gt;
&lt;figure class=&#34;invertable&#34;&gt;&lt;img src=&#34;https://andreyor.st/2020-10-15-raymarching-with-lua-and-love/distances.svg&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;We can see, that there are two circles, and one is bigger than another.
This means, that if we choose the shortest safe distance, we can safely cast rays in any direction and not overshoot anything.
For example, let&amp;rsquo;s cast a ray towards the square:&lt;/p&gt;
&lt;figure class=&#34;invertable&#34;&gt;&lt;img src=&#34;https://andreyor.st/2020-10-15-raymarching-with-lua-and-love/ray-in-safe-zone.svg&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;We can see, that we haven&amp;rsquo;t reached the square, but more importantly, we did not overshoot it.
Now we need to march the ray again, but what distance should it cover?
To answer this question, we need to take another distance estimation from the ray end to the objects in the scene:&lt;/p&gt;
&lt;figure class=&#34;invertable&#34;&gt;&lt;img src=&#34;https://andreyor.st/2020-10-15-raymarching-with-lua-and-love/second-safe-march.svg&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;Once again we choose a shorter distance, and march towards the square, then get the distance again, and repeat the whole process:&lt;/p&gt;
&lt;figure class=&#34;invertable&#34;&gt;&lt;img src=&#34;https://andreyor.st/2020-10-15-raymarching-with-lua-and-love/another-safe-match.svg&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;You can see that with each step the distance to the object becomes smaller, and thus we will never overshoot the object.
However, this also means, that we will take a lot of really small steps until we finally fully hit the object if we ever do.
This is not a good idea, because it is even more inefficient than using fixed distance, and produces too accurate results, which we don&amp;rsquo;t really need.
So instead of marching up until we exactly hit the object, we will march &lt;em&gt;enough&lt;/em&gt; times.
E.g., until the distance to the object is small enough, then there&amp;rsquo;s no real point to continue marching, as it is clear that we will hit the object soon.
But this also means, that if the ray goes near the edge of an object, we do a lot of expensive steps of computing distance estimations.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s a ray that is parallel to the side of the square, and marches towards the circle:&lt;/p&gt;
&lt;figure class=&#34;invertable&#34;&gt;&lt;img src=&#34;https://andreyor.st/2020-10-15-raymarching-with-lua-and-love/expensive-marching.svg&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;We do a lot of seemingly pointless measurements, and if a ray was closer to the square&amp;rsquo;s side, we would do even more steps.
However, this also means, that we can use this data (since we&amp;rsquo;re already computed it) to render such things as glow, or ambient occlusion.
But more on this later.&lt;/p&gt;
&lt;p&gt;Once a ray hit an object we have all the data we need.
Ray represents a point on the screen, and the more rays we cast the higher resolution of our image will be.
And since we&amp;rsquo;re not using triangles to represent objects, our spheres will always be smooth, no matter how close we are to them, because there are no polygons involved.&lt;/p&gt;
&lt;p&gt;This is basically it.
Ray marching is a quite simple concept, just like raycaster, although it&amp;rsquo;s a bit more complicated, as we do have to compute things in 3D space now.
So let&amp;rsquo;s begin implementing it by installing the required tools, and setting up the project.&lt;/p&gt;
&lt;h2 id=&#34;project-structure&#34;&gt;Project structure&lt;/h2&gt;
&lt;p&gt;As you know from the title we will use two main tools to create ray-marcher, which are &lt;a href=&#34;https://love2d.org/&#34; target=&#34;_blank&#34;&gt;LÖVE&lt;/a&gt;, a free game engine, and &lt;a href=&#34;https://fennel-lang.org/&#34; target=&#34;_blank&#34;&gt;Fennel&lt;/a&gt; the programming language.
I&amp;rsquo;ve chosen Fennel, because it is a Lisp-like language, that compiles to Lua, and I&amp;rsquo;m quite a fan of Lisps.
But we also needed to draw somewhere, and I know no GUI toolkit for Lua.
But there is LÖVE - a game engine that runs Lua code, which is capable of running on all systems, thus a perfect candidate for our task.&lt;/p&gt;
&lt;p&gt;Installation steps may differ per operating system, so please refer to manuals&lt;sup id=&#34;fnref:3&#34;&gt;&lt;a href=&#34;#fn:3&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;3&lt;/a&gt;&lt;/sup&gt;&lt;sup&gt;, &lt;/sup&gt;&lt;sup id=&#34;fnref:4&#34;&gt;&lt;a href=&#34;#fn:4&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;4&lt;/a&gt;&lt;/sup&gt;.
At the time of writing this post, I&amp;rsquo;m using Fedora GNU/Linux, so for me it means:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ sudo dnf install love luarocks readline-devel
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ luarocks install --local fennel
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ luarocks install --local readline &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;# requires readline-devel&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;export&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;PATH&lt;/span&gt;=&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;$PATH&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;$HOME&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;/.luarocks/bin&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It&amp;rsquo;s better to permanently add &lt;code&gt;$HOME/luarocks/bin&lt;/code&gt; (or another path, if your installation differs) to the &lt;code&gt;PATH&lt;/code&gt; variable in your shell, in order to be able to use installed utilities without specifying the full path every time.
You can test if everything is installed correctly, by running &lt;code&gt;fennel&lt;/code&gt; in your command line.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ fennel
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Welcome to Fennel 0.5.0 on Lua 5.3!
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Use (doc something) to view documentation.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;gt;&amp;gt; (+ 1 2 3)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;6
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;For other distributions, installation steps may vary, and for Windows, I think it&amp;rsquo;s safe to skip the &lt;code&gt;readline&lt;/code&gt; part, which is fully optional but makes editing in a REPL a bit more comfortable.&lt;/p&gt;
&lt;p&gt;Once everything is installed, let&amp;rsquo;s create the project directory and the &lt;code&gt;main.fnl&lt;/code&gt; file, where we will write our code.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ mkdir love_raymarching
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;cd&lt;/span&gt; love_raymarching
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ touch main.fnl
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And that&amp;rsquo;s it!
We can test if everything works by adding this code to &lt;code&gt;main.fnl&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.draw&lt;/span&gt; []
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.graphics.print&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;It works!&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now we can compile it with &lt;code&gt;fennel --compile main.fnl &amp;gt; main.lua&lt;/code&gt;, thus producing the &lt;code&gt;main.lua&lt;/code&gt; file, and run &lt;code&gt;love .&lt;/code&gt; (dot is intentional, it indicates current directory).&lt;/p&gt;
&lt;p&gt;A window should appear, with white text &lt;code&gt;It works!&lt;/code&gt; in the upper left corner:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2020-10-15-raymarching-with-lua-and-love/love-works.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;Now we can begin implementing our ray marcher.&lt;/p&gt;
&lt;h2 id=&#34;scene-setup&#34;&gt;Scene setup&lt;/h2&gt;
&lt;p&gt;Just as in raycaster, we need a camera that will shoot rays, and some objects to look at.
Let&amp;rsquo;s begin by creating a camera object, that will store coordinates and rotation information.
We can do so, by using &lt;code&gt;var&lt;/code&gt; to declare a variable that is local to our file, and that we can later change with &lt;code&gt;set&lt;/code&gt;&lt;sup id=&#34;fnref:5&#34;&gt;&lt;a href=&#34;#fn:5&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;5&lt;/a&gt;&lt;/sup&gt;:&lt;/p&gt;
&lt;p&gt;&lt;a id=&#34;code-snippet--camera-unit&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;var &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;camera&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:pos&lt;/span&gt; [0.0 0.0 0.0]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:x-rotate&lt;/span&gt; 0.0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:z-rotate&lt;/span&gt; 0.0})
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;blockquote&gt;
&lt;p&gt;For those unfamiliar with Lisps, and especially Clojure, let me quickly explain what this syntax is.
If you know this stuff, feel free to &lt;a href=&#34;#org-target--end-of-syntax-explanation&#34;&gt;skip this part&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We start by using a &lt;code&gt;var&lt;/code&gt; special form, that binds a value to a name like this: &lt;code&gt;(var name value)&lt;/code&gt;.
So if we start the REPL, using the &lt;code&gt;fennel&lt;/code&gt; command in the shell, and write &lt;code&gt;(var a 40)&lt;/code&gt;, a new variable &lt;code&gt;a&lt;/code&gt; will be created.
We then can check, that it has the desired value by typing &lt;code&gt;a&lt;/code&gt;, and pressing return:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;var &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; 40)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;40
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We can then alter the contents of this variable by using &lt;code&gt;set&lt;/code&gt; special form, which works like this &lt;code&gt;(set name new-value)&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; 2))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;42
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now to curly and square brackets.
Everything enclosed in curly braces is a hashmap.
We can use any Lua value as our key, and the most common choice is a string, but Fennel has additional syntax for defining keys - a colon followed by a word: &lt;code&gt;:a&lt;/code&gt;.
This is called a keyword, and in Fennel, it is essentially the same as &lt;code&gt;&amp;quot;a&amp;quot;&lt;/code&gt;, but we don&amp;rsquo;t need to write a pair of quotes.
However, keywords can&amp;rsquo;t contain spaces and some other symbols.&lt;/p&gt;
&lt;p&gt;So writing this &lt;code&gt;{:a 0 :b 2 :c :hello}&lt;/code&gt; in the REPL will make a new table, that holds three key-value pairs, which we can later get with another syntax - the dot &lt;code&gt;.&lt;/code&gt;.
Combining it with &lt;code&gt;var&lt;/code&gt;, we can see that it works:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;var &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;m&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:a&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:b&lt;/span&gt; 2 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:c&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:hello&lt;/span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;m&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:b&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;2
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;There&amp;rsquo;s also a shorthand for this syntax, that is, we can type &lt;code&gt;m.b&lt;/code&gt; and access the &lt;code&gt;:b&lt;/code&gt; key&amp;rsquo;s value:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;m.b&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;m.c&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;hello&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Notice that even though we&amp;rsquo;ve specified the value for &lt;code&gt;:c&lt;/code&gt; as &lt;code&gt;:hello&lt;/code&gt;, the REPL printed it to us as &lt;code&gt;&amp;quot;hello&amp;quot;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;We&amp;rsquo;re left with square brackets now, and this is a plain simple vector.
It can grow and shrink, and store any Lua values in it:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; [0 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:a&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;b c&amp;#34;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;] &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[0 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;a&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;b c&amp;#34;&lt;/span&gt; #&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;function&lt;/span&gt;&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; 0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x56482230e090&amp;gt;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;However Lua doesn&amp;rsquo;t really have vectors or arrays, and it utilizes tables for this, where keys are simply indexes.
So the code above is equivalent to this Fennel expression &lt;code&gt;{1 0 2 &amp;quot;a&amp;quot; 3 &amp;quot;b c&amp;quot; 4 (fn [x] x)}&lt;/code&gt;, but we can use square brackets for convenience.&lt;/p&gt;
&lt;p&gt;Note, that we can combine indexed tables (vectors) and ordinary tables (hashmaps) together.
We can do it as shown above, by specifying indexes as keys, or defining a vector var and &lt;code&gt;set&lt;/code&gt; a key in it to some value:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;var &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;v&lt;/span&gt; [0 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:a&lt;/span&gt;])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;v.a&lt;/span&gt; 3)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;v&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:a&lt;/span&gt; 3
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; 1 0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; 2 1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; 3 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;a&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/blockquote&gt;
&lt;p&gt;&lt;span class=&#34;org-target&#34; id=&#34;org-target--end-of-syntax-explanation&#34;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;So camera is essentially a &lt;a href=&#34;https://www.lua.org/pil/2.5.html&#34; target=&#34;_blank&#34;&gt;Lua table&lt;/a&gt;, that stores keys &lt;code&gt;:pos&lt;/code&gt;, &lt;code&gt;:x-rotate&lt;/code&gt;, and &lt;code&gt;:y-rotate&lt;/code&gt;, each storing a respective value.
We use a vector as our position, and two floats as our rotation angles.
Now we can make objects, but before that, we need a scene to store those objects:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;var &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;scene&lt;/span&gt; [])
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Yep, that&amp;rsquo;s our scene.
Nothing fancy, simply an empty vector to which we will later add objects.&lt;/p&gt;
&lt;p&gt;Now we can create these objects, so let&amp;rsquo;s start with perhaps the simplest one - a sphere.
And I&amp;rsquo;ll also briefly explain what makes raymarching different from other methods of creating 3D graphics.&lt;/p&gt;
&lt;h3 id=&#34;creating-objects&#34;&gt;Creating objects&lt;/h3&gt;
&lt;p&gt;What is a sphere?
That depends on the domain, we&amp;rsquo;re working in.
Let&amp;rsquo;s open up &lt;a href=&#34;https://www.blender.org/&#34; target=&#34;_blank&#34;&gt;Blender&lt;/a&gt;, remove the default cube, and create sphere with &lt;kbd&gt;Shift+a&lt;/kbd&gt;, Mesh, UV Sphere:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2020-10-15-raymarching-with-lua-and-love/blender-uv-sphere.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;To me, this looks nothing like a sphere, because it consists of rectangles.
However, if we subdivide the surface, we can get a more correct representation:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2020-10-15-raymarching-with-lua-and-love/blender-uv-sphere-subdivided.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;This looks more like a sphere, but this is still just an approximation.
Theoretically, if we move very close to it, we will see the edges and corners, especially with flat shading.
Also, each subdivision adds more points, and it gets more and more expensive to compute:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2020-10-15-raymarching-with-lua-and-love/subdivisions.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;We have to make these trade-offs because we don&amp;rsquo;t need very accurate spheres when we need real-time processing.
But raymarching doesn&amp;rsquo;t have this limitation, because the sphere in raymarching is defined by the point and radius length.
Which we can then work with by using the signed distance function.&lt;/p&gt;
&lt;p&gt;So let&amp;rsquo;s create a function, that will produce a sphere:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sphere&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;radius&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pos&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;color&lt;/span&gt;] &lt;span style=&#34;&#34;&gt;➊&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;z&lt;/span&gt;] &lt;span style=&#34;&#34;&gt;➋&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pos&lt;/span&gt; [0 0 0])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;r&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;g&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt;] (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;color&lt;/span&gt; [1 1 1])]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:radius&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;radius&lt;/span&gt; 5)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:pos&lt;/span&gt; [(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; 0) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt; 0) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;z&lt;/span&gt; 0)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:color&lt;/span&gt; [(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;r&lt;/span&gt; 0) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;g&lt;/span&gt; 0) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt; 0)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:sdf&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sphere-distance&lt;/span&gt; &lt;span style=&#34;&#34;&gt;➌&lt;/span&gt;}))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;There&amp;rsquo;s a lot of stuff going on, so let&amp;rsquo;s dive into it.&lt;/p&gt;
&lt;p&gt;This is a so-called constructor - a function, that takes some parameters and constructs an object with these parameters applied, then returns it.
In most typed languages we would define a class, or structure to represent this object, however, in Fennel (and hence in Lua) we can just use a table.
And this is my favorite part of such languages.&lt;/p&gt;
&lt;p&gt;So we used &lt;code&gt;fn&lt;/code&gt; special form to create a function named &lt;code&gt;sphere&lt;/code&gt;, that takes three parameters: &lt;code&gt;radius&lt;/code&gt;, position in space &lt;code&gt;pos&lt;/code&gt;, and &lt;code&gt;color&lt;/code&gt; ➊.
Then we see another special form &lt;code&gt;let&lt;/code&gt;.
It is used to introduce locally scoped variables and has another nice property - destructuring ➋.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Let&amp;rsquo;s quickly understand how &lt;code&gt;let&lt;/code&gt; works in this case.
If you know how destructuring works, you can &lt;a href=&#34;#org-target--end-of-let-breakdown&#34;&gt;skip this part&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s a simple example:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; 1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt; 2]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;3
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We&amp;rsquo;ve introduced two local variables &lt;code&gt;a&lt;/code&gt; and &lt;code&gt;b&lt;/code&gt;, which hold values &lt;code&gt;1&lt;/code&gt; and &lt;code&gt;2&lt;/code&gt; respectively.
Then we computed their sum and returned it as a result.&lt;/p&gt;
&lt;p&gt;This is good, but what if we wanted to compute a sum of three vector elements multiplied by &lt;code&gt;b&lt;/code&gt;?
Let&amp;rsquo;s put a vector into &lt;code&gt;a&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; [1 2 3]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt; 2]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;???&amp;gt;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;There are many ways to do this, such as &lt;code&gt;reduce&lt;/code&gt; over a vector with a function that sums elements, or getting values from the vector in a loop and putting those into some local variable.
However, in the case of our project, we always know exactly how many elements there will be, so we can just take these out by indexes without any kind of loop:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; [1 2 3]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt; 2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a1&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; 1)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a2&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; 2)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a3&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; 3)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;* &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a1&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a2&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a3&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;12
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Yet, this is very verbose, and not really good.
We can make it a bit less verbose by skipping local variable definitions and using values directly in the sum:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; [1 2 3]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt; 2]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;print &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;value of the second element is &amp;#34;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; 2)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;* &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;+ &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; 1) (&lt;span style=&#34;font-weight:bold&#34;&gt;. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; 2) (&lt;span style=&#34;font-weight:bold&#34;&gt;. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; 3)) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;of&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;the&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;second &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;element&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;is&lt;/span&gt; 2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;12
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;However, again, this isn&amp;rsquo;t really great, as we have to repeat the same syntax three times, and what if we want to use the second value from the vector in several places?
Like here, I&amp;rsquo;ve added &lt;code&gt;print&lt;/code&gt; since I particularly about the second element&amp;rsquo;s value, and want to see it in the log, but I have to repeat myself and get the second element twice.
We could use a local binding for this, but we don&amp;rsquo;t want to do this manually.&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s where destructuring comes in handy, and trust me, it is a very handy thing.
We can specify a pattern, that is applied to our data, and binds variables for us like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a1&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a2&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a3&lt;/span&gt;] [1 2 3]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt; 2]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;print &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;value of the second element is &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a2&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;* &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a1&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a2&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a3&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;of&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;the&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;second &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;element&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;is&lt;/span&gt; 2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;12
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This works somewhat like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[1  2  3]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; ↓  ↓  ↓
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[a1 a2 a3]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This is much shorter than any of the previous examples and allows us to use any vector values in several places.&lt;/p&gt;
&lt;p&gt;We can also destructure maps like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;var &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;m&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:a-key&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:b-key&lt;/span&gt; 2})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:a-key&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:b-key&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt;} &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;m&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;3
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And this also has a shorthand for when the name of the key and the name of desired local binding will match:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;var &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;m&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:a&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:b&lt;/span&gt; 2})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[{&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt;} &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;m&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;3
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Which is even shorter.&lt;/p&gt;
&lt;p&gt;All this essentially boils down to this kind of Lua code:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- vector destructuring&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- (let [[a b] [1 2]] (+ a b))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; _0_ = {1, 2}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; a = _0_[1]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; b = _0_[2]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; (a + b)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- hashmap destructuring&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- (let [{: a : b} {:a 1 :b 2}] (+ a b))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; _0_ = {a = 1, b = 2}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; a = _0_[&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;a&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; b = _0_[&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;b&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; (a + b)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This is nothing special really, but this example still shows the power of Lisp&amp;rsquo;s macro system, in which destructuring is implemented.
But it gets really cool when we use this in function forms, as we will see later.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;span class=&#34;org-target&#34; id=&#34;org-target--end-of-let-breakdown&#34;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;If we were to call &lt;code&gt;(sphere)&lt;/code&gt; now, we would get an error, because we specified a value ➌ for a key &lt;code&gt;:sdf&lt;/code&gt;, that doesn&amp;rsquo;t yet exist.
SDF stands for &lt;a href=&#34;https://en.wikipedia.org/wiki/Signed_distance_function&#34; target=&#34;_blank&#34;&gt;Signed Distance Function&lt;/a&gt;.
That is a function, that will return the distance from a given point to an object.
The distance is positive when the point is outside of the object and negative when the point is inside the object.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s define an SDF for a sphere.
What&amp;rsquo;s great about spheres, is that to compute the distance to the sphere&amp;rsquo;s surface, we only need to compute the distance to the center of the sphere, and subtract the sphere&amp;rsquo;s radius from this distance.&lt;/p&gt;
&lt;img src=&#34;https://andreyor.st/ltximg/2020-10-15-raymarching-with-fennel-and-love_9184447246721f1ac8fa15ea8fc4c62e5817d1d9.svg&#34; alt=&#34;\[d(P,S)=\sqrt{(S_x-P_x)^2+(S_y-P_y)^2+(S_z-P_z)^2}-S_r\]&#34; class=&#34;org-svg&#34; /&gt;
&lt;p&gt;Let&amp;rsquo;s implement this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sqrt&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;math.sqrt&lt;/span&gt;) &lt;span style=&#34;&#34;&gt;➊&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sphere-distance&lt;/span&gt; [{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:pos&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sx&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sy&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sz&lt;/span&gt;] &lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;radius&lt;/span&gt;} [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;z&lt;/span&gt;]] &lt;span style=&#34;&#34;&gt;➋&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;- &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sqrt&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;+ &lt;/span&gt;(^ (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;- &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sx&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;) 2) (^ (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;- &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sy&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt;) 2) (^ (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;- &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sz&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;z&lt;/span&gt;) 2)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;radius&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;For &lt;a href=&#34;https://www.lua.org/gems/sample.pdf&#34; target=&#34;_blank&#34;&gt;performance reasons&lt;/a&gt; we declare &lt;code&gt;math.sqrt&lt;/code&gt; as a &lt;code&gt;local&lt;/code&gt; variable &lt;code&gt;sqrt&lt;/code&gt;, that holds function value, to avoid repeated table lookup.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;As was later pointed out, Luajit does optimize such calls, and there is no repeated lookup for method calls.
This is still true for plain Lua, so I&amp;rsquo;m going to keep this as is, but you can skip all these local definitions if you want and use methods directly.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;And at ➋ we again see destructuring, however not in the &lt;code&gt;let&lt;/code&gt; block, but in the function argument list.
What essentially happens here is this - function takes two parameters, the first of which is a hashmap, which must have a &lt;code&gt;:pos&lt;/code&gt; keyword associated with a vector of three numbers, and a &lt;code&gt;:radius&lt;/code&gt; keyword with a value.
The second parameter is simply a vector of three numbers.
We immediately destructured these parameters into a set of variables local to the function body.
Hashmap is being destructured into sphere position vector, which is immediately destructured to &lt;code&gt;sx&lt;/code&gt;, &lt;code&gt;sy&lt;/code&gt;, and &lt;code&gt;sz&lt;/code&gt;, and a &lt;code&gt;radius&lt;/code&gt; variable storing sphere&amp;rsquo;s radius.
Second parameter is destructured to &lt;code&gt;x&lt;/code&gt;, &lt;code&gt;y&lt;/code&gt;, and &lt;code&gt;z&lt;/code&gt;.
We then compute the resulting value by using the formula above.
However, Fennel and Lua only understand definitions in the order from the top to the bottom, so we need to define &lt;code&gt;sphere-distance&lt;/code&gt; before &lt;code&gt;sphere&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s test our function by passing several points and a sphere of radius 5:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sphere-distance&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sphere&lt;/span&gt; 5) [5 0 0])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;0.0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sphere-distance&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sphere&lt;/span&gt; 5) [0 15 0])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;10.0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sphere-distance&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sphere&lt;/span&gt; 5) [0 0 0])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;-5.0
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Great!
First, we check if we&amp;rsquo;re on the sphere&amp;rsquo;s surface, because the radius of our sphere is &lt;code&gt;5&lt;/code&gt;, and we&amp;rsquo;ve set &lt;code&gt;x&lt;/code&gt; coordinate to &lt;code&gt;5&lt;/code&gt; as well.
Next, we check if we&amp;rsquo;re &lt;code&gt;10&lt;/code&gt; something away from the sphere, and lastly, we check that we&amp;rsquo;re &lt;em&gt;inside&lt;/em&gt; the sphere because the sphere&amp;rsquo;s center and our point both are at the origin.&lt;/p&gt;
&lt;p&gt;But we also can call this function as a method with &lt;code&gt;:&lt;/code&gt; syntax:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sphere&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:sdf&lt;/span&gt; [0 0 0])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;-5
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This works because methods in Lua are syntactic sugar.
When we write &lt;code&gt;(s:sdf p)&lt;/code&gt; it is essentially equal to &lt;code&gt;(s.sdf s p)&lt;/code&gt;, and our distance function takes sphere as its first parameter, which allows us to utilize method syntax.&lt;/p&gt;
&lt;p&gt;Now we need a distance estimator - a function that will compute distances to all objects and will return the shortest one, so we could then safely extend our ray by this amount.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;DRAW-DISTANCE&lt;/span&gt; 1000)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;distance-estimator&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;point&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;scene&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;var &lt;/span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;min &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;DRAW-DISTANCE&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;var &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;color&lt;/span&gt; [0 0 0])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;each&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;object&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ipairs&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;scene&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;distance&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;object&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:sdf&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;point&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;when &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;&amp;lt; &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;distance&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;min&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;set min &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;distance&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;color&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;object&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:color&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;values&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;min &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;color&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This function will compute the distance to &lt;code&gt;each&lt;/code&gt; object in the &lt;code&gt;scene&lt;/code&gt; from given &lt;code&gt;point&lt;/code&gt;, using our signed distance functions, and will choose the minimum distance and the color of this ray.
Even though it makes little sense to return color from the distance-estimator, we&amp;rsquo;re doing this here because we don&amp;rsquo;t want to compute this whole process again just to get the color of the endpoint.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s check if this function works:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;distance-estimator&lt;/span&gt; [5 4 0] [(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sphere&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sphere&lt;/span&gt; 2 [5 7 0] [0 1 0])])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;1.0     [0 1 0]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It works, we obtained the distance to the second sphere, and its color because the point we specified was closer to this sphere than to the other.&lt;/p&gt;
&lt;p&gt;With the camera, object, a scene, and this function we have all we need to start shooting rays and rendering this on screen.&lt;/p&gt;
&lt;h2 id=&#34;marching-ray&#34;&gt;Marching ray&lt;/h2&gt;
&lt;p&gt;Just as in raycaster, we cast rays from the camera, but now we do it in 3D space.
In raycasting, our horizontal resolution was specified by a number of rays, and our vertical resolution was basically infinite.
For 3D this is not an option, so our resolution now depends on the 2D matrix of rays, instead of the 1D matrix.&lt;/p&gt;
&lt;p&gt;Quick math.
How many rays we&amp;rsquo;ll need to cast in order to fill up 512 by 448 pixels?
The answer is simple - multiply width and height and here&amp;rsquo;s the amount of rays you&amp;rsquo;ll need:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;* &lt;/span&gt;512 448)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;229376
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;A stunning &lt;code&gt;229376&lt;/code&gt; rays to march.
And each ray has to do many distance estimations as it marches away from the point.
Suddenly, all that micro-optimizations, like locals for functions do not feel that unnecessary.
Let&amp;rsquo;s hope for the best and that LÖVE will handle real-time rendering.
We can begin by creating a function that marches a single ray in the direction our camera looks.
But first, we need to define what we would use to specify coordinates, directions, and so on in our 3D space.&lt;/p&gt;
&lt;p&gt;My first attempt was to use &lt;a href=&#34;https://en.wikipedia.org/wiki/Spherical_coordinate_system&#34; target=&#34;_blank&#34;&gt;spherical coordinates&lt;/a&gt; to define ray direction and move points in 3D space relative to the camera.
However, it had a lot of problems, especially when looking at objects at angles different from 90 degrees.
Like here&amp;rsquo;s a screenshot of me looking at the sphere from the &amp;ldquo;front&amp;rdquo;:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2020-10-15-raymarching-with-lua-and-love/spherical-ok.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;And here&amp;rsquo;s when looking from &amp;ldquo;above&amp;rdquo;:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2020-10-15-raymarching-with-lua-and-love/spherical-not-ok.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;And when I added the cube object, I noticed a &lt;em&gt;slight&lt;/em&gt; fish-eye distortion effect:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2020-10-15-raymarching-with-lua-and-love/spherical-distortion.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;Which was not great at all.
So I&amp;rsquo;ve decided that I would remake everything with vectors, and make a proper camera, with a &amp;ldquo;look-at&amp;rdquo; point, will compute projection plane, and so on.&lt;/p&gt;
&lt;p&gt;And to do this we need to be able to work with vectors - add those, multiply, normalize, e.t.c.
I&amp;rsquo;ve wanted to refresh my knowledge on this topic, and decided not to use any existing library for vectors, and implement everything from scratch.
It&amp;rsquo;s not that hard.
Especially when we already have vectors in the language, and can destructure it to variables with ease.&lt;/p&gt;
&lt;p&gt;So we need these basic functions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;vec3&lt;/code&gt; - a constructor with some handy semantics,&lt;/li&gt;
&lt;li&gt;&lt;code&gt;vec-length&lt;/code&gt; - function that computes magnitude of vector,&lt;/li&gt;
&lt;li&gt;arithmetic functions, such as &lt;code&gt;vec-sub&lt;/code&gt;, &lt;code&gt;vec-add&lt;/code&gt;, and &lt;code&gt;vec-mul&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;and other unit vector functions, mainly &lt;code&gt;normalize&lt;/code&gt;, &lt;code&gt;dot-product&lt;/code&gt;, and &lt;code&gt;cross-product&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here&amp;rsquo;s the source code of each of these functions:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vec3&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;z&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;not &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;) [0 0 0]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;and &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;not &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;not &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;z&lt;/span&gt;)) [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;z&lt;/span&gt; 0)]))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vec-length&lt;/span&gt; [[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;z&lt;/span&gt;]]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sqrt&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;+ &lt;/span&gt;(^ &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; 2) (^ &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt; 2) (^ &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;z&lt;/span&gt; 2))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vec-sub&lt;/span&gt; [[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x0&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y0&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;z0&lt;/span&gt;] [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x1&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y1&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;z1&lt;/span&gt;]]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  [(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;- &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x0&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x1&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;- &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y0&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y1&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;- &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;z0&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;z1&lt;/span&gt;)])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vec-add&lt;/span&gt; [[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x0&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y0&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;z0&lt;/span&gt;] [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x1&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y1&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;z1&lt;/span&gt;]]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  [(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x0&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x1&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y0&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y1&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;z0&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;z1&lt;/span&gt;)])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vec-mul&lt;/span&gt; [[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x0&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y0&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;z0&lt;/span&gt;] [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x1&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y1&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;z1&lt;/span&gt;]]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  [(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;* &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x0&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x1&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;* &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y0&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y1&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;* &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;z0&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;z1&lt;/span&gt;)])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;norm&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;v&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;len&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vec-length&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;v&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;z&lt;/span&gt;] &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;v&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    [(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;/ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;len&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;/ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;len&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;/ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;z&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;len&lt;/span&gt;)]))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dot&lt;/span&gt; [[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x0&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y0&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;z0&lt;/span&gt;] [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x1&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y1&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;z1&lt;/span&gt;]]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;+ &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;* &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x0&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x1&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;* &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y0&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y1&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;* &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;z0&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;z1&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cross&lt;/span&gt; [[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x0&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y0&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;z0&lt;/span&gt;] [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x1&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y1&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;z1&lt;/span&gt;]]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  [(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;- &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;* &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y0&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;z1&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;* &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;z0&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y1&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;- &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;* &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;z0&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x1&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;* &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x0&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;z1&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;- &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;* &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x0&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y1&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;* &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y0&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x1&lt;/span&gt;))])
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Since we already know how destructuring works, it&amp;rsquo;s not hard to see what these functions do.
&lt;code&gt;vec3&lt;/code&gt;, however, has some logic in it, and you can notice that &lt;code&gt;if&lt;/code&gt; has three outcomes.
&lt;code&gt;if&lt;/code&gt; in Fennel is more like &lt;code&gt;cond&lt;/code&gt; in other lisps, which means that we can specify as many &lt;code&gt;else if&lt;/code&gt; as we want.&lt;/p&gt;
&lt;p&gt;Therefore, calling it without arguments produces a zero-length vector &lt;code&gt;[0 0 0]&lt;/code&gt;.
If called with one argument, it returns a vector where each coordinate is set to this argument: &lt;code&gt;(vec 3)&lt;/code&gt; will produce &lt;code&gt;[3 3 3]&lt;/code&gt;.
In other cases we either specified or not specified &lt;code&gt;z&lt;/code&gt;, so we can simply create a vector with &lt;code&gt;x&lt;/code&gt;, &lt;code&gt;y&lt;/code&gt;, and either &lt;code&gt;0&lt;/code&gt; or &lt;code&gt;z&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;You may wonder, why this is defined as functions, and why I didn&amp;rsquo;t implement operator overloading, so we could simply use &lt;code&gt;+&lt;/code&gt; or &lt;code&gt;*&lt;/code&gt; to compute values?
I&amp;rsquo;ve tried this, however, this is extremely slow, since on each operation we have to do a lookup in meta-table, and this is like really slow.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s a quick benchmark:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;macro&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;time &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;body&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  `(&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clock#&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;os.clock&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;start#&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clock#&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res#&lt;/span&gt; ,&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;body&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;end#&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clock#&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;print &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Elapsed &amp;#34;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;* &lt;/span&gt;1000 (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;- &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;end#&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;start#&lt;/span&gt;)) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; ms&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res#&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; operator overloading&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;var &lt;/span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;vector &lt;/span&gt;{})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vector.__index&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vector&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vec3-meta&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;z&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;setmetatable&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;z&lt;/span&gt;] &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vector&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vector.__add&lt;/span&gt; [[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x1&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y1&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;z1&lt;/span&gt;] [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x2&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y2&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;z2&lt;/span&gt;]]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vec3-meta&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x1&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x2&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y1&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y2&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;z1&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;z2&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;v0&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vec3-meta&lt;/span&gt; 1 1 1))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;time &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;for &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; 0 1000000] (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;v0&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;v0&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;v0&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;v0&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; basic functions&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vec3&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;z&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;z&lt;/span&gt;])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vector-add&lt;/span&gt; [[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x1&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y1&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;z1&lt;/span&gt;] [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x2&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y2&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;z2&lt;/span&gt;]]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vec3&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x1&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x2&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y1&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y2&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;z1&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;z2&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;v1&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vec3&lt;/span&gt; 1 1 1))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;time &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;for &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; 0 1000000] (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vector-add&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vector-add&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vector-add&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;v1&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;v1&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;v1&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;v1&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If we run it with &lt;code&gt;lua&lt;/code&gt; interpreter, we&amp;rsquo;ll see the difference:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ fennel --compile test.fnl | lua
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Elapsed 1667.58 ms
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Elapsed 1316.078 ms
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Testing this with &lt;code&gt;luajit&lt;/code&gt; claims that this way is actually faster, &lt;strong&gt;however&lt;/strong&gt;, I&amp;rsquo;ve experienced a major slowdown in the renderer - everything ran about 70% slower, according to the frame per second count.
So functions are okay, even though are much more verbose.&lt;/p&gt;
&lt;p&gt;Now we can define a &lt;code&gt;march-ray&lt;/code&gt; function:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;move-point&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;point&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dir&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;distance&lt;/span&gt;] &lt;span style=&#34;&#34;&gt;➊&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vec-add&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;point&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vec-mul&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dir&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vec3&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;distance&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;MARCH-DELTA&lt;/span&gt; 0.0001)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;MAX-STEPS&lt;/span&gt; 500)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;march-ray&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;origin&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;direction&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;scene&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;var &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;steps&lt;/span&gt; 0)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;var &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;distance&lt;/span&gt; 0)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;var &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;color&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;var &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;not-done?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;true&lt;/span&gt;) &lt;span style=&#34;&#34;&gt;➋&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;while&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;not-done?&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;&#34;&gt;➍&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;new-distance&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;new-color&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;-&amp;gt; &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;origin&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                             (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;move-point&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;direction&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;distance&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                             (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;distance-estimator&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;scene&lt;/span&gt;))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;when &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;&amp;lt; &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;new-distance&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;MARCH-DELTA&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;distance&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;DRAW-DISTANCE&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;&amp;gt; &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;steps&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;MAX-STEPS&lt;/span&gt;) &lt;span style=&#34;&#34;&gt;➌&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;not-done?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;false&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;distance&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;distance&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;new-distance&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;color&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;new-color&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;steps&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;steps&lt;/span&gt; 1))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;values&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;distance&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;color&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;steps&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Not much, but we have some things to discuss.&lt;/p&gt;
&lt;p&gt;First, we define a function to move points in 3D space ➊.
It accepts a &lt;code&gt;point&lt;/code&gt;, which is a three-dimensional vector, a direction vector &lt;code&gt;dir&lt;/code&gt;, which must be normalized, and a &lt;code&gt;distance&lt;/code&gt;.
We then multiply the direction vector by a vector that consists of our distances and add it to the point.
Simple and easy.&lt;/p&gt;
&lt;p&gt;Next, we define several constants, and the &lt;code&gt;march-ray&lt;/code&gt; function itself.
It Defines some local vars, that hold initial values, and uses a &lt;code&gt;while&lt;/code&gt; loop to march a given ray enough times.
You can notice, that at ➋ we created a &lt;code&gt;not-done?&lt;/code&gt; var, that holds &lt;code&gt;true&lt;/code&gt; value, and then use it in the &lt;code&gt;while&lt;/code&gt; loop as our test.
And you also can notice that at ➌ we have a test, in case of which we &lt;code&gt;set&lt;/code&gt; &lt;code&gt;not-done?&lt;/code&gt; to &lt;code&gt;false&lt;/code&gt; and exit the loop.
So you may wonder, why not use &lt;code&gt;for&lt;/code&gt; loop instead?
Lua supports index-based &lt;code&gt;for&lt;/code&gt; loops.
Fennel also has support for these.
So why use &lt;code&gt;while&lt;/code&gt; with a &lt;code&gt;variable&lt;/code&gt;?&lt;/p&gt;
&lt;p&gt;Because Fennel has no &lt;code&gt;break&lt;/code&gt; special form for some reason.&lt;/p&gt;
&lt;p&gt;&lt;span class=&#34;org-target&#34; id=&#34;org-target--break-rant&#34;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Here&amp;rsquo;s a little rant.
You &lt;a href=&#34;#org-target--end-of-break-rant&#34;&gt;can skip it&lt;/a&gt; if you&amp;rsquo;re not interested in me making unconfirmed inferences about Fennel :).&lt;/p&gt;
&lt;p&gt;I think that Fennel doesn&amp;rsquo;t support &lt;code&gt;break&lt;/code&gt; because Fennel is influenced by Clojure (correct me if I&amp;rsquo;m wrong), and Clojure doesn&amp;rsquo;t have &lt;code&gt;break&lt;/code&gt; either.
However, looping in Clojure is a bit more controllable, as we &lt;em&gt;choose&lt;/em&gt; when we want to go to the next iteration:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;loop &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; 0]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; do stuff&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;when &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;&amp;lt; &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; 10)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;recur&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; 1))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Which means that &lt;code&gt;when&lt;/code&gt; &lt;code&gt;i&lt;/code&gt; is less then &lt;code&gt;10&lt;/code&gt; I want you to perform another iteration.&lt;/p&gt;
&lt;p&gt;In Fennel, however, the concept isn&amp;rsquo;t quite like this, because we have to define a &lt;code&gt;var&lt;/code&gt; explicitly, and put it into the &lt;code&gt;while&lt;/code&gt; test position:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;var &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; 0)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;while&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;&amp;lt; &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; 10)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; do stuff&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; 1)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You may not see the difference, but I do.
This also can be trivially expressed as a &lt;code&gt;for&lt;/code&gt; loop: &lt;code&gt;(for [i 0 10] (do-stuff))&lt;/code&gt;.
However, not every construct can be defined as &lt;code&gt;for&lt;/code&gt; loop, when we don&amp;rsquo;t have &lt;code&gt;break&lt;/code&gt;.
And in Clojure we don&amp;rsquo;t have to declare a variable outside the loop, since &lt;code&gt;loop&lt;/code&gt; does it for us, but the biggest difference is here:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;loop &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; 0]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;when &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;&amp;lt; &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; 100)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;&amp;lt; &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;some-foo&lt;/span&gt;) 1000))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;recur&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;inc &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Notice, that we&amp;rsquo;re looping until &lt;code&gt;i&lt;/code&gt; reaches &lt;code&gt;100&lt;/code&gt;, &lt;strong&gt;or&lt;/strong&gt; until &lt;code&gt;some-foo&lt;/code&gt; returns something greater than 1000.
We can easily express this as &lt;code&gt;for&lt;/code&gt; loop in Lua:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;for&lt;/span&gt; i = 0, 100 &lt;span style=&#34;font-weight:bold&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; some_foo() &amp;gt; 1000 &lt;span style=&#34;font-weight:bold&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;font-weight:bold&#34;&gt;break&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;However, we can&amp;rsquo;t do the same in Fennel, because there&amp;rsquo;s no &lt;code&gt;break&lt;/code&gt;.
In this case we could define &lt;code&gt;i&lt;/code&gt; var, put &lt;code&gt;some_foo() &amp;lt; 1000&lt;/code&gt; to the &lt;code&gt;while&lt;/code&gt; loop test, and then use break when &lt;code&gt;i&lt;/code&gt; reaches &lt;code&gt;100&lt;/code&gt;, like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;var &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; 0)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;while&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;&amp;lt; &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; 100)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;&amp;lt; &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;some-foo&lt;/span&gt;) 1000))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; 1)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This is almost like the Clojure example, and you may wonder why I complain, but in the case of &lt;code&gt;march-ray&lt;/code&gt; function, we can&amp;rsquo;t do this either!
Because the function we call returns multiple values, we need to destructure ➍ to be able to test those.
Or in some loops, such a function may depend on the context of the loop, so it has to be inside the loop, not in the test.&lt;/p&gt;
&lt;p&gt;So not having &lt;code&gt;break&lt;/code&gt;, or the ability to control when to go to the next iteration is a serious disadvantage.
Yes, Clojure&amp;rsquo;s &lt;code&gt;recur&lt;/code&gt; is also limited, since it must be in the tail position, so you can&amp;rsquo;t use it as &lt;code&gt;continue&lt;/code&gt; or something like that.
But it&amp;rsquo;s still a bit more powerful construct.
I&amp;rsquo;ve actually thought about writing a &lt;code&gt;loop&lt;/code&gt; macro, but it seems that it&amp;rsquo;s not as easy to do in Fennel, as in Clojure, because Fennel lacks some inbuilt functions to manipulate sequences.
I mean it&amp;rsquo;s totally doable, but requires way too much work compared to defining a Boolean &lt;code&gt;var&lt;/code&gt; and setting it in the loop.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;span class=&#34;org-target&#34; id=&#34;org-target--end-of-break-rant&#34;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;At ➍ we see the syntax that I didn&amp;rsquo;t cover before: &lt;code&gt;(let [(a b) (foo)] ...)&lt;/code&gt;.
Many of us, who are familiar with Lisp and especially Racket may be confused.
You see, in Racket, and other Scheme implementations (that allow using different kinds of parentheses) &lt;code&gt;let&lt;/code&gt; has this kind of syntax:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-racket&#34; data-lang=&#34;racket&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;let&lt;/span&gt; [(a 1)   &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; In Scheme square brackets around bindings&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (b 41)] &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; are replaced with parentheses&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;+&lt;/span&gt; a b))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Or more generally, &lt;code&gt;(let ((name1 value1) (name2 value2) ...) body)&lt;/code&gt;.
However, in the case of the &lt;code&gt;march-ray&lt;/code&gt; function, we see a similar form, except the second element has no value specified.
This is again a valid syntax in some lisps (Common Lisp, for example), as we can make a binding that holds &lt;em&gt;nothing&lt;/em&gt; and later &lt;code&gt;set&lt;/code&gt; it, but this is not what happens in this code, as we don&amp;rsquo;t use &lt;code&gt;foo&lt;/code&gt; at all:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;foo&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And, since in Fennel we don&amp;rsquo;t need parentheses, and simply specify bindings as a vector &lt;code&gt;[name1 value1 name2 value2 ...]&lt;/code&gt;, another possible confusion may happen.
You may think that &lt;code&gt;(a b)&lt;/code&gt; is a function call that returns a &lt;code&gt;name&lt;/code&gt;, and &lt;code&gt;(foo)&lt;/code&gt; is a function call that produces a &lt;code&gt;value&lt;/code&gt;.
But then we &lt;strong&gt;somehow&lt;/strong&gt; use &lt;code&gt;a&lt;/code&gt; and &lt;code&gt;b&lt;/code&gt;.
What is happening here?&lt;/p&gt;
&lt;p&gt;But this is just another kind of destructuring available in Fennel.&lt;/p&gt;
&lt;p&gt;Lua has 1 universal data type, called a table.
However Lua doesn&amp;rsquo;t have any special syntax for destructuring, so when a function needs to return several values, you have two options.
First, you can return a table:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;returns_table&lt;/span&gt;(a, b)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; {a, b}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;But the user of such function will have to get values out of the table themselves:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; res = returns_table(1, 2)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; a, b = unpack(res) &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- or use indexes, e.g. local a = res[1]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;print(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;a: &amp;#34;&lt;/span&gt; .. a .. &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;, b: &amp;#34;&lt;/span&gt; .. b)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- a: 1, b: 2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;But this is extra work, and it ties values together into a data structure, which may not be really good for you.
So Lua has a shorthand for this - you can return multiple values:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;returns_values&lt;/span&gt;(a, b)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; a, b
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; a, b = returns_values(1, 2)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;print(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;a: &amp;#34;&lt;/span&gt; .. a .. &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;, b: &amp;#34;&lt;/span&gt; .. b)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- a: 1, b: 2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This is shorter and more concise.
Fennel also support this multivalue return with &lt;code&gt;values&lt;/code&gt; special form:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;returns-values&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;values&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This is equivalent to the previous code, but how do we use these values?
All binding forms in Fennel support destructuring, so we can write this as:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;returns-values&lt;/span&gt; 1 2))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;print &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;a: &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;, b: &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; a: 1, b: 2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Same can be done with vectors or maps when defining, &lt;code&gt;local&lt;/code&gt;, &lt;code&gt;var&lt;/code&gt;, or &lt;code&gt;global&lt;/code&gt; variables:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt;] (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;returns-vector&lt;/span&gt;)) &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; returns [1 2 3]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;var &lt;/span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:z&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;z&lt;/span&gt;} (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;returns-map&lt;/span&gt;)) &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; returns {:x 1 :y 2 :z 3}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;global&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bar&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;baz&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;returns-values&lt;/span&gt;)) &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; returns (values 1 2)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And all of this works in &lt;code&gt;let&lt;/code&gt; or when defining a function!&lt;/p&gt;
&lt;p&gt;OK.
We&amp;rsquo;ve defined a function that marches a ray, now we need to shoot some!&lt;/p&gt;
&lt;h2 id=&#34;shooting-rays&#34;&gt;Shooting rays&lt;/h2&gt;
&lt;p&gt;As with math functions, let&amp;rsquo;s define some local definitions somewhere at the top of the file:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love-points&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.graphics.points&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love-dimensions&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.graphics.getDimensions&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love-set-color&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.graphics.setColor&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love-key-pressed?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.keyboard.isDown&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love-get-joysticks&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.joystick.getJoysticks&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This is pretty much all we&amp;rsquo;ll need from LÖVE - two functions to draw colored pixels, one function to get the resolution of the window, and input handling functions for the keyboard and gamepad.
We&amp;rsquo;ll also define some functions in &lt;code&gt;love&lt;/code&gt; &lt;em&gt;namespace table&lt;/em&gt; (IDK how it is called properly in Lua, because it is a table that acts like a namespace) - &lt;code&gt;love.load&lt;/code&gt;, &lt;code&gt;love.draw&lt;/code&gt;, and others along the way.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s begin by initializing our window:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;window-width&lt;/span&gt; 512)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;window-height&lt;/span&gt; 448)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;window-flags&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:resizable&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;true&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:vsync&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;false&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:minwidth&lt;/span&gt; 256 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:minheight&lt;/span&gt; 224})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.load&lt;/span&gt; []
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.window.setTitle&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;LÖVE Raymarching&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.window.setMode&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;window-width&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;window-height&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;window-flags&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This will set our window&amp;rsquo;s default width and height to &lt;code&gt;512&lt;/code&gt; by &lt;code&gt;448&lt;/code&gt; pixels and set the minimum width and height to &lt;code&gt;256&lt;/code&gt; by &lt;code&gt;224&lt;/code&gt; pixels respectively.
We also add title &lt;code&gt;&amp;quot;LÖVE Raymarching&amp;quot;&lt;/code&gt; to our window, but it is fully optional.&lt;/p&gt;
&lt;p&gt;Now we can set &lt;code&gt;love.draw&lt;/code&gt; function, which will shoot 1 ray per pixel, and draw that pixel with the appropriate color.
However, we need a way of saying in which direction we want to shoot our ray.
To define the direction we will first need a projection plane and a look-at point.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s create a look-at point as a simple zero vector &lt;code&gt;[0 0 0]&lt;/code&gt; for now:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lookat&lt;/span&gt; [0 0 0])
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now we need to understand how we define our projection plane.
In our case, a projection plane is a plane that is our screen, and our camera is some distance away from the screen.
We also want to be able to change our field of view, or FOV for short, so we need a way of computing the distance to projection, since the closer we are to the projection plane, the wider our field of view:&lt;/p&gt;
&lt;figure class=&#34;invertable&#34;&gt;&lt;img src=&#34;https://andreyor.st/2020-10-15-raymarching-with-lua-and-love/distances-to-projection-plane.svg&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;We can easily compute the distance if we have an angle, which we also can define as a &lt;code&gt;var&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;var &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fov&lt;/span&gt; 60)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now we can compute our projection distance (PD), by using this formula:&lt;/p&gt;
&lt;img src=&#34;https://andreyor.st/ltximg/2020-10-15-raymarching-with-fennel-and-love_32b13e61133b5f79cc4ee40a35afa13e72a8e735.svg&#34; alt=&#34;\[PD=\frac{1}{\tan{(fov/2)}}\]&#34; class=&#34;org-svg&#34; /&gt;
&lt;p&gt;Where &lt;code&gt;fov&lt;/code&gt; is in Radians.
And to compute radians we&amp;rsquo;ll need this constant:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;RAD&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;/ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;math.pi&lt;/span&gt; 180.0))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now we can transform any angle into radians by multiplying it by this value.&lt;/p&gt;
&lt;p&gt;At this point, we know what is the distance to our projection plane, but we don&amp;rsquo;t know its size and position.
First, we need a ray origin (&lt;code&gt;RO&lt;/code&gt;), and we already have it as our camera, so our &lt;code&gt;ro&lt;/code&gt; will be equal to the current value of &lt;code&gt;camera.pos&lt;/code&gt;.
Next, we need a look-at point, and we have it as a &lt;code&gt;lookat&lt;/code&gt; variable, which is set to &lt;code&gt;[0 0 0]&lt;/code&gt;.
Now we can define a direction vector, that will specify our &lt;em&gt;forward direction&lt;/em&gt;:&lt;/p&gt;
&lt;img src=&#34;https://andreyor.st/ltximg/2020-10-15-raymarching-with-fennel-and-love_ff94fdb25712c79044bfb62102c21558e710b0cc.svg&#34; alt=&#34;\[\overrightarrow{F}=normalize(\overrightarrow{lookat}-\overrightarrow{ro})\]&#34; class=&#34;org-svg&#34; /&gt;
&lt;p&gt;And with this vector &lt;code&gt;F&lt;/code&gt; if we move our point the distance that we&amp;rsquo;ve computed previously, we&amp;rsquo;ll navigate the center of our projection plane, which we can call &lt;code&gt;C&lt;/code&gt;:&lt;/p&gt;
&lt;img src=&#34;https://andreyor.st/ltximg/2020-10-15-raymarching-with-fennel-and-love_c12545f0f21b7028183e58e928fa64ce358535e6.svg&#34; alt=&#34;\[\overrightarrow{C}=\overrightarrow{RO}+\overrightarrow{F}\cdot{PD}\]&#34; class=&#34;org-svg&#34; /&gt;
&lt;p&gt;The last thing we need to know, in order to get our orientation in space, is where is &lt;em&gt;up&lt;/em&gt; and &lt;em&gt;right&lt;/em&gt;.
We can compute this by specifying an upward vector and taking a cross product of it and our forward vector, thus producing a vector that is perpendicular to both of these vectors, and pointing to the right.
To do this we need an up vector, which we define like this &lt;code&gt;[0 0 -1]&lt;/code&gt;.
You may wonder why it is defined with the z-axis negative, but this is done so positive z values actually go up as we look from the camera, and the right is to the right.
We then compute the right vector as follows:&lt;/p&gt;
&lt;img src=&#34;https://andreyor.st/ltximg/2020-10-15-raymarching-with-fennel-and-love_bb975b5a9462d9d4d29cb464c294a9c493a095d2.svg&#34; alt=&#34;\[\overrightarrow{R}=normalize(cross(\overrightarrow{F},\begin{bmatrix}0&amp;amp;amp;0&amp;amp;amp;-1\end{bmatrix}))\]&#34; class=&#34;org-svg&#34; /&gt;
&lt;p&gt;And the up vector &lt;code&gt;U&lt;/code&gt; is a cross product of &lt;code&gt;R&lt;/code&gt; and &lt;code&gt;F&lt;/code&gt;. Let&amp;rsquo;s write this down as in &lt;code&gt;love.draw&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.draw&lt;/span&gt; []
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;width&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;height&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love-dimensions&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;projection-distance&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;/ &lt;/span&gt;1 (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tan&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;* &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;/ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fov&lt;/span&gt; 2) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;RAD&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ro&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;camera.pos&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;norm&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vec-sub&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lookat&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ro&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vec-add&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ro&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vec-mul&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vec3&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;projection-distance&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;r&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;norm&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cross&lt;/span&gt; [0 0 -1] &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;u&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cross&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;r&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;)) &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; TBD&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Currently, we only compute these values but do not use those, hence the &lt;code&gt;nil&lt;/code&gt; at the end of the &lt;code&gt;let&lt;/code&gt;.
But now, as we know where our projection plane is, and where our right and up are, we can compute the intersection point, where at given &lt;code&gt;x&lt;/code&gt; and &lt;code&gt;y&lt;/code&gt; coordinates of a plane in unit vector coordinates, thus defining a direction vector.&lt;/p&gt;
&lt;p&gt;So, &lt;code&gt;for&lt;/code&gt; each &lt;code&gt;x&lt;/code&gt; from &lt;code&gt;0&lt;/code&gt; to &lt;code&gt;width&lt;/code&gt; and each &lt;code&gt;y&lt;/code&gt; from &lt;code&gt;0&lt;/code&gt; to &lt;code&gt;height&lt;/code&gt; we will compute a &lt;code&gt;uv-x&lt;/code&gt; and &lt;code&gt;uv-y&lt;/code&gt; coordinates, and find the direction vector &lt;code&gt;rd&lt;/code&gt;.
To find the &lt;code&gt;uv-x&lt;/code&gt; we need to make sure it is between &lt;code&gt;-1&lt;/code&gt; and &lt;code&gt;1&lt;/code&gt; by dividing current &lt;code&gt;x&lt;/code&gt; by &lt;code&gt;width&lt;/code&gt; and subtracting &lt;code&gt;0.5&lt;/code&gt; from it, then multiplying by &lt;code&gt;x/width&lt;/code&gt;.
For &lt;code&gt;uv-y&lt;/code&gt; we only need to divide current &lt;code&gt;y&lt;/code&gt; by height, and subtract &lt;code&gt;0.5&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;for &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt; 0 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;height&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;for &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; 0 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;width&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;uv-x&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;* &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;- &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;/ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;width&lt;/span&gt;) 0.5) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;/ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;width&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;height&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;uv-y&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;- &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;/ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;height&lt;/span&gt;) 0.5)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;))) &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; TBD&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now as we have &lt;code&gt;uv-x&lt;/code&gt; and &lt;code&gt;uv-y&lt;/code&gt;, we can compute intersection point &lt;code&gt;i&lt;/code&gt;, by using the up and right vectors and the center of the plane:&lt;/p&gt;
&lt;img src=&#34;https://andreyor.st/ltximg/2020-10-15-raymarching-with-fennel-and-love_a69b83ebed3bcf5eca644e7d65e9b0d62504bb41.svg&#34; alt=&#34;\[\overrightarrow{I}=\overrightarrow{C}\cdot(\overrightarrow{R}\cdot{X_{UV}}+\overrightarrow{U}\cdot{Y_{UV}})\]&#34; class=&#34;org-svg&#34; /&gt;
&lt;p&gt;And finally, compute our direction vector &lt;code&gt;RD&lt;/code&gt;:&lt;/p&gt;
&lt;img src=&#34;https://andreyor.st/ltximg/2020-10-15-raymarching-with-fennel-and-love_e500d651acc2ee6f01323734028400ea32660648.svg&#34; alt=&#34;\[\overrightarrow{RD}=normalize(\overrightarrow{I}-\overrightarrow{RO})\]&#34; class=&#34;org-svg&#34; /&gt;
&lt;p&gt;And now we can use our &lt;code&gt;march-ray&lt;/code&gt; procedure to compute the distance and color of the pixel.
Let&amp;rsquo;s wrap everything up:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tan&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;math.tan&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.draw&lt;/span&gt; []
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;projection-distance&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;/ &lt;/span&gt;1 (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tan&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;* &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;/ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fov&lt;/span&gt; 2) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;RAD&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ro&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;camera.pos&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;norm&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vec-sub&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lookat&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ro&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vec-add&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ro&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vec-mul&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vec3&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;projection-distance&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;r&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;norm&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cross&lt;/span&gt; [0 0 -1] &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;u&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cross&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;r&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;width&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;height&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love-dimensions&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;for &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt; 0 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;height&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;for &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; 0 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;width&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;uv-x&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;* &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;- &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;/ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;width&lt;/span&gt;) 0.5) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;/ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;width&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;height&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;uv-y&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;- &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;/ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;height&lt;/span&gt;) 0.5)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vec-add&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vec-add&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vec-mul&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;r&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vec3&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;uv-x&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vec-mul&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;u&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vec3&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;uv-y&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rd&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;norm&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vec-sub&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ro&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;distance&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;color&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;march-ray&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ro&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rd&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;scene&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;&amp;lt; &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;distance&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;DRAW-DISTANCE&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love-set-color&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;color&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love-set-color&lt;/span&gt; 0 0 0))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love-points&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt;))))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now, if we set the &lt;code&gt;scene&lt;/code&gt; to contain a default &lt;code&gt;sphere&lt;/code&gt;, and place our camera at &lt;code&gt;[20 0 0]&lt;/code&gt;, we should see this:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2020-10-15-raymarching-with-lua-and-love/results-so-far.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;This is correct because our default sphere has white as the default color.&lt;/p&gt;
&lt;p&gt;You can notice, that we compute &lt;code&gt;distance&lt;/code&gt; and &lt;code&gt;color&lt;/code&gt; by calling &lt;code&gt;(march-ray ro rd scene)&lt;/code&gt;, and then check if &lt;code&gt;distance&lt;/code&gt; is less than &lt;code&gt;DRAW-DISTANCE&lt;/code&gt;.
If this is the case, we set the pixel&amp;rsquo;s color to the &lt;code&gt;color&lt;/code&gt; found by &lt;code&gt;march-ray&lt;/code&gt; function, otherwise, we set it to black.
Lastly, we draw the pixel to the screen and repeat the whole process for the next intersection point, thus the next pixel.&lt;/p&gt;
&lt;p&gt;But we don&amp;rsquo;t have to draw black pixels if we didn&amp;rsquo;t hit anything!
Remember, that in the beginning, I&amp;rsquo;ve written, that if we go past the object, we do many steps, and we can use this data to render glow.
So if we modify &lt;code&gt;love.draw&lt;/code&gt; function a bit, we will be able to see the glow around our sphere.
And the closer the gay got to the sphere, the stronger the glow will be:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; rest of love.draw&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[ &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; rest of love.draw&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;distance&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;color&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;steps&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;march-ray&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ro&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rd&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;scene&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;&amp;lt; &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;distance&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;DRAW-DISTANCE&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love-set-color&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;color&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love-set-color&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vec3&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;/ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;steps&lt;/span&gt; 100))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love-points&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; rest of love.draw&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Here, I&amp;rsquo;m setting the color to the number of steps divided by &lt;code&gt;100&lt;/code&gt;, which results in this glow effect:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2020-10-15-raymarching-with-lua-and-love/glow.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;Similarly to this glow effect, we can create a fake ambient occlusion - the more steps we did before hitting the surface, the more complex it is, hence less ambient light should be able to pass.
Unfortunately, the only object we have at this moment is a sphere, so there&amp;rsquo;s no way of showing this trick on it, as its surface isn&amp;rsquo;t very complex.&lt;/p&gt;
&lt;p&gt;All this may seem expensive, and it actually is.
Unfortunately, Lua doesn&amp;rsquo;t have real multithreading to speed this up, and the &lt;a href=&#34;https://love2d.org/wiki/love.thread&#34; target=&#34;_blank&#34;&gt;threads&lt;/a&gt; feature, provided by LÖVE results in even worse performance than computing everything in a single thread.
Well, at least the way I&amp;rsquo;ve tried it.
There&amp;rsquo;s a &lt;a href=&#34;https://love2d.org/wiki/Shader&#34; target=&#34;_blank&#34;&gt;shader DSL&lt;/a&gt; in LÖVE, which could be used to compute this stuff on GPU, but this is currently out of the scope of this project, as I wanted to implement this in Fennel.&lt;/p&gt;
&lt;p&gt;Speaking of shaders, now, that we can draw pixels on the screen, we also can shade those, and compute lighting and reflections!&lt;/p&gt;
&lt;h2 id=&#34;lighting-and-reflections&#34;&gt;Lighting and reflections&lt;/h2&gt;
&lt;p&gt;Before we begin implementing lighting, let&amp;rsquo;s add two more objects - a ground plane, and an arbitrary box.
Much like a sphere object, we first define the signed distance function, and then the constructor for the object:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;abs&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;math.abs&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;box-distance&lt;/span&gt; [{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:pos&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;box-x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;box-y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;box-z&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:dimensions&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x-side&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y-side&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;z-side&lt;/span&gt;]}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;z&lt;/span&gt;]]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sqrt&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;+ &lt;/span&gt;(^ (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;max &lt;/span&gt;0 (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;- &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;abs&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;- &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;box-x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;)) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;/ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x-side&lt;/span&gt; 2))) 2)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (^ (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;max &lt;/span&gt;0 (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;- &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;abs&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;- &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;box-y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt;)) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;/ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y-side&lt;/span&gt; 2))) 2)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (^ (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;max &lt;/span&gt;0 (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;- &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;abs&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;- &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;box-z&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;z&lt;/span&gt;)) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;/ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;z-side&lt;/span&gt; 2))) 2))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;box&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sides&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pos&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;color&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;z&lt;/span&gt;] (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pos&lt;/span&gt; [0 0 0])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x-side&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y-side&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;z-side&lt;/span&gt;] (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sides&lt;/span&gt; [10 10 10])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;r&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;g&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt;] (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;color&lt;/span&gt; [1 1 1])]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:dimensions&lt;/span&gt; [(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x-side&lt;/span&gt; 10)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y-side&lt;/span&gt; 10)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;z-side&lt;/span&gt; 10)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:pos&lt;/span&gt; [(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; 0) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt; 0) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;z&lt;/span&gt; 0)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:color&lt;/span&gt; [(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;r&lt;/span&gt; 0) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;g&lt;/span&gt; 0) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt; 0)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:sdf&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;box-distance&lt;/span&gt;}))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ground-plane&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;z&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;color&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;r&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;g&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt;] (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;color&lt;/span&gt; [1 1 1])]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:z&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;z&lt;/span&gt; 0)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:color&lt;/span&gt; [(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;r&lt;/span&gt; 0) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;g&lt;/span&gt; 0) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt; 0)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:sdf&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;plane&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;z&lt;/span&gt;]] (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;- &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;z&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;plane.z&lt;/span&gt;))}))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In case of &lt;code&gt;ground-plane&lt;/code&gt; we incorporate &lt;code&gt;:sdf&lt;/code&gt; as a anonymous function, because it is a simple one-liner.&lt;/p&gt;
&lt;p&gt;Now, as we have more objects, let&amp;rsquo;s add those to the scene and see if those work:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;var &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;camera&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:pos&lt;/span&gt; [20.0 50.0 0.0]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:x-rotate&lt;/span&gt; 0.0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:z-rotate&lt;/span&gt; 0.0})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;scene&lt;/span&gt; [(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sphere&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt; [-6 0 0] [1 0 0])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;box&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt; [6 0 0] [0 1 0])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ground-plane&lt;/span&gt; -10 [0 0 1])])
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With this &lt;code&gt;scene&lt;/code&gt; and &lt;code&gt;camera&lt;/code&gt; we should see this:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2020-10-15-raymarching-with-lua-and-love/more-objects.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;It&amp;rsquo;s a bit sadistic in the eyes, but we can at least be sure that everything works correctly.
Now we can implement lighting.&lt;/p&gt;
&lt;p&gt;In order to calculate lighting, we&amp;rsquo;ll need to know a normal to the surface at the point.
Let&amp;rsquo;s create &lt;code&gt;get-normal&lt;/code&gt; function, that receives the &lt;code&gt;point&lt;/code&gt;, and our &lt;code&gt;scene&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;get-normal&lt;/span&gt; [[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;px&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;py&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pz&lt;/span&gt;] &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;scene&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;MARCH-DELTA&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;d&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;distance-estimator&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;px&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;py&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pz&lt;/span&gt;] &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;scene&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dx&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;distance-estimator&lt;/span&gt; [(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;- &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;px&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;py&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pz&lt;/span&gt;] &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;scene&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dy&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;distance-estimator&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;px&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;- &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;py&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pz&lt;/span&gt;] &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;scene&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dz&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;distance-estimator&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;px&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;py&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;- &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pz&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;)] &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;scene&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;norm&lt;/span&gt; [(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;- &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;d&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dx&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;- &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;d&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dy&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;- &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;d&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dz&lt;/span&gt;)])))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It is a nice trick, since we create three more points around our original point, use the existing distance estimation function, and get a normalized vector of subtraction of each axis from the original point, with the distance to the new point.
Let&amp;rsquo;s use this function to get normal for each point, and use the normal as our color:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; rest of love.draw&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;&amp;lt; &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;distance&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;DRAW-DISTANCE&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love-set-color&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;get-normal&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;move-point&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ro&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rd&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;distance&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;scene&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love-set-color&lt;/span&gt; 0 0 0))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; rest of love.draw&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Notice that in order to get endpoint of our ray we &lt;code&gt;move-point&lt;/code&gt; &lt;code&gt;ro&lt;/code&gt; along the direction &lt;code&gt;rd&lt;/code&gt; using the computed &lt;code&gt;distance&lt;/code&gt;.
We then pass the resulting point into &lt;code&gt;get-normal&lt;/code&gt;, and our &lt;code&gt;scene&lt;/code&gt;, thus computing the normal vector, which we then pass to &lt;code&gt;love-set-color&lt;/code&gt;, and it gives us this result:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2020-10-15-raymarching-with-lua-and-love/colored-normals.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;You can see that the &lt;code&gt;ground-plane&lt;/code&gt; remained blue, and this isn&amp;rsquo;t an error.
Blue in our case is &lt;code&gt;[0 0 1]&lt;/code&gt;, and since in our world, positive &lt;code&gt;z&lt;/code&gt; coordinates indicate &lt;em&gt;up&lt;/em&gt;, we can see it directly in the resulting color of the plane.
The top of the cube and the sphere are also blue, and the front side is green, which means that our normals are correct.&lt;/p&gt;
&lt;p&gt;Now we can compute basic lighting.
For that we&amp;rsquo;ll need a light object:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;var &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;light&lt;/span&gt; [70 40 100])
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Let&amp;rsquo;s create a &lt;code&gt;shade-point&lt;/code&gt; function, that will accept a &lt;code&gt;point&lt;/code&gt;, point &lt;code&gt;color&lt;/code&gt;, &lt;code&gt;light&lt;/code&gt; position, and a &lt;code&gt;scene&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;shade-point&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;point&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;color&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;light&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;scene&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vec-mul&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;color&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vec3&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;point-lightness&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;point&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;scene&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;light&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It may seem that this function&amp;rsquo;s only purpose is to call &lt;code&gt;point-lightness&lt;/code&gt;, which we will define a bit later, and return a new color.
And this is true, at least for now.
Let&amp;rsquo;s create &lt;code&gt;point-lightness&lt;/code&gt; function:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clamp&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;l&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;&amp;lt; &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;l&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;l&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;&amp;gt; &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;above-surface-point&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;point&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;normal&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vec-add&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;point&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vec-mul&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;normal&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vec3&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;* &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;MARCH-DELTA&lt;/span&gt; 2)))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;point-lightness&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;point&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;scene&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;light&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;normal&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;get-normal&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;point&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;scene&lt;/span&gt;) &lt;span style=&#34;&#34;&gt;➊&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;light-vec&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;norm&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vec-sub&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;light&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;point&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;distance&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;march-ray&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;above-surface-point&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;point&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;normal&lt;/span&gt;) &lt;span style=&#34;&#34;&gt;➋&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                              &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;light-vec&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                              &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;scene&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lightness&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clamp&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dot&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;light-vec&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;normal&lt;/span&gt;) 0 1)] &lt;span style=&#34;&#34;&gt;➌&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;&amp;lt; &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;distance&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;DRAW-DISTANCE&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;* &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lightness&lt;/span&gt; 0.5)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lightness&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;What this function does, is simple.
We compute the &lt;code&gt;normal&lt;/code&gt; ➊ for given &lt;code&gt;point&lt;/code&gt;, then we find a point that is just above the surface, using &lt;code&gt;above-surface-point&lt;/code&gt; function ➋.
And we use this point as our new ray origin to march towards the &lt;code&gt;light&lt;/code&gt;.
We then get the &lt;code&gt;distance&lt;/code&gt; from the &lt;code&gt;march-ray&lt;/code&gt; function and check if we&amp;rsquo;ve gone all the way to the max distance or not.
If not, this means that there was a hit, and we divide total &lt;code&gt;lightness&lt;/code&gt; by 2 thus creating a shadow.
In the other case, we return &lt;code&gt;lightness&lt;/code&gt; as is.
And &lt;code&gt;lightness&lt;/code&gt; is a dot product between &lt;code&gt;light-vec&lt;/code&gt; and &lt;code&gt;normal&lt;/code&gt; to the surface ➌, where &lt;code&gt;light-vec&lt;/code&gt; is a normalized vector from the &lt;code&gt;point&lt;/code&gt; to the &lt;code&gt;light&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;If we again modify our &lt;code&gt;love.draw&lt;/code&gt; function like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; rest of love.draw&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;&amp;lt; &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;distance&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;DRAW-DISTANCE&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;point&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;move-point&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ro&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rd&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;distance&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love-set-color&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;shade-point&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;point&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;color&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;scene&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;light&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love-set-color&lt;/span&gt; 0 0 0))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; rest of love.draw&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We should see the shadows:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2020-10-15-raymarching-with-lua-and-love/shadows.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;This already looks like real 3D, and it is.
But we can do a bit more, so let&amp;rsquo;s add reflections.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s create a &lt;code&gt;reflection-color&lt;/code&gt; function:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;var &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;reflection-count&lt;/span&gt; 3)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;reflection-color&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;color&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;point&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;direction&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;scene&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;light&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;var &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;color&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;p&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;d&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;] [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;color&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;point&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;direction&lt;/span&gt; 0 (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;get-normal&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;point&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;scene&lt;/span&gt;)]) &lt;span style=&#34;&#34;&gt;➊&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;var &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;not-done?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;true&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;while&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;and &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;&amp;lt; &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;reflection-count&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;not-done?&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;r&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vec-sub&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;d&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vec-mul&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vec-mul&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vec3&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dot&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;d&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;)) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;) [2 2 2])) &lt;span style=&#34;&#34;&gt;➋&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;distance&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;new-color&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;march-ray&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;above-surface-point&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;p&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;r&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;scene&lt;/span&gt;)] &lt;span style=&#34;&#34;&gt;➌&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;&amp;lt; &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;distance&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;DRAW-DISTANCE&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;font-weight:bold&#34;&gt;do &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;p&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;move-point&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;p&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;r&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;distance&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;get-normal&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;p&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;scene&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;d&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;r&lt;/span&gt;) &lt;span style=&#34;&#34;&gt;➍&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;r0&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;g0&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b0&lt;/span&gt;] &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;color&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;r1&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;g1&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b1&lt;/span&gt;] &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;new-color&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;l&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;/ &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;point-lightness&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;p&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;scene&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;light&lt;/span&gt;) 2)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;color&lt;/span&gt; [(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;* &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;r0&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;* &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;r1&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;l&lt;/span&gt;)) 0.66)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;* &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;g0&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;* &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;g1&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;l&lt;/span&gt;)) 0.66)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;* &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b0&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;* &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b1&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;l&lt;/span&gt;)) 0.66)]) &lt;span style=&#34;&#34;&gt;➎&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;not-done?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;false&lt;/span&gt;) &lt;span style=&#34;&#34;&gt;➏&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; 1)) &lt;span style=&#34;&#34;&gt;➐&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;color&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This is quite a big function, so let&amp;rsquo;s look at it piece by piece.&lt;/p&gt;
&lt;p&gt;First, we use destructuring to define several &lt;code&gt;vars&lt;/code&gt; ➊, which we will be able to change using &lt;code&gt;set&lt;/code&gt; later in the function.
Next, we go into the &lt;code&gt;while&lt;/code&gt; loop, which checks both for maximum reflections reached, and if the ray went to infinity.
The first thing we do in the loop, computes the reflection vector &lt;code&gt;r&lt;/code&gt; ➋, by using this formula:&lt;/p&gt;
&lt;img src=&#34;https://andreyor.st/ltximg/2020-10-15-raymarching-with-fennel-and-love_dc97ecd084b47c4884333ad30190962c2093b2a7.svg&#34; alt=&#34;\[\overrightarrow{R}=\overrightarrow{D}-\overrightarrow{N}\cdot{dotproduct}(\overrightarrow{D},\overrightarrow{N})\cdot{2}\]&#34; class=&#34;org-svg&#34; /&gt;
&lt;p&gt;This is our new direction, which we will march from new &lt;code&gt;above-surface-point&lt;/code&gt; ➌.
If we&amp;rsquo;ve hit something, and our &lt;code&gt;distance&lt;/code&gt; will be less than &lt;code&gt;DRAW-DISTANCE&lt;/code&gt;, we&amp;rsquo;ll &lt;code&gt;set&lt;/code&gt; our point &lt;code&gt;p&lt;/code&gt; to new point, compute new normal &lt;code&gt;n&lt;/code&gt;, and set direction &lt;code&gt;d&lt;/code&gt; to previous direction, which was reflection vector &lt;code&gt;r&lt;/code&gt; ➍.
Next, we compute the resulting color.
I&amp;rsquo;m doing a simple color addition here, which is not an entirely correct way of doing it, but for now, I&amp;rsquo;m fine with that.
We also compute &lt;code&gt;lightness&lt;/code&gt; of the reflection point, and divide it by &lt;code&gt;2&lt;/code&gt;, so our reflections appear slightly darker.
Then we add each channel and make sure it is not greater than &lt;code&gt;1&lt;/code&gt;, by multiplying it by &lt;code&gt;0.66&lt;/code&gt; ➎.
The trick here is that maximum &lt;code&gt;lightness&lt;/code&gt; we can get is &lt;code&gt;0.5&lt;/code&gt;, so if we add two values, one of which is multiplied by &lt;code&gt;0.5&lt;/code&gt; overall result can be averaged by multiplying by &lt;code&gt;0.66&lt;/code&gt;.
This way we do not lose brightness all the way and the reflection color blends with the original color nicely.&lt;/p&gt;
&lt;p&gt;In case we don&amp;rsquo;t hit anything, it means that this is the final reflection, therefore we can end ➏ the &lt;code&gt;while&lt;/code&gt; loop on this iteration.
Lastly, since I&amp;rsquo;ve &lt;a href=&#34;#org-target--break-rant&#34;&gt;already ranted&lt;/a&gt; on the absence of &lt;code&gt;break&lt;/code&gt; in Fennel, we have to increase the loop counter manually ➐ at the end of the loop.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s change &lt;code&gt;shade-point&lt;/code&gt; so it will pass color into this function:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;shade-point&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;point&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;color&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;direction&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;scene&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;light&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;-&amp;gt; &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;color&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vec-mul&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vec3&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;point-lightness&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;point&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;scene&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;light&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;reflection-color&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;point&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;direction&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;scene&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;light&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You can notice that I&amp;rsquo;ve added the &lt;code&gt;direction&lt;/code&gt; parameter, as we need it for computing reflections, so we also have to change the call to &lt;code&gt;shade-point&lt;/code&gt; in &lt;code&gt;love.draw&lt;/code&gt; function:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; rest of love.draw&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;&amp;lt; &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;distance&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;DRAW-DISTANCE&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;point&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;move-point&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ro&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rd&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;distance&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love-set-color&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;shade-point&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;point&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;color&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rd&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;scene&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;light&lt;/span&gt;))) &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; rd is our initial direction&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love-set-color&lt;/span&gt; 0 0 0))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; rest of love.draw&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Let&amp;rsquo;s try this out (I&amp;rsquo;ve brought &lt;code&gt;ground-plane&lt;/code&gt; a bit closer to objects so we could better see reflections):&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2020-10-15-raymarching-with-lua-and-love/reflections.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;We can see reflections, and reflections of reflections in reflections, because previously we&amp;rsquo;ve set &lt;code&gt;reflection-count&lt;/code&gt; to &lt;code&gt;3&lt;/code&gt;.
Currently, our reflections are pure mirrors, as we reflect everything at a perfect angle, and shapes appear just as real objects.
This can be changed by introducing materials, that have different qualities like roughness, and by using better reflection algorithms like &lt;a href=&#34;https://en.wikipedia.org/wiki/Phong_reflection_model&#34; target=&#34;_blank&#34;&gt;Phong shading&lt;/a&gt;, but maybe next time.
Refractions also kinda need materials, as refraction angles can be different, depending on what kind of material it goes through.
E.g. glass and still pool of water should have different refraction angles.
And some surfaces should reflect rays at certain angles, and let them go through at other angles, which will also require certain modifications in the reflection algorithm.&lt;/p&gt;
&lt;p&gt;Now, if we would set our &lt;code&gt;camera&lt;/code&gt;, &lt;code&gt;lookat&lt;/code&gt;, and &lt;code&gt;light&lt;/code&gt; to:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lookat&lt;/span&gt; [19.75 49 19.74])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;var &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;camera&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:pos&lt;/span&gt; [20 50 20]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:x-rotate&lt;/span&gt; 0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:z-rotate&lt;/span&gt; 0})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;scene&lt;/span&gt; [(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;box&lt;/span&gt; [5 5 5] [-2.7 -2 2.5] [0.79 0.69 0.59])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;box&lt;/span&gt; [5 5 5] [2.7 2 2.5] [0.75 0.08 0.66])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;box&lt;/span&gt; [5 5 5] [0 0 7.5] [0.33 0.73 0.42])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sphere&lt;/span&gt; 2.5 [-2.7 2.5 2.5] [0.56 0.11 0.05])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sphere&lt;/span&gt; 10 [6 -20 10] [0.97 0.71 0.17])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ground-plane&lt;/span&gt; 0 [0.97 0.27 0.35])])
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We would see an image from the beginning of this post:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2020-10-15-raymarching-with-lua-and-love/end-result.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;For now, I&amp;rsquo;m pretty happy with the current result, so lastly let&amp;rsquo;s make it possible to move into our 3D space.&lt;/p&gt;
&lt;h2 id=&#34;user-input&#34;&gt;User input&lt;/h2&gt;
&lt;p&gt;We&amp;rsquo;ll be doing two different ways of moving in our scene - with keyboard and gamepad.
The difference mostly is in the fact, that gamepads can give us floating point values, so we can move slower or faster depending on how we move the analogs.&lt;/p&gt;
&lt;p&gt;We&amp;rsquo;ve already specified needed functions from LÖVE as our locals, but to recap, we&amp;rsquo;ll need only two:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love-key-pressed?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.keyboard.isDown&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love-get-joysticks&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.joystick.getJoysticks&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;But first, we&amp;rsquo;ll need to make changes to our &lt;code&gt;camera&lt;/code&gt;, as currently, it can only look at the origin.&lt;/p&gt;
&lt;p&gt;How will we compute the look-at point for our camera so we will be able to move it around in a meaningful way?
I&amp;rsquo;ve decided that a good way will be to &amp;ldquo;move&amp;rdquo; the camera forward a certain amount, and then rotate this point around the camera by using some angles.
Luckily for us, we&amp;rsquo;ve already specified that our &lt;code&gt;camera&lt;/code&gt; has two angles &lt;code&gt;:x-rotate&lt;/code&gt;, and &lt;code&gt;z-rotate&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;var &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;camera&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:pos&lt;/span&gt; [20 50 20]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:x-rotate&lt;/span&gt; 255
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:z-rotate&lt;/span&gt; 15})
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And it is also declared as a &lt;code&gt;var&lt;/code&gt;, which means that we can &lt;code&gt;set&lt;/code&gt; new values into it.
Let&amp;rsquo;s write a function that will compute a new &lt;code&gt;lookat&lt;/code&gt; point for current &lt;code&gt;camera&lt;/code&gt; position and rotation:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cos&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;math.cos&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sin&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;math.sin&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rotate-point&lt;/span&gt; [[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;z&lt;/span&gt;] [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ax&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ay&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;az&lt;/span&gt;] &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x-angle&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;z-angle&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;- &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ax&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;- &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ay&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;z&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;- &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;z&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;az&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x-angle&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;* &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x-angle&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;RAD&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;z-angle&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;* &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;z-angle&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;RAD&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cos-x&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cos&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x-angle&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sin-x&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sin&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x-angle&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cos-z&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cos&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;z-angle&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sin-z&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sin&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;z-angle&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    [(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;+ &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;* &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cos-x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cos-z&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;* &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;- &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sin-x&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;* &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cos-x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sin-z&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;z&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ax&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;+ &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;* &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sin-x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cos-z&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;* &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cos-x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;- &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;* &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sin-x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sin-z&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;z&lt;/span&gt;)) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ay&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;+ &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;* &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;- &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sin-z&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;* &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cos-z&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;z&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;az&lt;/span&gt;)]))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;forward-vec&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;camera&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pos&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;camera.pos&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rotate-point&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vec-add&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pos&lt;/span&gt; [1 0 0]) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pos&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;camera.x-rotate&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;camera.z-rotate&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The first function &lt;code&gt;rotate-point&lt;/code&gt; will rotate one point around another point by using two degrees.
It is based on &lt;a href=&#34;https://en.wikipedia.org/wiki/Aircraft_principal_axes&#34; target=&#34;_blank&#34;&gt;aircraft principal axes&lt;/a&gt;, but we only have two axes, so we do not need to &amp;ldquo;roll&amp;rdquo;, hence we do little fewer computations here.&lt;/p&gt;
&lt;p&gt;Next is the &lt;code&gt;forward-vec&lt;/code&gt; function, that computes current &amp;ldquo;forward&amp;rdquo; vector for &lt;code&gt;camera&lt;/code&gt;.
Forward, in this case, means the direction camera is &amp;ldquo;facing&amp;rdquo;, which is based on two angles we specify in the &lt;code&gt;camera&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;With this function we can implement basic movement and rotation functions for the camera:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;camera-forward&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dir&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;norm&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vec-sub&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;forward-vec&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;camera&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;camera.pos&lt;/span&gt;))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;camera.pos&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;move-point&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;camera.pos&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dir&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;camera-elevate&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;camera.pos&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vec-add&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;camera.pos&lt;/span&gt; [0 0 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;])))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;camera-rotate-x&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;camera.x-rotate&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;%&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;- &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;camera.x-rotate&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;) 360)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;camera-rotate-z&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;z&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;camera.z-rotate&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clamp&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;camera.z-rotate&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;z&lt;/span&gt;) -89.9 89.9)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;camera-strafe&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;z-rotate&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;camera.z-rotate&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;camera.z-rotate&lt;/span&gt; 0)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;camera-rotate-x&lt;/span&gt; 90)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;camera-forward&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;camera-rotate-x&lt;/span&gt; -90)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;camera.z-rotate&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;z-rotate&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And if we modify our &lt;code&gt;love.draw&lt;/code&gt; again, we&amp;rsquo;ll be able to use our computed look-at point as follows:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.draw&lt;/span&gt; []
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; rest of love.draw&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lookat&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;forward-vec&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;camera&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; rest of love.draw&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now we don&amp;rsquo;t need a global &lt;code&gt;lookat&lt;/code&gt; variable, and it is actually enough for us to compute new &lt;code&gt;lookat&lt;/code&gt; every frame.&lt;/p&gt;
&lt;p&gt;As for movement, let&amp;rsquo;s implement a simple keyboard handler:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;handle-keyboard-input&lt;/span&gt; []
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love-key-pressed?&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;w&amp;#34;&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;camera-forward&lt;/span&gt; 1)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love-key-pressed?&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;s&amp;#34;&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;camera-forward&lt;/span&gt; -1))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love-key-pressed?&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;d&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love-key-pressed?&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;lshift&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;camera-strafe&lt;/span&gt; 1)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;camera-rotate-x&lt;/span&gt; 1))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love-key-pressed?&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;a&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love-key-pressed?&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;lshift&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;camera-strafe&lt;/span&gt; -1)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;camera-rotate-x&lt;/span&gt; -1)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love-key-pressed?&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;q&amp;#34;&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;camera-rotate-z&lt;/span&gt; 1)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love-key-pressed?&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;e&amp;#34;&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;camera-rotate-z&lt;/span&gt; -1))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love-key-pressed?&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;r&amp;#34;&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;camera-elevate&lt;/span&gt; 1)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love-key-pressed?&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;f&amp;#34;&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;camera-elevate&lt;/span&gt; -1)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Similarly, we can implement controller support:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;handle-controller&lt;/span&gt; []
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;when &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;gamepad&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lstick-x&lt;/span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;gamepad&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:getGamepadAxis&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;leftx&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lstick-y&lt;/span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;gamepad&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:getGamepadAxis&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;lefty&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;l2&lt;/span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;gamepad&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:getGamepadAxis&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;triggerleft&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rstick-x&lt;/span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;gamepad&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:getGamepadAxis&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;rightx&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rstick-y&lt;/span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;gamepad&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:getGamepadAxis&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;righty&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;r2&lt;/span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;gamepad&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:getGamepadAxis&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;triggerright&amp;#34;&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;when &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;and &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lstick-y&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;&amp;lt; &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lstick-y&lt;/span&gt; -0.2) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;&amp;gt; &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lstick-y&lt;/span&gt; 0.2)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;camera-forward&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;* &lt;/span&gt;2 (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;- &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lstick-y&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;when &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;and &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lstick-x&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;&amp;lt; &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lstick-x&lt;/span&gt; -0.2) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;&amp;gt; &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lstick-x&lt;/span&gt; 0.2)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;camera-strafe&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;* &lt;/span&gt;2 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lstick-x&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;when &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;and &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rstick-x&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;&amp;lt; &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rstick-x&lt;/span&gt; -0.2) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;&amp;gt; &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rstick-x&lt;/span&gt; 0.2)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;camera-rotate-x&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;* &lt;/span&gt;4 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rstick-x&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;when &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;and &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rstick-y&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;&amp;lt; &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rstick-y&lt;/span&gt; -0.2) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;&amp;gt; &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rstick-y&lt;/span&gt; 0.2)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;camera-rotate-z&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;* &lt;/span&gt;4 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rstick-y&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;when &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;and &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;r2&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;&amp;gt; &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;r2&lt;/span&gt; -0.8))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;camera-elevate&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;+ &lt;/span&gt;1 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;r2&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;when &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;and &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;l2&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;&amp;gt; &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;l2&lt;/span&gt; -0.8))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;camera-elevate&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;- &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;+ &lt;/span&gt;1 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;l2&lt;/span&gt;)))))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Only for a controller, we make sure that our &lt;code&gt;l2&lt;/code&gt; and &lt;code&gt;r2&lt;/code&gt; axes are from 0 to 2, since by default these axes are from &lt;code&gt;-1&lt;/code&gt; to &lt;code&gt;1&lt;/code&gt;, which isn&amp;rsquo;t going to work for us.
Similarly to this, we can add the ability to change the field of view or reflection count, but I&amp;rsquo;ll leave this out for those who are interested in trying it themselves.
It&amp;rsquo;s not hard.&lt;/p&gt;
&lt;p&gt;As a final piece, we need to detect if the controller was inserted and handle keys somewhere.
So let&amp;rsquo;s add these two final functions that we need for everything to work:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;var &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;gamepad&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.joystickadded&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;g&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;gamepad&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;g&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.update&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dt&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;handle-keyboard-input&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;handle-controller&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;love.joystickadded&lt;/code&gt; will take care of watching for new controllers, and &lt;code&gt;love.update&lt;/code&gt; will ask for new input every now and then.&lt;/p&gt;
&lt;p&gt;By this moment we should have a working raymarching 3D renderer with basic lighting and reflections!&lt;/p&gt;
&lt;h2 id=&#34;final-thoughts&#34;&gt;Final thoughts&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;ve decided to write this post because I was interested in three topics:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Fennel, a Lisp-like language, which is a lot like Clojure syntax-wise, and has great interop with Lua (because it IS Lua)&lt;/li&gt;
&lt;li&gt;LÖVE, is a nice game engine I&amp;rsquo;ve been watching for a long time already and played some games written with it, which were quite awesome,&lt;/li&gt;
&lt;li&gt;and Lua itself, a nice, fast scripting language, with the cool idea that everything is a table.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Although I didn&amp;rsquo;t use much of Lua here, I&amp;rsquo;ve actually tinkered with it a lot during the whole process, testing different things, reading Fennel&amp;rsquo;s compiler output, and benchmarking various constructs, like field access, or unpacking numeric tables versus multiple return values.
Lua has some really cool semantics of defining modules as tables and incorporating special meaning to tables via &lt;code&gt;setmetatable&lt;/code&gt;, which is really easy to understand in my opinion.&lt;/p&gt;
&lt;p&gt;Fennel is a great choice if you don&amp;rsquo;t want to learn Lua syntax (which is small, but, you know, it &lt;em&gt;exists&lt;/em&gt;).
For me, Fennel is a great language, because I don&amp;rsquo;t have to deal with Lua syntax AND because I can write macros.
And even though I didn&amp;rsquo;t write any macro for this project, because everything is already presented in Fennel itself, the possibility of doing this is worth something.
Also, during benchmarking various features, I&amp;rsquo;ve used self-written &lt;code&gt;time&lt;/code&gt; macro:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;macro&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;time &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;body&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  `(&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clock#&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;os.clock&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;start#&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clock#&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res#&lt;/span&gt; ,&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;body&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;end#&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clock#&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;print &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Elapsed: &amp;#34;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;* &lt;/span&gt;1000 (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;- &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;end#&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;start#&lt;/span&gt;)) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; ms&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res#&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So the ability to define such things is a good thing.&lt;/p&gt;
&lt;p&gt;LÖVE is a great engine, and although I&amp;rsquo;ve used a very little bit of it, I still think that this is a really cool project, because there is so much more in it.
Maybe someday I&amp;rsquo;ll make a game that will realize LÖVE&amp;rsquo;s full potential.&lt;/p&gt;
&lt;p&gt;On a downside note&amp;hellip;
The resulting raymarching is &lt;strong&gt;very slow&lt;/strong&gt;.
I&amp;rsquo;ve managed to get around 25 FPS for a single object in the scene, and a 256 by 224 pixel resolution.
Yes, this is because it runs in a single thread, and does a lot of expensive computations.
Lua itself isn&amp;rsquo;t a very fast language, and even though LÖVE uses Luajit - a just-in-time compiler that emits machine code, it&amp;rsquo;s still not fast enough for certain operations, or techniques.
For example, if we implement operator overloading for vectors we&amp;rsquo;ll lose a lot of performance for constant table lookups.
This is an existing problem in Lua, since it does its best of being small and embeddable, so it could work nearly on anything, therefore it doesn&amp;rsquo;t do a lot of caching and optimizations.&lt;/p&gt;
&lt;p&gt;But hey, this is a raymarching in ~350 lines of code with some cool tricks like destructuring!
I&amp;rsquo;m fine with the results.
A slightly more polished version of the code from this article is available at &lt;a href=&#34;https://gitlab.com/andreyorst/love-raymarching&#34; target=&#34;_blank&#34;&gt;this repository&lt;/a&gt;, so if anything doesn&amp;rsquo;t work in the code above, or you got lost and just want to play with the final result, you know where to go :)&lt;/p&gt;
&lt;p&gt;Till next time, and thanks for reading!&lt;/p&gt;
&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://en.wikipedia.org/wiki/Ray_tracing_%28graphics%29&#34; target=&#34;_blank&#34;&gt;https://en.wikipedia.org/wiki/Ray_tracing_(graphics)&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:2&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/ssloy/tinyraytracer&#34; target=&#34;_blank&#34;&gt;https://github.com/ssloy/tinyraytracer&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:2&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:3&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://fennel-lang.org/setup&#34; target=&#34;_blank&#34;&gt;https://fennel-lang.org/setup&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:3&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:4&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://love2d.org/wiki/Getting_Started&#34; target=&#34;_blank&#34;&gt;https://love2d.org/wiki/Getting_Started&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:4&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:5&#34;&gt;
&lt;p&gt;there&amp;rsquo;s no need to declare a variable as &lt;code&gt;var&lt;/code&gt; if it is a table and we&amp;rsquo;re only going to change the values stored inside the table, not the table itself.&amp;#160;&lt;a href=&#34;#fnref:5&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: Raymarching with Fennel and LÖVE&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Thu, 15 Oct 2020 20:33:00 +0300</pubDate>
    </item>
  </channel>
</rss>
