<?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/laziness/</link>
    <image>
      <title>Andrey Listopadov</title>
      <link>https://andreyor.st/tags/laziness/</link>
      <url>https://andreyor.st/tags/laziness/favicon-64.png</url>
    </image>
    <description>Posts tagged 'laziness' 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>Tue, 07 Apr 2026 02:47:00 +0300</lastBuildDate>
    <atom:link href="https://andreyor.st/tags/laziness/feed.xml" rel="self" type="application/rss+xml" />
    <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;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>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://github.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://github.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://github.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>
  </channel>
</rss>
