<rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0">
    <channel>
        <title>Clojure - Tag - Notes about stuff</title>
        <link>/tags/clojure/</link>
        <description>Clojure - Tag - Notes about stuff</description>
        <generator>Hugo -- gohugo.io</generator><language>en</language><lastBuildDate>Mon, 06 Apr 2026 17:48:00 &#43;0200</lastBuildDate><atom:link href="/tags/clojure/" rel="self" type="application/rss+xml" /><item>
    <title>Define a reusable and lazy pipeline</title>
    <link>/posts/2026-04-06_define_a_reusable_and_lazy_pipeline/</link>
    <pubDate>Mon, 06 Apr 2026 17:48:00 &#43;0200</pubDate>
    <author>Kamila Chyla</author>
    <guid>/posts/2026-04-06_define_a_reusable_and_lazy_pipeline/</guid>
    <description><![CDATA[<div class="featured-image">
                <img src="/image.png" referrerpolicy="no-referrer">
            </div><h1 id="the-problem">The problem</h1>
<p>I have the idea of a pipeline: it is defined once, it can be reused and when called, it changes its state but does not evaluate eagerly, because it could be &ldquo;fed&rdquo; from an infinite source of data.</p>
<p>For example:</p>
<ul>
<li>all integers which are multiple of 13 and has in its binary representation more ones than zeroes</li>
<li>indices of bytes read from /dev/random which are ascii characters</li>
</ul>
<p>Perhaps there are two separate issues I&rsquo;m thinking about here:</p>
<ol>
<li>Is the pipeline creating intermediate collections when processing items through the pipeline?
For example, in Scala, all intermediate operations <em>do</em> create a collection (each map and filter)</li>
<li>When exactly is the pipeline execution triggered?</li>
<li>Can the pipeline computation be reused with different collection? Does it need a collection at all?</li>
</ol>
<h2 id="in-scala">In scala</h2>
<p>Note: see this insightful comment on SO: <a href="https://stackoverflow.com/questions/31664918/does-scala-has-intermediate-terminal-ops-as-java8-has" target="_blank" rel="noopener noreffer ">https://stackoverflow.com/questions/31664918/does-scala-has-intermediate-terminal-ops-as-java8-has</a></p>
<p>In the collections library Scala makes a distinction between <em>strict</em> and <em>lazy</em> evaluation. A mechanism for lazy evaluation is called <em>view</em>. By default collections evaluate eagerly <em>at every step</em>.</p>
<p>Let&rsquo;s create an efectful operation that doubles its input and prints it:</p>
<div class="code-block code-line-numbers open" style="counter-reset: code-block 0">
    <div class="code-header language-scala">
        <span class="code-title"><i class="arrow fas fa-angle-right" aria-hidden="true"></i></span>
        <span class="ellipses"><i class="fas fa-ellipsis-h" aria-hidden="true"></i></span>
        <span class="copy" title="Copy to clipboard"><i class="far fa-copy" aria-hidden="true"></i></span>
    </div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-scala" data-lang="scala"><span class="line"><span class="cl"><span class="k">def</span> <span class="n">reportDouble</span><span class="o">(</span><span class="n">v</span><span class="k">:</span> <span class="kt">Int</span><span class="o">)</span><span class="k">:</span> <span class="kt">Int</span> <span class="o">=</span> <span class="o">{</span> <span class="n">println</span><span class="o">(</span><span class="s">s&#34;Reporting </span><span class="si">$v</span><span class="s"> -&gt; </span><span class="si">${</span><span class="n">v</span><span class="o">*</span><span class="mi">2</span><span class="si">}</span><span class="s">&#34;</span><span class="o">);</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">v</span> <span class="o">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">val</span> <span class="n">l</span> <span class="k">=</span> <span class="nc">List</span><span class="o">(</span><span class="mi">1</span><span class="o">,</span> <span class="mi">2</span><span class="o">,</span> <span class="mi">5</span><span class="o">,</span> <span class="mi">10</span><span class="o">,</span> <span class="mi">34</span><span class="o">,</span> <span class="mi">78</span><span class="o">,</span> <span class="mi">126</span><span class="o">)</span></span></span></code></pre></div></div>
<p>Now, each <code>map</code> or <code>filter</code> on a <code>List</code> evaluates eagerly and produces a list immediately, and the map &ldquo;traverses&rdquo; all elements:</p>
<div class="code-block code-line-numbers open" style="counter-reset: code-block 0">
    <div class="code-header language-scala">
        <span class="code-title"><i class="arrow fas fa-angle-right" aria-hidden="true"></i></span>
        <span class="ellipses"><i class="fas fa-ellipsis-h" aria-hidden="true"></i></span>
        <span class="copy" title="Copy to clipboard"><i class="far fa-copy" aria-hidden="true"></i></span>
    </div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-scala" data-lang="scala"><span class="line"><span class="cl"><span class="n">l</span><span class="o">.</span><span class="n">map</span><span class="o">(</span><span class="n">reportDouble</span><span class="o">).</span><span class="n">filter</span><span class="o">(</span><span class="k">_</span> <span class="o">&gt;</span> <span class="mi">3</span><span class="o">).</span><span class="n">take</span><span class="o">(</span><span class="mi">3</span><span class="o">).</span><span class="n">foreach</span><span class="o">(</span><span class="n">println</span><span class="o">)</span>
</span></span><span class="line"><span class="cl"><span class="k">#</span> <span class="nc">Reporting</span> <span class="mi">1</span> <span class="o">-&gt;</span> <span class="mi">2</span>
</span></span><span class="line"><span class="cl"><span class="k">#</span> <span class="nc">Reporting</span> <span class="mi">2</span> <span class="o">-&gt;</span> <span class="mi">4</span>
</span></span><span class="line"><span class="cl"><span class="k">#</span> <span class="nc">Reporting</span> <span class="mi">5</span> <span class="o">-&gt;</span> <span class="mi">10</span>
</span></span><span class="line"><span class="cl"><span class="k">#</span> <span class="nc">Reporting</span> <span class="mi">10</span> <span class="o">-&gt;</span> <span class="mi">20</span>
</span></span><span class="line"><span class="cl"><span class="k">#</span> <span class="nc">Reporting</span> <span class="mi">34</span> <span class="o">-&gt;</span> <span class="mi">68</span>
</span></span><span class="line"><span class="cl"><span class="k">#</span> <span class="nc">Reporting</span> <span class="mi">78</span> <span class="o">-&gt;</span> <span class="mi">156</span>
</span></span><span class="line"><span class="cl"><span class="k">#</span> <span class="nc">Reporting</span> <span class="mi">126</span> <span class="o">-&gt;</span> <span class="mi">252</span>
</span></span><span class="line"><span class="cl"><span class="k">#</span> <span class="mi">4</span>
</span></span><span class="line"><span class="cl"><span class="k">#</span> <span class="mi">10</span>
</span></span><span class="line"><span class="cl"><span class="k">#</span> <span class="mi">20</span></span></span></code></pre></div></div>
<h3 id="iterator">Iterator</h3>
<p>We can also create an iterator. Note how the first value gets through the map, even if we haven&rsquo;t explicitely trigerred it. However, the first element is not actually missing, we will get it eventually when we do <code>next</code> or use other <code>terminal</code> operations causing traversal and evaluation of pipeline operations:</p>
<div class="code-block code-line-numbers open" style="counter-reset: code-block 0">
    <div class="code-header language-scala">
        <span class="code-title"><i class="arrow fas fa-angle-right" aria-hidden="true"></i></span>
        <span class="ellipses"><i class="fas fa-ellipsis-h" aria-hidden="true"></i></span>
        <span class="copy" title="Copy to clipboard"><i class="far fa-copy" aria-hidden="true"></i></span>
    </div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-scala" data-lang="scala"><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">scala</span><span class="o">&gt;</span>  <span class="k">val</span> <span class="n">it</span> <span class="k">=</span> <span class="n">l</span><span class="o">.</span><span class="n">iterator</span><span class="o">.</span><span class="n">map</span><span class="o">(</span><span class="n">reportDouble</span><span class="o">).</span><span class="n">filter</span><span class="o">(</span><span class="k">_</span> <span class="o">&gt;</span> <span class="mi">3</span><span class="o">)</span>
</span></span><span class="line"><span class="cl"><span class="nc">Reporting</span> <span class="mi">1</span> <span class="o">-&gt;</span> <span class="mi">2</span>
</span></span><span class="line"><span class="cl"><span class="nc">Reporting</span> <span class="mi">2</span> <span class="o">-&gt;</span> <span class="mi">4</span>
</span></span><span class="line"><span class="cl"><span class="k">val</span> <span class="n">it</span><span class="k">:</span> <span class="kt">Iterator</span><span class="o">[</span><span class="kt">Int</span><span class="o">]</span> <span class="k">=</span> <span class="n">non</span><span class="o">-</span><span class="n">empty</span> <span class="n">iterator</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">scala</span><span class="o">&gt;</span> <span class="n">it</span><span class="o">.</span><span class="n">next</span>
</span></span><span class="line"><span class="cl"><span class="k">val</span> <span class="n">res0</span><span class="k">:</span> <span class="kt">Int</span> <span class="o">=</span> <span class="mi">4</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">scala</span><span class="o">&gt;</span> <span class="n">it</span><span class="o">.</span><span class="n">next</span>
</span></span><span class="line"><span class="cl"><span class="nc">Reporting</span> <span class="mi">5</span> <span class="o">-&gt;</span> <span class="mi">10</span>
</span></span><span class="line"><span class="cl"><span class="k">val</span> <span class="n">res1</span><span class="k">:</span> <span class="kt">Int</span> <span class="o">=</span> <span class="mi">10</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">scala</span><span class="o">&gt;</span> <span class="n">it</span><span class="o">.</span><span class="n">toList</span>
</span></span><span class="line"><span class="cl"><span class="nc">Reporting</span> <span class="mi">10</span> <span class="o">-&gt;</span> <span class="mi">20</span>
</span></span><span class="line"><span class="cl"><span class="nc">Reporting</span> <span class="mi">34</span> <span class="o">-&gt;</span> <span class="mi">68</span>
</span></span><span class="line"><span class="cl"><span class="nc">Reporting</span> <span class="mi">78</span> <span class="o">-&gt;</span> <span class="mi">156</span>
</span></span><span class="line"><span class="cl"><span class="nc">Reporting</span> <span class="mi">126</span> <span class="o">-&gt;</span> <span class="mi">252</span>
</span></span><span class="line"><span class="cl"><span class="k">val</span> <span class="n">res2</span><span class="k">:</span> <span class="kt">List</span><span class="o">[</span><span class="kt">Int</span><span class="o">]</span> <span class="k">=</span> <span class="nc">List</span><span class="o">(</span><span class="mi">20</span><span class="o">,</span> <span class="mi">68</span><span class="o">,</span> <span class="mi">156</span><span class="o">,</span> <span class="mi">252</span><span class="o">)</span></span></span></code></pre></div></div>
<h3 id="reusability---iterator-is-not-reusable">Reusability - Iterator is not reusable</h3>
<p>The iterator approach allows to build a pipeline and evaluate elements when needed. However, we are not able to reuse the pipeline: once the iterator is exhausted, we&rsquo;re done. We need to create a new iterator, repeating the pipeline code.
It seems the pipeline needs to have a collection to work on attached to it. Or, in other words, there is <em>no such thing</em> as a pipeline here, I guess.</p>
<h2 id="being-lazy---scala-views">Being lazy - scala views</h2>
<p><code>views</code> make the pipeline lazy - but this happens only if we have whole pipeline and we don&rsquo;t store e.g. <code>map</code> result in a val (then - we have no laziness, but eager creation of strict collection). This is the part that was very confusing to me :)</p>
<p>If I create a view and try to map, I am forcing the evaluation! As you can see, all elements of the list get evaluated and printed, and <code>xv</code> hols a SeqView of all evaluated, already-computed values:</p>
<div class="code-block code-line-numbers open" style="counter-reset: code-block 0">
    <div class="code-header language-scala">
        <span class="code-title"><i class="arrow fas fa-angle-right" aria-hidden="true"></i></span>
        <span class="ellipses"><i class="fas fa-ellipsis-h" aria-hidden="true"></i></span>
        <span class="copy" title="Copy to clipboard"><i class="far fa-copy" aria-hidden="true"></i></span>
    </div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-scala" data-lang="scala"><span class="line"><span class="cl"><span class="k">#</span> <span class="nc">BAD</span> <span class="o">-</span> <span class="n">asiigning</span> <span class="n">l</span><span class="o">.</span><span class="n">view</span><span class="o">.</span><span class="n">map</span> <span class="n">to</span> <span class="k">val</span>
</span></span><span class="line"><span class="cl"><span class="n">scala</span><span class="o">&gt;</span> <span class="k">val</span> <span class="n">xv</span> <span class="k">=</span> <span class="n">l</span><span class="o">.</span><span class="n">view</span><span class="o">.</span><span class="n">map</span><span class="o">(</span><span class="n">reportDouble</span><span class="o">)</span>
</span></span><span class="line"><span class="cl"><span class="nc">Reporting</span> <span class="mi">1</span> <span class="o">-&gt;</span> <span class="mi">2</span>
</span></span><span class="line"><span class="cl"><span class="nc">Reporting</span> <span class="mi">2</span> <span class="o">-&gt;</span> <span class="mi">4</span>
</span></span><span class="line"><span class="cl"><span class="nc">Reporting</span> <span class="mi">5</span> <span class="o">-&gt;</span> <span class="mi">10</span>
</span></span><span class="line"><span class="cl"><span class="nc">Reporting</span> <span class="mi">10</span> <span class="o">-&gt;</span> <span class="mi">20</span>
</span></span><span class="line"><span class="cl"><span class="nc">Reporting</span> <span class="mi">34</span> <span class="o">-&gt;</span> <span class="mi">68</span>
</span></span><span class="line"><span class="cl"><span class="nc">Reporting</span> <span class="mi">78</span> <span class="o">-&gt;</span> <span class="mi">156</span>
</span></span><span class="line"><span class="cl"><span class="nc">Reporting</span> <span class="mi">126</span> <span class="o">-&gt;</span> <span class="mi">252</span>
</span></span><span class="line"><span class="cl"><span class="k">val</span> <span class="n">xv</span><span class="k">:</span> <span class="kt">scala.collection.SeqView</span><span class="o">[</span><span class="kt">Int</span><span class="o">]</span> <span class="k">=</span> <span class="nc">SeqView</span><span class="o">(</span><span class="mi">2</span><span class="o">,</span> <span class="mi">4</span><span class="o">,</span> <span class="mi">10</span><span class="o">,</span> <span class="mi">20</span><span class="o">,</span> <span class="mi">68</span><span class="o">,</span> <span class="mi">156</span><span class="o">,</span> <span class="mi">252</span><span class="o">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">#</span> <span class="nc">GOOD</span> <span class="o">-</span> <span class="n">reportDouble</span> <span class="n">does</span> <span class="n">not</span> <span class="n">run</span> <span class="n">again</span><span class="o">,</span> <span class="n">values</span> <span class="n">are</span> <span class="n">materialized</span> <span class="n">in</span> <span class="n">xv</span>
</span></span><span class="line"><span class="cl"><span class="n">scala</span><span class="o">&gt;</span> <span class="n">xv</span><span class="o">.</span><span class="n">filter</span><span class="o">(</span><span class="k">_</span> <span class="o">&lt;</span> <span class="mi">20</span><span class="o">).</span><span class="n">take</span><span class="o">(</span><span class="mi">3</span><span class="o">).</span><span class="n">foreach</span><span class="o">(</span><span class="n">println</span><span class="o">)</span>
</span></span><span class="line"><span class="cl"><span class="n">xv</span><span class="o">.</span><span class="n">filter</span><span class="o">(</span><span class="k">_</span> <span class="o">&lt;</span> <span class="mi">20</span><span class="o">).</span><span class="n">take</span><span class="o">(</span><span class="mi">3</span><span class="o">).</span><span class="n">foreach</span><span class="o">(</span><span class="n">println</span><span class="o">)</span>
</span></span><span class="line"><span class="cl"><span class="nc">Reporting</span> <span class="mi">1</span> <span class="o">-&gt;</span> <span class="mi">2</span>
</span></span><span class="line"><span class="cl"><span class="mi">2</span>
</span></span><span class="line"><span class="cl"><span class="nc">Reporting</span> <span class="mi">2</span> <span class="o">-&gt;</span> <span class="mi">4</span>
</span></span><span class="line"><span class="cl"><span class="mi">4</span>
</span></span><span class="line"><span class="cl"><span class="nc">Reporting</span> <span class="mi">5</span> <span class="o">-&gt;</span> <span class="mi">10</span>
</span></span><span class="line"><span class="cl"><span class="mi">10</span></span></span></code></pre></div></div>
<p>Lesson: <em>keep entire chaing on one expression</em> if what I need is the laziness.</p>
<h3 id="view-and-reusability">View and reusability</h3>
<p>Unlike <code>iterator</code>, <code>view</code> <em>is</em> reusable - it holds a reference to the original connection, and it reconstructs the pipeline on each terminal operation, doing a minimal, lazy work on each call (starting fresh from the begining, with minimal processing of what is necessary) - the map is not triggered:</p>
<div class="code-block code-line-numbers open" style="counter-reset: code-block 0">
    <div class="code-header language-scala">
        <span class="code-title"><i class="arrow fas fa-angle-right" aria-hidden="true"></i></span>
        <span class="ellipses"><i class="fas fa-ellipsis-h" aria-hidden="true"></i></span>
        <span class="copy" title="Copy to clipboard"><i class="far fa-copy" aria-hidden="true"></i></span>
    </div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-scala" data-lang="scala"><span class="line"><span class="cl"><span class="n">scala</span><span class="o">&gt;</span> <span class="k">val</span> <span class="n">xv</span> <span class="k">=</span> <span class="n">l</span><span class="o">.</span><span class="n">view</span><span class="o">.</span><span class="n">map</span><span class="o">(</span><span class="n">reportDouble</span><span class="o">).</span><span class="n">filter</span><span class="o">(</span><span class="k">_</span> <span class="o">&lt;</span> <span class="mi">20</span><span class="o">)</span>
</span></span><span class="line"><span class="cl"><span class="nc">Reporting</span> <span class="mi">1</span> <span class="o">-&gt;</span> <span class="mi">2</span>
</span></span><span class="line"><span class="cl"><span class="nc">Reporting</span> <span class="mi">2</span> <span class="o">-&gt;</span> <span class="mi">4</span>
</span></span><span class="line"><span class="cl"><span class="nc">Reporting</span> <span class="mi">5</span> <span class="o">-&gt;</span> <span class="mi">10</span>
</span></span><span class="line"><span class="cl"><span class="nc">Reporting</span> <span class="mi">10</span> <span class="o">-&gt;</span> <span class="mi">20</span>
</span></span><span class="line"><span class="cl"><span class="nc">Reporting</span> <span class="mi">34</span> <span class="o">-&gt;</span> <span class="mi">68</span>
</span></span><span class="line"><span class="cl"><span class="nc">Reporting</span> <span class="mi">78</span> <span class="o">-&gt;</span> <span class="mi">156</span>
</span></span><span class="line"><span class="cl"><span class="nc">Reporting</span> <span class="mi">126</span> <span class="o">-&gt;</span> <span class="mi">252</span>
</span></span><span class="line"><span class="cl"><span class="k">val</span> <span class="n">xv</span><span class="k">:</span> <span class="kt">scala.collection.View</span><span class="o">[</span><span class="kt">Int</span><span class="o">]</span> <span class="k">=</span> <span class="nc">View</span><span class="o">(</span><span class="mi">2</span><span class="o">,</span> <span class="mi">4</span><span class="o">,</span> <span class="mi">10</span><span class="o">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">scala</span><span class="o">&gt;</span> <span class="n">xv</span><span class="o">.</span><span class="n">take</span><span class="o">(</span><span class="mi">3</span><span class="o">).</span><span class="n">foreach</span><span class="o">(</span><span class="n">println</span><span class="o">)</span>
</span></span><span class="line"><span class="cl"><span class="nc">Reporting</span> <span class="mi">1</span> <span class="o">-&gt;</span> <span class="mi">2</span>
</span></span><span class="line"><span class="cl"><span class="mi">2</span>
</span></span><span class="line"><span class="cl"><span class="nc">Reporting</span> <span class="mi">2</span> <span class="o">-&gt;</span> <span class="mi">4</span>
</span></span><span class="line"><span class="cl"><span class="mi">4</span>
</span></span><span class="line"><span class="cl"><span class="nc">Reporting</span> <span class="mi">5</span> <span class="o">-&gt;</span> <span class="mi">10</span>
</span></span><span class="line"><span class="cl"><span class="mi">10</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">scala</span><span class="o">&gt;</span> <span class="n">xv</span><span class="o">.</span><span class="n">take</span><span class="o">(</span><span class="mi">2</span><span class="o">).</span><span class="n">foreach</span><span class="o">(</span><span class="n">println</span><span class="o">)</span>
</span></span><span class="line"><span class="cl"><span class="nc">Reporting</span> <span class="mi">1</span> <span class="o">-&gt;</span> <span class="mi">2</span>
</span></span><span class="line"><span class="cl"><span class="mi">2</span>
</span></span><span class="line"><span class="cl"><span class="nc">Reporting</span> <span class="mi">2</span> <span class="o">-&gt;</span> <span class="mi">4</span>
</span></span><span class="line"><span class="cl"><span class="mi">4</span></span></span></code></pre></div></div>
<p>The answer to reusability is: yes, views can be reused. They still are attached to the source collection- you cannot define a pipeline and apply it to a different collection.</p>
<h3 id="lazylist">LazyList</h3>
<p>Docs: <a href="https://www.scala-lang.org/api/2.13.4/scala/collection/immutable/LazyList.html" target="_blank" rel="noopener noreffer ">LazyList</a></p>
<p><code>LazyList</code>s can be infinite, are lazy and their values are memoized. What does it mean? The pipeline would be evaluated in a way that elements that were previously accessed will not be evaluated again.</p>
<p>The usecase for LazyList are infinite collections which we don&rsquo;t want to evaluate eagerly (like in the beautiful fibonacci example) and for finite collections don&rsquo;t give any benefit over <code>view</code>s&quot;</p>
<div class="code-block code-line-numbers open" style="counter-reset: code-block 0">
    <div class="code-header language-scala">
        <span class="code-title"><i class="arrow fas fa-angle-right" aria-hidden="true"></i></span>
        <span class="ellipses"><i class="fas fa-ellipsis-h" aria-hidden="true"></i></span>
        <span class="copy" title="Copy to clipboard"><i class="far fa-copy" aria-hidden="true"></i></span>
    </div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-scala" data-lang="scala"><span class="line"><span class="cl"><span class="nc">LazyList</span><span class="o">.</span><span class="n">from</span><span class="o">(</span><span class="n">l</span><span class="o">).</span><span class="n">map</span><span class="o">(</span><span class="n">reportDouble</span><span class="o">).</span><span class="n">filter</span><span class="o">(</span><span class="k">_</span> <span class="o">&gt;</span> <span class="mi">3</span><span class="o">).</span><span class="n">take</span><span class="o">(</span><span class="mi">3</span><span class="o">).</span><span class="n">foreach</span><span class="o">(</span><span class="n">println</span><span class="o">)</span>
</span></span><span class="line"><span class="cl"><span class="nc">Reporting</span> <span class="mi">1</span> <span class="o">-&gt;</span> <span class="mi">2</span>
</span></span><span class="line"><span class="cl"><span class="nc">Reporting</span> <span class="mi">2</span> <span class="o">-&gt;</span> <span class="mi">4</span>
</span></span><span class="line"><span class="cl"><span class="mi">4</span>
</span></span><span class="line"><span class="cl"><span class="nc">Reporting</span> <span class="mi">5</span> <span class="o">-&gt;</span> <span class="mi">10</span>
</span></span><span class="line"><span class="cl"><span class="mi">10</span>
</span></span><span class="line"><span class="cl"><span class="nc">Reporting</span> <span class="mi">10</span> <span class="o">-&gt;</span> <span class="mi">20</span>
</span></span><span class="line"><span class="cl"><span class="mi">20</span></span></span></code></pre></div></div>
<h3 id="conclusions-for-scala">Conclusions for Scala</h3>
<p>For lazy, efficient pipelines it is a good idea to use a<code>view</code>, and remember to keep the chain *in one expression&quot;.</p>
<p>Reusability of a pipeline across different collections is not possible: the best I can think of is to create a function that takes a collection or an iterator. Similar to Java Streams, we can talk about terminal and intermediate operations, but intermediate does not mean lazy in this case, becasue Scala collections API is by default <em>strict</em> and will evaluate <em>everyting</em> unless you <em>opt out</em> using <em>views</em> (now: think about Rust - it is lazy by default).</p>
<p>At least this is my understanding.</p>
<h2 id="python">Python</h2>
<p>In Python, mapping and filtering operations leave you with lazy iterator objects which by itself do not trigger anything - nothing is evaluated until consumed.</p>
<div class="code-block code-line-numbers open" style="counter-reset: code-block 0">
    <div class="code-header language-python">
        <span class="code-title"><i class="arrow fas fa-angle-right" aria-hidden="true"></i></span>
        <span class="ellipses"><i class="fas fa-ellipsis-h" aria-hidden="true"></i></span>
        <span class="copy" title="Copy to clipboard"><i class="far fa-copy" aria-hidden="true"></i></span>
    </div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">li</span> <span class="o">=</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">10</span><span class="p">,</span> <span class="mi">34</span><span class="p">,</span> <span class="mi">78</span><span class="p">,</span> <span class="mi">126</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">reportDouble</span><span class="p">(</span><span class="n">v</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="s2">&#34;Reporting </span><span class="si">{v}</span><span class="s2"> -&gt; {v*2}&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">v</span> <span class="o">*</span> <span class="mi">2</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nb">map</span><span class="p">(</span><span class="n">reportDouble</span><span class="p">,</span> <span class="n">li</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1"># &lt;map at 0x7b77bd1bf5e0&gt; -- no output</span>
</span></span><span class="line"><span class="cl"><span class="nb">filter</span><span class="p">(</span><span class="k">lambda</span> <span class="n">v</span><span class="p">:</span> <span class="n">v</span> <span class="o">&lt;</span> <span class="mi">15</span><span class="p">,</span> <span class="nb">map</span><span class="p">(</span><span class="n">reportDouble</span><span class="p">,</span> <span class="n">li</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="c1"># &lt;filter at 0x7b77bc4fd9c0&gt; -- still nothing</span></span></span></code></pre></div></div>
<p>Evaluation happens element-by-element only when something consumes those iterators. One needs to explicitely create a list out of the iterators created by <code>map</code> or <code>filter</code>.</p>
<div class="code-block code-line-numbers open" style="counter-reset: code-block 0">
    <div class="code-header language-python">
        <span class="code-title"><i class="arrow fas fa-angle-right" aria-hidden="true"></i></span>
        <span class="ellipses"><i class="fas fa-ellipsis-h" aria-hidden="true"></i></span>
        <span class="copy" title="Copy to clipboard"><i class="far fa-copy" aria-hidden="true"></i></span>
    </div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">fm</span> <span class="o">=</span> <span class="nb">filter</span><span class="p">(</span><span class="k">lambda</span> <span class="n">v</span><span class="p">:</span> <span class="n">v</span> <span class="o">&lt;</span> <span class="mi">15</span><span class="p">,</span> <span class="nb">map</span><span class="p">(</span><span class="n">reportDouble</span><span class="p">,</span> <span class="n">li</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">[</span><span class="n">i</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="n">fm</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Reporting 1 -&gt; 2</span>
</span></span><span class="line"><span class="cl"><span class="c1"># Reporting 2 -&gt; 4</span>
</span></span><span class="line"><span class="cl"><span class="c1"># Reporting 5 -&gt; 10</span>
</span></span><span class="line"><span class="cl"><span class="c1"># Reporting 10 -&gt; 20 (processed but filtered out)</span>
</span></span><span class="line"><span class="cl"><span class="c1"># Reporting 34 -&gt; 68  (processed but filtered out)</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ...</span>
</span></span><span class="line"><span class="cl"><span class="c1"># result: [2, 4, 10]</span></span></span></code></pre></div></div>
<p>Note that <em>all</em> elements get processed  - map and filter don&rsquo;t do any short-circuiting&hellip;</p>
<p>I remember that Python has <code>itertools</code> module, perhaps I can find some answers there?</p>
<p>Build-in <code>map</code> and <code>filter</code> suffer from <em>reusability problem</em>: they produce just single-use iterators:</p>
<div class="code-block code-line-numbers open" style="counter-reset: code-block 0">
    <div class="code-header language-python">
        <span class="code-title"><i class="arrow fas fa-angle-right" aria-hidden="true"></i></span>
        <span class="ellipses"><i class="fas fa-ellipsis-h" aria-hidden="true"></i></span>
        <span class="copy" title="Copy to clipboard"><i class="far fa-copy" aria-hidden="true"></i></span>
    </div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">fm</span> <span class="o">=</span> <span class="nb">filter</span><span class="p">(</span><span class="k">lambda</span> <span class="n">v</span><span class="p">:</span> <span class="n">v</span> <span class="o">&lt;</span> <span class="mi">15</span><span class="p">,</span> <span class="nb">map</span><span class="p">(</span><span class="n">reportDouble</span><span class="p">,</span> <span class="n">li</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nb">list</span><span class="p">(</span><span class="n">fm</span><span class="p">)</span>  <span class="c1"># works, prints all, returns [2, 4, 10]</span>
</span></span><span class="line"><span class="cl"><span class="nb">list</span><span class="p">(</span><span class="n">fm</span><span class="p">)</span>  <span class="c1"># returns [] - iterator is exhausted</span></span></span></code></pre></div></div>
<h3 id="the-fix---wrap-it">The Fix - wrap it</h3>
<p>If we wrap the source in a function then each time the function is called, new iterator will be created, allowing to reuse the pipeline:</p>
<div class="code-block code-line-numbers open" style="counter-reset: code-block 0">
    <div class="code-header language-python">
        <span class="code-title"><i class="arrow fas fa-angle-right" aria-hidden="true"></i></span>
        <span class="ellipses"><i class="fas fa-ellipsis-h" aria-hidden="true"></i></span>
        <span class="copy" title="Copy to clipboard"><i class="far fa-copy" aria-hidden="true"></i></span>
    </div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">pipeline</span><span class="p">(</span><span class="n">source</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="nb">filter</span><span class="p">(</span><span class="k">lambda</span> <span class="n">v</span><span class="p">:</span> <span class="n">v</span> <span class="o">&lt;</span> <span class="mi">15</span><span class="p">,</span> <span class="nb">map</span><span class="p">(</span><span class="n">reportDouble</span><span class="p">,</span> <span class="n">source</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nb">list</span><span class="p">(</span><span class="n">pipeline</span><span class="p">(</span><span class="n">li</span><span class="p">))</span> <span class="c1"># [2, 4, 10]</span>
</span></span><span class="line"><span class="cl"><span class="nb">list</span><span class="p">(</span><span class="n">pipeline</span><span class="p">(</span><span class="n">li</span><span class="p">))</span> <span class="c1"># [2, 4, 10] - works again &lt;- new iterator</span></span></span></code></pre></div></div>
<p>If the pipeline is complex (or we want to keep complex state, eg. when traversing a tree) and we want multiple conditions or early exit, or we want it to be <em>lazy</em> then we should use generators, and also <code>itertools.islice</code>(<a href="https://docs.python.org/3/library/itertools.html#itertools.islice" target="_blank" rel="noopener noreffer ">python doc</a>) which is an equivalet of <code>take</code>:</p>
<div class="code-block code-line-numbers open" style="counter-reset: code-block 0">
    <div class="code-header language-python">
        <span class="code-title"><i class="arrow fas fa-angle-right" aria-hidden="true"></i></span>
        <span class="ellipses"><i class="fas fa-ellipsis-h" aria-hidden="true"></i></span>
        <span class="copy" title="Copy to clipboard"><i class="far fa-copy" aria-hidden="true"></i></span>
    </div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">gen_pipeline</span><span class="p">(</span><span class="n">source</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">  <span class="k">for</span> <span class="n">v</span> <span class="ow">in</span> <span class="n">source</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">doubled</span> <span class="o">=</span> <span class="n">reportDouble</span><span class="p">(</span><span class="n">v</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="n">doubled</span> <span class="o">&lt;</span> <span class="mi">15</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">      <span class="k">yield</span> <span class="n">doubled</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># lazy short-cicquit, take only 3 elems</span>
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">itertools</span>
</span></span><span class="line"><span class="cl"><span class="nb">list</span><span class="p">(</span><span class="n">itertools</span><span class="o">.</span><span class="n">islice</span><span class="p">(</span><span class="n">gen_pipeline</span><span class="p">(</span><span class="n">li</span><span class="p">),</span> <span class="mi">3</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Reporting 1 -&gt; 2</span>
</span></span><span class="line"><span class="cl"><span class="c1"># Reporting 2 -&gt; 4</span>
</span></span><span class="line"><span class="cl"><span class="c1"># Reporting 5 -&gt; 10</span>
</span></span><span class="line"><span class="cl"><span class="c1"># result: [2, 4, 10] - stops after 3, does not process rest</span>
</span></span><span class="line"><span class="cl"><span class="c1"># </span></span></span></code></pre></div></div>
<h3 id="python---summary">Python - summary</h3>
<p>Python&rsquo;s <code>map</code>/<code>filter</code> are lazy but single-use. The language, as far as I know, does not have a &ldquo;pipeline&rdquo; construct - the most similar thing I can think of is a <em>function</em> wich can be used to start new iterators when needed - a callable is the reusable abstraction. It cannot be, however, independent from the source: you always need to have a collection or iterator to iterate over.</p>
<p>I once came quite close to the idea of a structure of computations that is independent on the collection - but never actually tried it. It is time to dive into&hellip;</p>
<h2 id="clojure">Clojure</h2>
<p>&hellip; clojure&rsquo;s transducers.</p>
<p>Perhaps the closest concept to what I am searching for is the <em>transducer</em> <a href="https://clojure.org/reference/transducers" target="_blank" rel="noopener noreffer ">concept</a> I encountered in clojure. It seems like a definition or composition of operations which
do not require a collection and can exist by itself. The documentation states that operations such as <code>map</code>, <code>filter</code> or <code>take</code> (for others see also <a href="https://clojure.org/api/cheatsheet" target="_blank" rel="noopener noreffer ">cheatscheet</a>) create transducers:</p>
<p>What the docs say is:</p>
<blockquote>
<p>Most sequence functions included in Clojure have an arity that produces a transducer. This arity omits the input collection; the inputs will be supplied by the process applying the transducer. Note: this reduced arity is not currying or partial application.</p>
</blockquote>
<p>Deriving from the documentation example, I can create <code>xf</code> transducer which is a composition of other transducers (<code>comp</code> is composing right-to-left, so the mental model for final transucer operation is that it executes left-to-right, first filtering, then mapping and finally taking two elements). Final reducing operation is &ldquo;+&rdquo; here; transduced sequence before addition can be retrieved by using <code>(into [] ...)</code> form:</p>
<div class="code-block code-line-numbers open" style="counter-reset: code-block 0">
    <div class="code-header language-clojure">
        <span class="code-title"><i class="arrow fas fa-angle-right" aria-hidden="true"></i></span>
        <span class="ellipses"><i class="fas fa-ellipsis-h" aria-hidden="true"></i></span>
        <span class="copy" title="Copy to clipboard"><i class="far fa-copy" aria-hidden="true"></i></span>
    </div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-clojure" data-lang="clojure"><span class="line"><span class="cl"><span class="nv">user&gt;</span> <span class="p">(</span><span class="k">def </span><span class="nv">xf</span> <span class="p">(</span><span class="nb">comp </span><span class="p">(</span><span class="nb">filter </span><span class="nv">odd?</span><span class="p">)</span> <span class="p">(</span><span class="nb">map </span><span class="nv">inc</span><span class="p">)</span> <span class="p">(</span><span class="nb">take </span><span class="mi">2</span><span class="p">)))</span> 
</span></span><span class="line"><span class="cl"><span class="o">#</span><span class="ss">&#39;user/xf</span>
</span></span><span class="line"><span class="cl"><span class="nv">user&gt;</span> <span class="p">(</span><span class="nf">transduce</span> <span class="nv">xf</span> <span class="nb">+ </span><span class="p">[</span><span class="mi">3</span>,<span class="mi">4</span>,<span class="mi">5</span>,<span class="mi">6</span>,<span class="mi">7</span>,<span class="mi">8</span>,<span class="mi">9</span>,<span class="mi">10</span>,<span class="mi">11</span>,<span class="mi">12</span><span class="p">])</span>
</span></span><span class="line"><span class="cl"><span class="mi">10</span>
</span></span><span class="line"><span class="cl"><span class="nv">user&gt;</span> <span class="p">(</span><span class="nb">into </span><span class="p">[]</span> <span class="nv">xf</span>  <span class="p">[</span><span class="mi">3</span>,<span class="mi">4</span>,<span class="mi">5</span>,<span class="mi">6</span>,<span class="mi">7</span>,<span class="mi">8</span>,<span class="mi">9</span>,<span class="mi">10</span>,<span class="mi">11</span>,<span class="mi">12</span><span class="p">])</span>
</span></span><span class="line"><span class="cl"><span class="p">[</span><span class="mi">4</span> <span class="mi">6</span><span class="p">]</span></span></span></code></pre></div></div>
<p>What happens when I define xf such that it prints an element, let&rsquo;s say: very early, before <code>filter</code>? Would It then print everything? At least, it will not at the time transducer is defined. I expect it to fire for all vec elements, however. I aslo expect that if I place <code>print</code> after <code>take</code>, I will print two filterred and inced values, 4 and 6:</p>
<p>Let&rsquo;s check. Define <code>a</code>: it takes value a, prints it and returns it.</p>
<div class="code-block code-line-numbers open" style="counter-reset: code-block 0">
    <div class="code-header language-clojure">
        <span class="code-title"><i class="arrow fas fa-angle-right" aria-hidden="true"></i></span>
        <span class="ellipses"><i class="fas fa-ellipsis-h" aria-hidden="true"></i></span>
        <span class="copy" title="Copy to clipboard"><i class="far fa-copy" aria-hidden="true"></i></span>
    </div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-clojure" data-lang="clojure"><span class="line"><span class="cl"><span class="nv">user&gt;</span> <span class="p">(</span><span class="kd">defn </span> <span class="nv">a</span> <span class="p">[</span><span class="nv">a</span><span class="p">]</span> <span class="p">(</span><span class="nb">println </span><span class="s">&#34;* &#34;</span> <span class="nv">a</span> <span class="s">&#34; *&#34;</span><span class="p">)</span> <span class="nv">a</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="o">#</span><span class="ss">&#39;user/a</span>
</span></span><span class="line"><span class="cl"><span class="nv">user&gt;</span> <span class="p">(</span><span class="nb">map </span><span class="nv">a</span> <span class="p">[</span><span class="mi">1</span> <span class="mi">2</span> <span class="mi">50</span><span class="p">])</span>
</span></span><span class="line"><span class="cl"><span class="nb">* </span> <span class="mi">1</span>  <span class="nv">*</span>
</span></span><span class="line"><span class="cl"><span class="nb">* </span> <span class="mi">2</span>  <span class="nv">*</span>
</span></span><span class="line"><span class="cl"><span class="nb">* </span> <span class="mi">50</span>  <span class="nv">*</span>
</span></span><span class="line"><span class="cl"><span class="p">(</span><span class="mi">1</span> <span class="mi">2</span> <span class="mi">50</span><span class="p">)</span></span></span></code></pre></div></div>
<p>Transducer <code>xf</code> now is composed of <code>(map a)</code> as first element of the pipeline. Wow, see what happened: it not only <em>did not</em> call map on each element of the sequence - it only executec exectly 3 times - minimal number of times needed to actually retrieve two elements required by last element of the pipeline&hellip;:</p>
<div class="code-block code-line-numbers open" style="counter-reset: code-block 0">
    <div class="code-header language-clojure">
        <span class="code-title"><i class="arrow fas fa-angle-right" aria-hidden="true"></i></span>
        <span class="ellipses"><i class="fas fa-ellipsis-h" aria-hidden="true"></i></span>
        <span class="copy" title="Copy to clipboard"><i class="far fa-copy" aria-hidden="true"></i></span>
    </div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-clojure" data-lang="clojure"><span class="line"><span class="cl"><span class="nv">user&gt;</span> <span class="p">(</span><span class="k">def </span><span class="nv">xf</span> <span class="p">(</span><span class="nb">comp </span><span class="p">(</span><span class="nb">map </span><span class="nv">a</span><span class="p">)</span> <span class="p">(</span><span class="nb">filter </span><span class="nv">odd?</span><span class="p">)</span> <span class="p">(</span><span class="nb">map </span><span class="nv">inc</span><span class="p">)</span> <span class="p">(</span><span class="nb">take </span><span class="mi">2</span><span class="p">)))</span>
</span></span><span class="line"><span class="cl"><span class="o">#</span><span class="ss">&#39;user/xf</span>
</span></span><span class="line"><span class="cl"><span class="nv">user&gt;</span> <span class="p">(</span><span class="nf">transduce</span> <span class="nv">xf</span> <span class="nb">+ </span><span class="p">[</span><span class="mi">3</span>,<span class="mi">4</span>,<span class="mi">5</span>,<span class="mi">6</span>,<span class="mi">7</span>,<span class="mi">8</span>,<span class="mi">9</span>,<span class="mi">10</span>,<span class="mi">11</span>,<span class="mi">12</span><span class="p">])</span>
</span></span><span class="line"><span class="cl"><span class="nb">* </span> <span class="mi">3</span>  <span class="nv">*</span>
</span></span><span class="line"><span class="cl"><span class="nb">* </span> <span class="mi">4</span>  <span class="nv">*</span>
</span></span><span class="line"><span class="cl"><span class="nb">* </span> <span class="mi">5</span>  <span class="nv">*</span>
</span></span><span class="line"><span class="cl"><span class="mi">10</span>
</span></span><span class="line"><span class="cl"><span class="nv">user&gt;</span> </span></span></code></pre></div></div>
<p>Interesting.</p>
<h2 id="in-rust">In Rust</h2>
<p>This behavior is similar to what we get in Rust - there are iterators everywhere :)
For example, below program constructs an infinite collection (wait! it is iterator!) and traverses it:</p>
<div class="code-block code-line-numbers open" style="counter-reset: code-block 0">
    <div class="code-header language-rust">
        <span class="code-title"><i class="arrow fas fa-angle-right" aria-hidden="true"></i></span>
        <span class="ellipses"><i class="fas fa-ellipsis-h" aria-hidden="true"></i></span>
        <span class="copy" title="Copy to clipboard"><i class="far fa-copy" aria-hidden="true"></i></span>
    </div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-rust" data-lang="rust"><span class="line"><span class="cl"><span class="kd">let</span><span class="w"> </span><span class="n">result</span>: <span class="nb">Vec</span><span class="o">&lt;</span><span class="nb">String</span><span class="o">&gt;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="mi">0</span><span class="k">u64</span><span class="o">..</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="p">.</span><span class="n">filter</span><span class="p">(</span><span class="o">|</span><span class="n">n</span><span class="o">|</span><span class="w"> </span><span class="n">n</span><span class="w"> </span><span class="o">%</span><span class="w"> </span><span class="mi">2</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="mi">0</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="p">.</span><span class="n">map</span><span class="p">(</span><span class="o">|</span><span class="n">n</span><span class="o">|</span><span class="w"> </span><span class="n">n</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">n</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="p">.</span><span class="n">take_while</span><span class="p">(</span><span class="o">|&amp;</span><span class="n">n</span><span class="o">|</span><span class="w"> </span><span class="n">n</span><span class="w"> </span><span class="o">&lt;</span><span class="w"> </span><span class="mi">1_000_000</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="p">.</span><span class="n">filter</span><span class="p">(</span><span class="o">|</span><span class="n">n</span><span class="o">|</span><span class="w"> </span><span class="n">n</span><span class="p">.</span><span class="n">to_string</span><span class="p">().</span><span class="n">starts_with</span><span class="p">(</span><span class="sc">&#39;4&#39;</span><span class="p">))</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="p">.</span><span class="n">map</span><span class="p">(</span><span class="o">|</span><span class="n">n</span><span class="o">|</span><span class="w"> </span><span class="fm">format!</span><span class="p">(</span><span class="s">&#34;val:</span><span class="si">{n}</span><span class="s">&#34;</span><span class="p">))</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="p">.</span><span class="n">collect</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="c1">// The entire chain runs element-by-element — no intermediate Vec
</span></span></span></code></pre></div></div>
<p>So the example with simple collection will be as follows:</p>
<div class="code-block code-line-numbers open" style="counter-reset: code-block 0">
    <div class="code-header language-rust">
        <span class="code-title"><i class="arrow fas fa-angle-right" aria-hidden="true"></i></span>
        <span class="ellipses"><i class="fas fa-ellipsis-h" aria-hidden="true"></i></span>
        <span class="copy" title="Copy to clipboard"><i class="far fa-copy" aria-hidden="true"></i></span>
    </div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-rust" data-lang="rust"><span class="line"><span class="cl"><span class="k">fn</span> <span class="nf">report_double</span><span class="p">(</span><span class="n">v</span>: <span class="kt">i32</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="kt">i32</span> <span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">doubled</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">v</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="mi">2</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="fm">println!</span><span class="p">(</span><span class="s">&#34;Reporting </span><span class="si">{}</span><span class="s"> -&gt; </span><span class="si">{}</span><span class="s">&#34;</span><span class="p">,</span><span class="w"> </span><span class="n">v</span><span class="p">,</span><span class="w"> </span><span class="n">doubled</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="n">doubled</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="k">fn</span> <span class="nf">simple_pipeline</span><span class="p">()</span><span class="w"> </span>-&gt; <span class="nb">Vec</span><span class="o">&lt;</span><span class="kt">i32</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">v</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="fm">vec!</span><span class="p">[</span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="mi">2</span><span class="p">,</span><span class="w"> </span><span class="mi">5</span><span class="p">,</span><span class="w"> </span><span class="mi">10</span><span class="p">,</span><span class="w"> </span><span class="mi">34</span><span class="p">,</span><span class="w"> </span><span class="mi">78</span><span class="p">,</span><span class="w"> </span><span class="mi">126</span><span class="p">];</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="n">v</span><span class="p">.</span><span class="n">iter</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="p">.</span><span class="n">map</span><span class="p">(</span><span class="o">|</span><span class="n">n</span><span class="o">|</span><span class="w"> </span><span class="n">report_double</span><span class="p">(</span><span class="o">*</span><span class="n">n</span><span class="p">))</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="p">.</span><span class="n">filter</span><span class="p">(</span><span class="o">|</span><span class="n">v</span><span class="o">|</span><span class="w"> </span><span class="o">*</span><span class="n">v</span><span class="w"> </span><span class="o">&lt;</span><span class="w"> </span><span class="mi">20</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="p">.</span><span class="n">take</span><span class="p">(</span><span class="mi">3</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="p">.</span><span class="n">collect</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="k">fn</span> <span class="nf">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="fm">println!</span><span class="p">(</span><span class="s">&#34;Example pipeline: </span><span class="si">{:#?}</span><span class="s">&#34;</span><span class="p">,</span><span class="w"> </span><span class="n">simple_pipeline</span><span class="p">())</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div></div>
<p>which behaves nicely - does not go through whole collection and gives exactly what I expected = three elements:</p>
<div class="code-block code-line-numbers open" style="counter-reset: code-block 0">
    <div class="code-header language-">
        <span class="code-title"><i class="arrow fas fa-angle-right" aria-hidden="true"></i></span>
        <span class="ellipses"><i class="fas fa-ellipsis-h" aria-hidden="true"></i></span>
        <span class="copy" title="Copy to clipboard"><i class="far fa-copy" aria-hidden="true"></i></span>
    </div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">Reporting 1 -&gt; 2
</span></span><span class="line"><span class="cl">Reporting 2 -&gt; 4
</span></span><span class="line"><span class="cl">Reporting 5 -&gt; 10
</span></span><span class="line"><span class="cl">Example pipeline: [
</span></span><span class="line"><span class="cl">    2,
</span></span><span class="line"><span class="cl">    4,
</span></span><span class="line"><span class="cl">    10,
</span></span><span class="line"><span class="cl">]</span></span></code></pre></div></div>
<p>Making the pipeline more generic can be done by making collection&rsquo;s element generic or by creating a function that takes an <code>Iterator&lt;Item=i32&gt;</code> - which allows to use the <code>pipeline</code> on both vec and set (note non-deteministic output):</p>
<div class="code-block code-line-numbers open" style="counter-reset: code-block 0">
    <div class="code-header language-rust">
        <span class="code-title"><i class="arrow fas fa-angle-right" aria-hidden="true"></i></span>
        <span class="ellipses"><i class="fas fa-ellipsis-h" aria-hidden="true"></i></span>
        <span class="copy" title="Copy to clipboard"><i class="far fa-copy" aria-hidden="true"></i></span>
    </div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-rust" data-lang="rust"><span class="line"><span class="cl"><span class="k">fn</span> <span class="nf">pipeline</span><span class="o">&lt;</span><span class="n">T</span>: <span class="nb">Iterator</span><span class="o">&lt;</span><span class="n">Item</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="kt">i32</span><span class="o">&gt;&gt;</span><span class="p">(</span><span class="n">it</span>: <span class="nc">T</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nb">Vec</span><span class="o">&lt;</span><span class="kt">i32</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="n">it</span><span class="p">.</span><span class="n">map</span><span class="p">(</span><span class="o">|</span><span class="n">n</span><span class="o">|</span><span class="w"> </span><span class="n">report_double</span><span class="p">(</span><span class="n">n</span><span class="p">))</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="p">.</span><span class="n">filter</span><span class="p">(</span><span class="o">|</span><span class="n">v</span><span class="o">|</span><span class="w"> </span><span class="o">*</span><span class="n">v</span><span class="w"> </span><span class="o">&lt;</span><span class="w"> </span><span class="mi">20</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="p">.</span><span class="n">take</span><span class="p">(</span><span class="mi">3</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="p">.</span><span class="n">collect</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="k">fn</span> <span class="nf">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="fm">println!</span><span class="p">(</span><span class="s">&#34;Print pipeline:&#34;</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="fm">println!</span><span class="p">(</span><span class="s">&#34;</span><span class="si">{:#?}</span><span class="s">&#34;</span><span class="p">,</span><span class="w"> </span><span class="n">pipeline</span><span class="p">(</span><span class="fm">vec!</span><span class="p">[</span><span class="mi">3</span><span class="p">,</span><span class="w"> </span><span class="mi">4</span><span class="p">,</span><span class="w"> </span><span class="mi">3</span><span class="p">,</span><span class="w"> </span><span class="mi">100</span><span class="p">,</span><span class="w"> </span><span class="mi">200</span><span class="p">].</span><span class="n">into_iter</span><span class="p">()));</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="fm">println!</span><span class="p">(</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="s">&#34;</span><span class="si">{:#?}</span><span class="s">&#34;</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="n">pipeline</span><span class="p">(</span><span class="n">HashSet</span>::<span class="n">from</span><span class="p">([</span><span class="mi">3</span><span class="p">,</span><span class="w"> </span><span class="mi">4</span><span class="p">,</span><span class="w"> </span><span class="mi">3</span><span class="p">,</span><span class="w"> </span><span class="mi">100</span><span class="p">,</span><span class="w"> </span><span class="mi">200</span><span class="p">]).</span><span class="n">into_iter</span><span class="p">())</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div></div>
<p>or by also returning an iterator - in this case I need to force collection (note a call to <code>.collect::&lt;Vec&lt;i32&gt;&gt;()</code>)to be able to print the results as iterator itself does not implement <code>Display</code>:</p>
<div class="code-block code-line-numbers open" style="counter-reset: code-block 0">
    <div class="code-header language-rust">
        <span class="code-title"><i class="arrow fas fa-angle-right" aria-hidden="true"></i></span>
        <span class="ellipses"><i class="fas fa-ellipsis-h" aria-hidden="true"></i></span>
        <span class="copy" title="Copy to clipboard"><i class="far fa-copy" aria-hidden="true"></i></span>
    </div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-rust" data-lang="rust"><span class="line"><span class="cl"><span class="k">fn</span> <span class="nf">pipeline</span><span class="o">&lt;</span><span class="n">T</span>: <span class="nb">Iterator</span><span class="o">&lt;</span><span class="n">Item</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="kt">i32</span><span class="o">&gt;&gt;</span><span class="p">(</span><span class="n">it</span>: <span class="nc">T</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nc">impl</span><span class="w"> </span><span class="nb">Iterator</span><span class="o">&lt;</span><span class="n">Item</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="kt">i32</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="n">it</span><span class="p">.</span><span class="n">map</span><span class="p">(</span><span class="o">|</span><span class="n">n</span><span class="o">|</span><span class="w"> </span><span class="n">report_double</span><span class="p">(</span><span class="n">n</span><span class="p">)).</span><span class="n">filter</span><span class="p">(</span><span class="o">|</span><span class="n">v</span><span class="o">|</span><span class="w"> </span><span class="o">*</span><span class="n">v</span><span class="w"> </span><span class="o">&lt;</span><span class="w"> </span><span class="mi">20</span><span class="p">).</span><span class="n">take</span><span class="p">(</span><span class="mi">3</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="k">fn</span> <span class="nf">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="fm">println!</span><span class="p">(</span><span class="s">&#34;Print pipeline:&#34;</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="fm">println!</span><span class="p">(</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="s">&#34;</span><span class="si">{:#?}</span><span class="s">&#34;</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="n">pipeline</span><span class="p">(</span><span class="fm">vec!</span><span class="p">[</span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="mi">3</span><span class="p">,</span><span class="w"> </span><span class="mi">4</span><span class="p">,</span><span class="w"> </span><span class="mi">3</span><span class="p">,</span><span class="w"> </span><span class="mi">100</span><span class="p">,</span><span class="w"> </span><span class="mi">200</span><span class="p">].</span><span class="n">into_iter</span><span class="p">()).</span><span class="n">collect</span>::<span class="o">&lt;</span><span class="nb">Vec</span><span class="o">&lt;</span><span class="kt">i32</span><span class="o">&gt;&gt;</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="fm">println!</span><span class="p">(</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="s">&#34;</span><span class="si">{:#?}</span><span class="s">&#34;</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="n">pipeline</span><span class="p">(</span><span class="n">HashSet</span>::<span class="n">from</span><span class="p">([</span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="mi">3</span><span class="p">,</span><span class="w"> </span><span class="mi">4</span><span class="p">,</span><span class="w"> </span><span class="mi">3</span><span class="p">,</span><span class="w"> </span><span class="mi">100</span><span class="p">,</span><span class="w"> </span><span class="mi">200</span><span class="p">]).</span><span class="n">into_iter</span><span class="p">()).</span><span class="n">collect</span>::<span class="o">&lt;</span><span class="nb">Vec</span><span class="o">&lt;</span><span class="kt">i32</span><span class="o">&gt;&gt;</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div></div>
<p>which gives following output (obviously, duplicates disappeared on HashSet construction, and set output changes in each execution of the program):</p>
<div class="code-block code-line-numbers open" style="counter-reset: code-block 0">
    <div class="code-header language-">
        <span class="code-title"><i class="arrow fas fa-angle-right" aria-hidden="true"></i></span>
        <span class="ellipses"><i class="fas fa-ellipsis-h" aria-hidden="true"></i></span>
        <span class="copy" title="Copy to clipboard"><i class="far fa-copy" aria-hidden="true"></i></span>
    </div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl"> Print pipeline:
</span></span><span class="line"><span class="cl">Reporting 1 -&gt; 2
</span></span><span class="line"><span class="cl">Reporting 1 -&gt; 2
</span></span><span class="line"><span class="cl">Reporting 3 -&gt; 6
</span></span><span class="line"><span class="cl">[
</span></span><span class="line"><span class="cl">    2,
</span></span><span class="line"><span class="cl">    2,
</span></span><span class="line"><span class="cl">    6,
</span></span><span class="line"><span class="cl">]
</span></span><span class="line"><span class="cl">Reporting 4 -&gt; 8
</span></span><span class="line"><span class="cl">Reporting 200 -&gt; 400
</span></span><span class="line"><span class="cl">Reporting 100 -&gt; 200
</span></span><span class="line"><span class="cl">Reporting 1 -&gt; 2
</span></span><span class="line"><span class="cl">Reporting 3 -&gt; 6
</span></span><span class="line"><span class="cl">[
</span></span><span class="line"><span class="cl">    8,
</span></span><span class="line"><span class="cl">    2,
</span></span><span class="line"><span class="cl">    6,
</span></span><span class="line"><span class="cl">]</span></span></code></pre></div></div>
<h1 id="conclusions">Conclusions</h1>
<p>Let&rsquo;s go back to initial question: can I define a pipeline once, keep it lazy and reuse with different inputs?</p>
<p>This question has two separate parts: laziness and reusability, and different languages answer them in a different way.</p>
<p><em>Python</em> is lazy: <code>map</code> and <code>filter</code> return iterators which are evaluated <em>lazily</em> element-by-element when they are consumed (in terminal operations, like creating a <code>list()</code>), and those iterators are <em>single use</em>: when exhaused, cannot be re-run. To re-use, you can define a function; to short-cirquit, you can use <code>itertools.islice</code>.</p>
<p><em>Scala</em> defaults to <em>strict evaluation</em> - every <code>map</code> and <code>filter</code> on a List creates a full intermediate collection. You can opt-out using <code>.view</code> which <em>defers</em> all operations until a terminal <code>foreach</code> which will process what&rsquo;s needed. <code>view</code>-based pipeline can be reused: it holds reference to original collection, and rebuilds the lazy chain on each terminal call - but it needs to be a single expression! (Confusing part: if you assign intermedite result to a <code>val</code> it will force evaluation at that point and break laziness.)</p>
<p><em>Rust</em> makes laziness default - iterators cause evaluation elem-by-elem, there is no intermediate collections created, and those pipelines short-cirquit nicely with <code>take</code> or <code>take while</code>. If you define a pipeline inside a function that takes <code>impl Iterator</code>, it is (somewhat) independent from the input: you can pass vec, set, infinite range. Very elegant.</p>
<p><em>Clojure</em> has a concept of a transducer - it is a pipeline definition that is completely decoupled from the source <em>and</em> the collection of results: you define complex transducers by combining simpler transducers using <code>comp</code> and then uou can appply it to different sinks (<code>transduce</code>, <code>into</code>) It evaluates lazily and minimally - only as many elements are processed as needed. Of all four langiuages I experimender with, transducers in Clojure are closest to my idea of an independent pipeline.</p>
<p>Depending on what you need, you can choose what you want! What I needed for sure was the above journey - it let me  to order the concept of pipelined computations in my head. Jumping bewteen languages and using all of them at the same time sometimes casues the concepts leak between areas of my brain, causing a bit of confusion :D</p>
<p>Happy hacking!</p>
]]></description>
</item>
</channel>
</rss>
