<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Clojure and me</title>
	<atom:link href="http://clj-me.cgrand.net/feed/" rel="self" type="application/rss+xml" />
	<link>http://clj-me.cgrand.net</link>
	<description>When the pupil is ready to learn, a teacher will appear.</description>
	<lastBuildDate>Fri, 09 Mar 2018 12:16:25 +0000</lastBuildDate>
	<language>en-US</language>
		<sy:updatePeriod>hourly</sy:updatePeriod>
		<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=4.0</generator>
	<item>
		<title>Content-Defined Dependency Shading</title>
		<link>http://clj-me.cgrand.net/2018/03/09/content-defined-dependency-shading/</link>
		<comments>http://clj-me.cgrand.net/2018/03/09/content-defined-dependency-shading/#comments</comments>
		<pubDate>Fri, 09 Mar 2018 12:16:25 +0000</pubDate>
		<dc:creator><![CDATA[cgrand]]></dc:creator>
				<category><![CDATA[unsorted]]></category>

		<guid isPermaLink="false">http://clj-me.cgrand.net/?p=683</guid>
		<description><![CDATA[Shading is the practice of renaming a dependency and embed it in a project to be sure it won&#8217;t conflict with another version of itself (it&#8217;s a good time to go watch or rewatch Rich Hickey&#8217;s Spec-ulation). For Unrepl we rely on shading extensively as we don&#8217;t want the code injected by the client to [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Shading is the practice of renaming a dependency and embed it in a project to be sure it won&#8217;t conflict with another version of itself (it&#8217;s a good time to go watch or rewatch <a href="https://www.youtube.com/watch?v=oyLBGkS5ICk">Rich Hickey&#8217;s Spec-ulation</a>).</p>
<p>For <a href="https://github.com/Unrepl/unrepl">Unrepl</a> we rely on shading extensively as we don&#8217;t want the code injected by the client to interfere with running code or even tools running a different strain of Unrepl.</p>
<p>That&#8217;s how we ended with the idea of content-defined shading: choose a granularity of shading (e.g. namespace or all eps, or whole project), compute a hash (in our case SHA1, thus we are SHA-ding!) on it and use the hash in the renaming process.</p>
<p>Doing so we end with stable names that don&#8217;t depend on date, version or commit.</p>
]]></content:encoded>
			<wfw:commentRss>http://clj-me.cgrand.net/2018/03/09/content-defined-dependency-shading/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Datastructures: stateless transient flags</title>
		<link>http://clj-me.cgrand.net/2018/03/05/datastructures-stateless-transient-flags/</link>
		<comments>http://clj-me.cgrand.net/2018/03/05/datastructures-stateless-transient-flags/#comments</comments>
		<pubDate>Mon, 05 Mar 2018 14:07:00 +0000</pubDate>
		<dc:creator><![CDATA[cgrand]]></dc:creator>
				<category><![CDATA[unsorted]]></category>

		<guid isPermaLink="false">http://clj-me.cgrand.net/?p=679</guid>
		<description><![CDATA[Traditionally transient data structures use a mutable box to determine whether a node can be modified in place or not. Somehow it acts like a transaction: when the mutable box contains a non null then it means the transient is still &#8220;open&#8221; (editable nodes have not been shared yet os can be modified). Thus each [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Traditionally transient data structures use a mutable box to determine whether a node can be modified in place or not. Somehow it acts like a transaction: when the mutable box contains a non null then it means the transient is still &#8220;open&#8221; (editable nodes have not been shared yet os can be modified). Thus each node has a reference to a reference object (when the node was created by a persistent operation the reference to the reference itself is null).</p>
<p>When I was working on <a href="https://github.com/cgrand/confluent-map">confluent map</a> I found another way to track transients node ownership.</p>
<p>The main idea is to put the flag not in the node but in its parent. Since there are one flag per child, better to store them has a bitmap. Space-wise this solution is not greedier than using a reference type: a 32 bit bitmap vs a 32 bit reference (with compressed pointers) and an additional object.</p>
<p>The role of these flags is to tell whether a child is exclusively owned (not shared) by its parent. Now when one traverse a transient data structures from its root, one has just to check that the whole ownership chain is exclusive. When so the node is editable (mutable). No mutability required.</p>
<p>Tangentially related notes:</p>
<ol>
<li>In confluent map, I doesn&#8217;t even need to have a separate bitmap, since I had a case left in the main bitmap.</li>
<li>CHAMP hash maps are no faster than Clojure ones, benchmarks in the paper measure differences in hash algorithms (plain Java vs Clojure Murmur3 strain) not in data structures implementations.</li>
<li>confluent maps sports 3-way merge in time linear with the number of edits (not the actual size).</li>
</ol>
]]></content:encoded>
			<wfw:commentRss>http://clj-me.cgrand.net/2018/03/05/datastructures-stateless-transient-flags/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Mic check</title>
		<link>http://clj-me.cgrand.net/2018/03/05/mic-check/</link>
		<comments>http://clj-me.cgrand.net/2018/03/05/mic-check/#comments</comments>
		<pubDate>Mon, 05 Mar 2018 11:04:05 +0000</pubDate>
		<dc:creator><![CDATA[cgrand]]></dc:creator>
				<category><![CDATA[unsorted]]></category>

		<guid isPermaLink="false">http://clj-me.cgrand.net/?p=675</guid>
		<description><![CDATA[Long time no post. In the years since the last post, I&#8217;ve worked on several projects, let me introduce some! First there&#8217;s xforms a collection of transducers-related stuff. Xforms is really great if you need to do any kind of aggregation, it also provides transducer versions of some core functions and several new transducing contexts [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Long time no post.<br />
In the years since the last post, I&#8217;ve worked on several projects, let me introduce some!</p>
<p>First there&#8217;s <a href="https://github.com/cgrand/xforms/">xforms</a> a collection of transducers-related stuff. Xforms is really great if you need to do any kind of aggregation, it also provides transducer versions of some core functions and several new transducing contexts (strings, io). Plus it has optimizations for dealing with key-value pairs without ever allocating a pair object (best case).</p>
<p>Xforms was initially a clojure/jvm lib but <a href="https://twitter.com/mfikes">Mike Fikes</a> started porting it to cljs, however I was not happy with having to either split the codebase or break the API to solve the &#8220;macros-and-code-in-one-file&#8221; problem. With his and <a href="https://twitter.com/anmonteiro90">António&#8217;s</a> expert knowledges to guide me I figured out a couple of macros which allows to write cljc code which mixes macros and code, works on clj/jvm, cljs/clj and self-host cljs (yes there are macros to figure out the cljs flavor). This is really useful when porting clj/jvm code to cljs/*. These macros are packaged in a library named <a href="https://github.com/cgrand/macrovich">Macrovich</a>.</p>
<p>With colleagues at HCA Datalab we worked on <a href="https://github.com/HCADatalab/powderkeg">Powderkeg</a> (&#8220;Keg&#8221; for friends) which basically turns Apache Spark in a giant transducing context. Plus it works without any AOT. Start the repl, connect to the cluster, run your transducers on RDDs. Benefits: you can experiment against real data with a tight feedback loop and you can test your computations with no dependencies on Spark.</p>
<p>The part of Keg that makes the REPL-no-AOT experience possible has been repurposed into <a href="https://github.com/portkey-cloud/portkey">Portkey</a> which allows to deploy freshly REPLed functions as AWS Lambdas; a sub project is <a href="https://github.com/portkey-cloud/aws-clj-sdk">aws-clj-sdk</a> an AWS api generated from the machine-readable services descriptions provided by Amazon (like official SDKs or Python&#8217;s Boto); <a href="https://twitter.com/KimmoKoskinen">Kimmo Koskinen</a> and <a href="https://twitter.com/BaptisteDupuch">Baptiste Dupuch</a> are hard at work on both projects.</p>
<p>Last, there&#8217;s <a href="https://github.com/Unrepl/unrepl">Unrepl</a> which aims to provide better REPLs and tooling in general without requiring a single dependency to your project. All that is needed is a plain socket repl and an Unrepl-powered tool (like <a href="https://github.com/Unrepl/spiral">Spiral</a> for Emacs, <a href="https://bitbucket.org/kotarak/vimpire">Vimpire</a> for VIM, or <a href="https://github.com/Unrepl/unravel">Unravel</a> for the terminal).</p>
]]></content:encoded>
			<wfw:commentRss>http://clj-me.cgrand.net/2018/03/05/mic-check/feed/</wfw:commentRss>
		<slash:comments>22</slash:comments>
		</item>
		<item>
		<title>These aren&#8217;t the reducing functions you are looking for</title>
		<link>http://clj-me.cgrand.net/2014/10/08/these-arent-the-reducing-functions-you-are-looking-for/</link>
		<comments>http://clj-me.cgrand.net/2014/10/08/these-arent-the-reducing-functions-you-are-looking-for/#comments</comments>
		<pubDate>Tue, 07 Oct 2014 23:12:09 +0000</pubDate>
		<dc:creator><![CDATA[cgrand]]></dc:creator>
				<category><![CDATA[unsorted]]></category>

		<guid isPermaLink="false">http://clj-me.cgrand.net/?p=660</guid>
		<description><![CDATA[Transducers are powerful and easy to grasp when they claim they transform reducing functions. However once you scratch their surface you quickly realize that&#8217;s not their true nature: they transform stateful processes. In a previous post, I explained why seeded transduce forces transducers to return stateful reducing functions. However this can be fixed. The current [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Transducers are powerful and easy to grasp when they claim they transform reducing functions. However once you scratch their surface you quickly realize that&#8217;s not their true nature: they transform <a href="https://www.youtube.com/watch?v=6mTbuzafcII#t=69">stateful processes</a>.</p>
<p>In <a href="http://clj-me.cgrand.net/2014/09/11/the-rules-of-transducer-club/">a previous post</a>, I explained why seeded transduce forces transducers to return stateful reducing functions. However this can be fixed. The current implementation of <code class="highlight"><span class="nv">transduce</span></code> reads:</p>
<pre class="highlight"><span class="p">(</span><span class="kd">defn </span><span class="nv">transduce</span>
  <span class="s">&quot;reduce with a transformation of f (xf). If init is not</span>
<span class="s">  supplied, (f) will be called to produce it. f should be a reducing</span>
<span class="s">  step function that accepts both 1 and 2 arguments, if it accepts</span>
<span class="s">  only 2 you can add the arity-1 with &#39;completing&#39;. Returns the result</span>
<span class="s">  of applying (the transformed) xf to init and the first item in coll,</span>
<span class="s">  then applying xf to that result and the 2nd item, etc. If coll</span>
<span class="s">  contains no items, returns init and f is not called. Note that</span>
<span class="s">  certain transforms may inject or skip items.&quot;</span>  <span class="p">{</span><span class="ss">:added</span> <span class="s">&quot;1.7&quot;</span><span class="p">}</span>
  <span class="p">([</span><span class="nv">xform</span> <span class="nv">f</span> <span class="nv">coll</span><span class="p">]</span> <span class="p">(</span><span class="nf">transduce</span> <span class="nv">xform</span> <span class="nv">f</span> <span class="p">(</span><span class="nf">f</span><span class="p">)</span> <span class="nv">coll</span><span class="p">))</span>
  <span class="p">([</span><span class="nv">xform</span> <span class="nv">f</span> <span class="nv">init</span> <span class="nv">coll</span><span class="p">]</span>
     <span class="p">(</span><span class="k">let </span><span class="p">[</span><span class="nv">f</span> <span class="p">(</span><span class="nf">xform</span> <span class="nv">f</span><span class="p">)</span>
           <span class="nv">ret</span> <span class="p">(</span><span class="nf">clojure.core.protocols/coll-reduce</span> <span class="nv">coll</span> <span class="nv">f</span> <span class="nv">init</span><span class="p">)]</span>
       <span class="p">(</span><span class="nf">f</span> <span class="nv">ret</span><span class="p">))))</span></pre>
<p>To fix it you have to make the seeded case the special case and not the normal case:</p>
<pre class="highlight"><span class="p">(</span><span class="kd">defn </span><span class="nv">fseed</span> <span class="p">[</span><span class="nv">f</span> <span class="nv">init</span><span class="p">]</span>
  <span class="p">(</span><span class="nf">fn</span>
    <span class="p">([]</span> <span class="nv">init</span><span class="p">)</span>
    <span class="p">([</span><span class="nv">x</span><span class="p">]</span> <span class="p">(</span><span class="nf">f</span> <span class="nv">x</span><span class="p">))</span>
    <span class="p">([</span><span class="nv">x</span> <span class="nv">y</span><span class="p">]</span> <span class="p">(</span><span class="nf">f</span> <span class="nv">x</span> <span class="nv">y</span><span class="p">))))</span>

<span class="p">(</span><span class="kd">defn </span><span class="nv">transduce</span>
  <span class="s">&quot;reduce with a transformation of f (xf). If init is not</span>
<span class="s">  supplied, (f) will be called to produce it. f should be a reducing</span>
<span class="s">  step function that accepts both 1 and 2 arguments, if it accepts</span>
<span class="s">  only 2 you can add the arity-1 with &#39;completing&#39;. Returns the result</span>
<span class="s">  of applying (the transformed) xf to init and the first item in coll,</span>
<span class="s">  then applying xf to that result and the 2nd item, etc. If coll</span>
<span class="s">  contains no items, returns init and f is not called. Note that</span>
<span class="s">  certain transforms may inject or skip items.&quot;</span>  <span class="p">{</span><span class="ss">:added</span> <span class="s">&quot;1.7&quot;</span><span class="p">}</span>
  <span class="p">([</span><span class="nv">xform</span> <span class="nv">f</span> <span class="nv">init</span> <span class="nv">coll</span><span class="p">]</span> <span class="p">(</span><span class="nf">transduce</span> <span class="nv">xform</span> <span class="p">(</span><span class="nf">fseed</span> <span class="nv">f</span> <span class="nv">init</span><span class="p">)</span> <span class="nv">coll</span><span class="p">))</span>
  <span class="p">([</span><span class="nv">xform</span> <span class="nv">f</span> <span class="nv">coll</span><span class="p">]</span>
     <span class="p">(</span><span class="k">let </span><span class="p">[</span><span class="nv">f</span> <span class="p">(</span><span class="nf">xform</span> <span class="nv">f</span><span class="p">)</span>
           <span class="nv">ret</span> <span class="p">(</span><span class="nf">clojure.core.protocols/coll-reduce</span> <span class="nv">coll</span> <span class="nv">f</span> <span class="p">(</span><span class="nf">f</span><span class="p">))]</span>
       <span class="p">(</span><span class="nf">f</span> <span class="nv">ret</span><span class="p">))))</span></pre>
<p>By making the seeded reduce the special case, the init value can be wrapped in a composite init value by transducer-returned reducing functions. Now writing, for example, a pure <code class="highlight"><span class="nv">take</span></code> is possible.</p>
<p>This modification fixes the seeded reduce case but it requires allocating intermediate objects at each step which goes against the promise that transducers alleviate allocative pressure (promise inherited from reducers). So it&#8217;s fixable but for performance reasons transducer-returned reducing functions remain stateful.</p>
<h2>Once you go stateful&#8230;</h2>
<p>Once you assume transducer-returned reducing functions are stateful, you realize they have some cruft from their functional origins (this was <a lang=fr href="https://www.youtube.com/watch?v=R-e0jnlIMto#t=2992">discussed at the last Paris Clojure Meetup</a> (fr))):
<ul>
<li>0-arity always delegate to the 0-arity of the downstream reducing function,
<li>in any arity, the accumulator must be used in a linear manner with the only allowed operation being the 2-arity of the downstream function.
<li>don&#8217;t forget to check for <code class="highlight"><span class="nv">reduced</span></code> return values!
</ul>
<p>So the accumulator values are passed around but never used except by the most downstream reducing function: the one that was passed to <code class="highlight"><span class="nv">transduce</span></code> by the user! Why not, then, encapsulates the accumulator state in a process?</p>
<p>A process in this model has only two operations: process one input and complete which could be respectively mapped to 1-arity and 0-arity of a function:</p>
<pre class="highlight"><span class="p">(</span><span class="nf">fn</span>
  <span class="p">([]</span><span class="err"> </span><span class="nv">...</span><span class="p">)</span> <span class="c1">; completes the process, return value is unspecified</span>
  <span class="p">([</span><span class="nv">x</span><span class="p">]</span> <span class="nv">...</span><span class="p">))</span> <span class="c1">; processes x, returns true when no more input should be fed in.</span></pre>
<p>So now <code class="highlight"><span class="nv">transduce</span></code> could be written as:</p>
<pre class="highlight"><span class="p">(</span><span class="kd">defn </span><span class="nv">transduce</span> <span class="p">[</span><span class="nv">xform</span> <span class="nv">f</span> <span class="nv">init</span> <span class="nv">coll</span><span class="p">]</span>
  <span class="p">(</span><span class="k">let </span><span class="p">[</span><span class="nv">vacc</span> <span class="p">(</span><span class="nf">volatile!</span> <span class="nv">init</span><span class="p">)</span>
        <span class="nv">p</span> <span class="p">(</span><span class="k">fn </span>
            <span class="p">([])</span>
            <span class="p">([</span><span class="nv">x</span><span class="p">]</span> <span class="p">(</span><span class="nf">reduced?</span> <span class="p">(</span><span class="nf">vswap!</span> <span class="nv">vacc</span> <span class="nv">f</span> <span class="nv">x</span><span class="p">))))</span>
        <span class="nv">p</span> <span class="p">(</span><span class="nf">xform</span> <span class="nv">p</span><span class="p">)]</span>
    <span class="p">(</span><span class="nf">feed!</span> <span class="nv">p</span> <span class="nv">coll</span><span class="p">)</span> <span class="c1">; transducers are now process -&gt; process</span>
    <span class="p">(</span><span class="nf">p</span><span class="p">)</span>
    <span class="p">(</span><span class="nf">f</span> <span class="p">(</span><span class="k">let </span><span class="p">[</span><span class="nv">acc</span> <span class="o">@</span><span class="nv">vacc</span><span class="p">]</span> <span class="p">(</span><span class="k">if </span><span class="p">(</span><span class="nf">reduced?</span> <span class="nv">acc</span><span class="p">)</span> <span class="o">@</span><span class="nv">acc</span> <span class="nv">acc</span><span class="p">)))))</span></pre>
<p>Where <code class="highlight"><span class="nv">feed!</span></code> is the iteration primitive – for exposition it can be implemented using <code class="highlight"><span class="nv">reduce</span></code> but it&#8217;s backwards: reduce should be implemented on top of <code class="highlight"><span class="nv">feed!</span></code>.</p>
<pre class="highlight"><span class="p">(</span><span class="kd">defn </span><span class="nv">feed!</span>
 <span class="s">&quot;Returns true if the process can&#39;t process more input.&quot;</span>
 <span class="p">[</span><span class="nv">p</span> <span class="nv">coll</span><span class="p">]</span>
  <span class="p">(</span><span class="nb">reduce </span><span class="o">#</span><span class="p">(</span><span class="nb">and </span><span class="p">(</span><span class="nf">p</span> <span class="nv">%2</span><span class="p">)</span> <span class="p">(</span><span class="nf">reduced</span> <span class="nv">true</span><span class="p">))</span> <span class="nv">false</span> <span class="nv">coll</span><span class="p">))</span></pre>
<p>Now we can try to reimplement some transducers as process-transforming functions:</p>
<pre class="highlight"><span class="p">(</span><span class="kd">defn </span><span class="nb">map </span><span class="p">[</span><span class="nv">f</span><span class="p">]</span>
  <span class="p">(</span><span class="k">fn </span><span class="p">[</span><span class="nv">p1</span><span class="p">]</span>
    <span class="p">(</span><span class="nf">fn</span>
      <span class="p">([]</span> <span class="p">(</span><span class="nf">p1</span><span class="p">))</span>
      <span class="p">([</span><span class="nv">x</span><span class="p">]</span> <span class="p">(</span><span class="nf">p1</span> <span class="p">(</span><span class="nf">f</span> <span class="nv">x</span><span class="p">))))))</span>

<span class="p">(</span><span class="kd">defn </span><span class="nb">filter </span><span class="p">[</span><span class="nv">pred</span><span class="p">]</span>
  <span class="p">(</span><span class="k">fn </span><span class="p">[</span><span class="nv">p1</span><span class="p">]</span>
    <span class="p">(</span><span class="nf">fn</span>
      <span class="p">([]</span> <span class="p">(</span><span class="nf">p1</span><span class="p">))</span>
      <span class="p">([</span><span class="nv">x</span><span class="p">]</span> <span class="p">(</span><span class="nb">and </span><span class="p">(</span><span class="nf">pred</span> <span class="nv">x</span><span class="p">)</span> <span class="p">(</span><span class="nf">p1</span> <span class="nv">x</span><span class="p">))))))</span>

<span class="p">(</span><span class="kd">defn </span><span class="nb">take </span><span class="p">[</span><span class="nv">n</span><span class="p">]</span>
  <span class="p">(</span><span class="k">fn </span><span class="p">[</span><span class="nv">p1</span><span class="p">]</span>
    <span class="p">(</span><span class="k">let </span><span class="p">[</span><span class="nv">vn</span> <span class="p">(</span><span class="nf">volatile!</span> <span class="p">(</span><span class="nb">dec </span><span class="nv">n</span><span class="p">))]</span>   
      <span class="p">(</span><span class="nf">fn</span>
        <span class="p">([]</span> <span class="p">(</span><span class="nf">p1</span><span class="p">))</span>
        <span class="p">([</span><span class="nv">x</span><span class="p">]</span> <span class="p">(</span><span class="nb">or </span><span class="p">(</span><span class="nb">neg? </span><span class="o">@</span><span class="nv">vn</span><span class="p">)</span> <span class="p">(</span><span class="nf">p1</span> <span class="nv">x</span><span class="p">)</span> <span class="p">(</span><span class="nb">neg? </span><span class="p">(</span><span class="nf">vswap!</span> <span class="nv">vn</span> <span class="nv">dec</span><span class="p">))))))))</span>

<span class="p">(</span><span class="kd">defn </span><span class="nv">partition-by</span> <span class="p">[</span><span class="nv">f</span><span class="p">]</span>
  <span class="p">(</span><span class="k">fn </span><span class="p">[</span><span class="nv">p</span><span class="p">]</span>
    <span class="p">(</span><span class="k">let </span><span class="p">[</span><span class="nv">a</span> <span class="p">(</span><span class="nf">java.util.ArrayList.</span><span class="p">)</span>
          <span class="nv">pv</span> <span class="p">(</span><span class="nf">volatile!</span> <span class="ss">::none</span><span class="p">)]</span>
      <span class="p">(</span><span class="nf">fn</span>
        <span class="p">([]</span>
          <span class="p">(</span><span class="nb">when-not </span><span class="p">(</span><span class="nf">.isEmpty</span> <span class="nv">a</span><span class="p">)</span>
            <span class="p">(</span><span class="k">let </span><span class="p">[</span><span class="nv">v</span> <span class="p">(</span><span class="nf">vec</span> <span class="p">(</span><span class="nf">.toArray</span> <span class="nv">a</span><span class="p">))]</span>
              <span class="c1">;;clear first!</span>
              <span class="p">(</span><span class="nf">.clear</span> <span class="nv">a</span><span class="p">)</span>
              <span class="p">(</span><span class="nf">p</span> <span class="nv">v</span><span class="p">)))</span>
          <span class="p">(</span><span class="nf">p</span><span class="p">))</span>
        <span class="p">([</span><span class="nv">input</span><span class="p">]</span>
          <span class="p">(</span><span class="k">let </span><span class="p">[</span><span class="nv">pval</span> <span class="o">@</span><span class="nv">pv</span>
                <span class="nb">val </span><span class="p">(</span><span class="nf">f</span> <span class="nv">input</span><span class="p">)]</span>
            <span class="p">(</span><span class="nf">vreset!</span> <span class="nv">pv</span> <span class="nv">val</span><span class="p">)</span>
            <span class="p">(</span><span class="k">if </span><span class="p">(</span><span class="nb">or </span><span class="p">(</span><span class="nb">identical? </span><span class="nv">pval</span> <span class="ss">::none</span><span class="p">)</span>
                  <span class="p">(</span><span class="nb">= val </span><span class="nv">pval</span><span class="p">))</span>
              <span class="p">(</span><span class="k">do </span><span class="p">(</span><span class="nf">.add</span> <span class="nv">a</span> <span class="nv">input</span><span class="p">)</span> <span class="nv">false</span><span class="p">)</span> <span class="c1">; .add returns true</span>
              <span class="p">(</span><span class="k">let </span><span class="p">[</span><span class="nv">v</span> <span class="p">(</span><span class="nf">vec</span> <span class="p">(</span><span class="nf">.toArray</span> <span class="nv">a</span><span class="p">))]</span>
                <span class="p">(</span><span class="nf">.clear</span> <span class="nv">a</span><span class="p">)</span>
                <span class="p">(</span><span class="nb">or </span><span class="p">(</span><span class="nf">p</span> <span class="nv">v</span><span class="p">)</span>
                  <span class="p">(</span><span class="k">do </span><span class="p">(</span><span class="nf">.add</span> <span class="nv">a</span> <span class="nv">input</span><span class="p">)</span> <span class="nv">false</span><span class="p">))))))))))</span></pre>
<h2>Conclusion</h2>
<p>To me the main advantage of transducers as process transformers is that their interface is a bit less complected; especially by not having to deal with reduced wrappers – because of that it may be easier to have them support primitive types.</p>
<p>The process model also seems to be less of a mismatch when reasoning about transducers in other contexts (e.g. sequences, channels).</p>
<h2>A better name</h2>
<p>There has been much discussion on how to best type them but not that much about how to name them in a more <em>patterned</em> way. What about <strong>BuilderDecoratorFactories</strong>?</p>
]]></content:encoded>
			<wfw:commentRss>http://clj-me.cgrand.net/2014/10/08/these-arent-the-reducing-functions-you-are-looking-for/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>The Rules of Transducer Club</title>
		<link>http://clj-me.cgrand.net/2014/09/11/the-rules-of-transducer-club/</link>
		<comments>http://clj-me.cgrand.net/2014/09/11/the-rules-of-transducer-club/#comments</comments>
		<pubDate>Thu, 11 Sep 2014 13:46:57 +0000</pubDate>
		<dc:creator><![CDATA[cgrand]]></dc:creator>
				<category><![CDATA[unsorted]]></category>

		<guid isPermaLink="false">http://clj-me.cgrand.net/?p=646</guid>
		<description><![CDATA[First rule: you don&#8217;t call a transducer.Second rule: only composition is allowed.Third rule: better stateful than pure. Here are the rationale behind each rule: First rule: you don&#8217;t call a transducer. Transducers may be so-called &#8220;stateful&#8221; that is they create stateful reducing functions. As a consequence you should not hold onto them for too long [&#8230;]]]></description>
				<content:encoded><![CDATA[<blockquote><p>First rule: you don&#8217;t call a transducer.<br />Second rule: only composition is allowed.<br />Third rule: better stateful than pure.</p></blockquote>
<p>Here are the rationale behind each rule:</p>
<h2>First rule: you don&#8217;t call a transducer.</h2>
<p>Transducers may be so-called &#8220;stateful&#8221; that is they create stateful reducing functions. As a consequence you should not hold onto them for too long (otherwise state goes sour&#8230;). And there&#8217;s no betetr way to not hold them for too long that to never get a hold on them at all!</p>
<p>That&#8217;s why <code>transduce</code>, <code>sequence</code>, <code>iteration</code> and <code>chan</code> all take a transducer to avoid you the perils of having to call it.</p>
<h2>Second rule: only composition is allowed.</h2>
<p>It&#8217;s a direct consequence of the first rule: you should only compose transducers.</p>
<h2>Third rule: better stateful than pure.</h2>
<p>This one is a bit more subtle and caused exclusively by <code>transduce</code>.</p>
<p>A reducing fn has now threes arities: <code>[] -> acc</code>, <code>[acc x] -> acc</code> and <code>[acc] -> result</code>.</p>
<p>When one wants to pass state from one step to the next there are two options: be pure and pass it in the accumulator (and you&#8217;ll use the 1-arity to clean up) or be stateful.</p>
<p>It turns out that the pure option is a bad one, for two reasons. First reason, it&#8217;s going to increase object churn. Second reason, it&#8217;s going to change the type of the accumulator and this is a problem because:
<ul>
<li>in <code>transduce</code> an init value may be specified and this init value must be of the type of the accumulator,
<li> we don&#8217;t have a way to map from the result domain to the accumulator domain.
</ul>
<p>So it means the user has to be aware of an implementation detail of your transducer (the way you smuggle state in the accumulator) to craft a proper init value. It&#8217;s an abstraction leak, it&#8217;s bad. Be stateful.</p>
]]></content:encoded>
			<wfw:commentRss>http://clj-me.cgrand.net/2014/09/11/the-rules-of-transducer-club/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Optimal justification of text with Dynamic Programming</title>
		<link>http://clj-me.cgrand.net/2014/08/29/optimal-justification-of-text-with-dynamic-programming/</link>
		<comments>http://clj-me.cgrand.net/2014/08/29/optimal-justification-of-text-with-dynamic-programming/#comments</comments>
		<pubDate>Fri, 29 Aug 2014 09:46:02 +0000</pubDate>
		<dc:creator><![CDATA[cgrand]]></dc:creator>
				<category><![CDATA[unsorted]]></category>

		<guid isPermaLink="false">http://clj-me.cgrand.net/?p=638</guid>
		<description><![CDATA[This is an exercise in dynamic programming I found on /ftp. The goal is to tightly arrange a given sequence of n words within page margins, maximizing overall neatness. To be more precise, we wish to minimize the sum, over all lines except the last, of the cubes of the number of blank characters at [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>This is an exercise in dynamic programming I found on <a href="http://okmij.org/ftp/Algorithms.html#page-layout-dp">/ftp</a>.</p>
<blockquote><p>The goal is to tightly arrange a given sequence of n words within page margins, maximizing overall neatness. To be more precise, we wish to minimize the sum, over all lines except the last, of the cubes of the number of blank characters at the end of each line. See the comments in the code for more details.</p>
<p>The algorithm has O(n^2) time and space complexities.
</p></blockquote>
<p>Below is my take on it and I believe the complexity to be O(n*width). I achieve linearity in the words count by laying out the text back to front: the key insight is that the optimal layout of some words only depends on the amount of space left on the current line, it does not depend on the layout of the words before them.</p>
<pre class="highlight"><span class="p">(</span><span class="kd">defn </span><span class="nv">layout</span> <span class="p">[</span><span class="nv">words</span> <span class="nv">width</span><span class="p">]</span>
  <span class="p">(</span><span class="k">let </span><span class="p">[</span><span class="nv">cat</span> <span class="p">(</span><span class="k">fn </span><span class="p">[</span><span class="nv">word</span> <span class="p">{</span><span class="nv">u</span> <span class="ss">:ugliness</span> <span class="p">[</span><span class="nv">l</span> <span class="o">&amp;</span> <span class="nv">ls</span><span class="p">]</span> <span class="ss">:lines</span><span class="p">}]</span> <span class="c1">; adds the word to the start of the first line</span>
              <span class="p">{</span><span class="ss">:ugliness</span> <span class="nv">u</span> <span class="ss">:lines</span> <span class="p">(</span><span class="nb">cons </span><span class="p">(</span><span class="nb">cons </span><span class="nv">word</span> <span class="nv">l</span><span class="p">)</span> <span class="nv">ls</span><span class="p">)})</span>
        <span class="nv">br</span> <span class="p">(</span><span class="k">fn </span><span class="p">[</span><span class="nb">rem </span><span class="p">{</span><span class="nv">u</span> <span class="ss">:ugliness</span> <span class="nv">ls</span> <span class="ss">:lines</span><span class="p">}]</span> <span class="c1">; adds a break (creates a new line)</span>
              <span class="p">{</span><span class="ss">:ugliness</span> <span class="p">(</span><span class="nb">+ </span><span class="nv">u</span> <span class="p">(</span><span class="nb">* rem rem </span><span class="nv">rem</span><span class="p">))</span> <span class="ss">:lines</span> <span class="p">(</span><span class="nb">cons </span><span class="p">()</span> <span class="nv">ls</span><span class="p">)})</span>
        <span class="nv">layout</span> <span class="c1">; layout words, knowing that the first line shouldn&#39;t have more than rem characters</span>
          <span class="p">(</span><span class="k">fn </span><span class="p">[</span><span class="nv">layout</span> <span class="nv">words</span> <span class="nv">rem</span><span class="p">]</span>
            <span class="p">(</span><span class="nb">if-let </span><span class="p">[[</span><span class="nv">word</span> <span class="o">&amp;</span> <span class="nv">ws</span><span class="p">]</span> <span class="p">(</span><span class="nb">seq </span><span class="nv">words</span><span class="p">)]</span>
              <span class="p">(</span><span class="nf">cond</span>
                <span class="p">(</span><span class="nb">= rem </span><span class="nv">width</span><span class="p">)</span> <span class="c1">; blank line ahead</span>
                  <span class="p">(</span><span class="nf">cat</span> <span class="nv">word</span> <span class="p">(</span><span class="nf">layout</span> <span class="nv">ws</span> <span class="p">(</span><span class="nb">- rem </span><span class="p">(</span><span class="nb">count </span><span class="nv">word</span><span class="p">))))</span>
                <span class="p">(</span><span class="nb">&lt; </span><span class="p">(</span><span class="nb">count </span><span class="nv">word</span><span class="p">)</span> <span class="nv">rem</span><span class="p">)</span> <span class="c1">; enough room for a space and the current word</span>
                  <span class="p">(</span><span class="nf">cat</span> <span class="nv">word</span>
                    <span class="p">(</span><span class="nb">min-key </span><span class="ss">:ugliness</span>
                      <span class="p">(</span><span class="nf">layout</span> <span class="nv">ws</span> <span class="p">(</span><span class="nb">- rem </span><span class="p">(</span><span class="nb">count </span><span class="nv">word</span><span class="p">)</span> <span class="mi">1</span><span class="p">))</span>
                      <span class="p">(</span><span class="nf">br</span> <span class="nb">rem </span><span class="p">(</span><span class="nf">layout</span> <span class="nv">ws</span> <span class="nv">width</span><span class="p">))))</span>
                <span class="ss">:else</span> <span class="p">(</span><span class="nf">br</span> <span class="nb">rem </span><span class="p">(</span><span class="nf">layout</span> <span class="nv">words</span> <span class="nv">width</span><span class="p">)))</span>
              <span class="p">{</span><span class="ss">:ugliness</span> <span class="mi">0</span> <span class="ss">:lines</span> <span class="p">(</span><span class="nb">list </span><span class="p">())}))</span>
        <span class="nv">mlayout</span> <span class="p">(</span><span class="nf">memoize</span> <span class="nv">layout</span><span class="p">)</span>
        <span class="nv">layout</span> <span class="p">(</span><span class="k">fn </span><span class="nv">self</span> <span class="p">[</span><span class="nv">words</span> <span class="nv">rem</span><span class="p">]</span> <span class="p">(</span><span class="nf">mlayout</span> <span class="nv">self</span> <span class="nv">words</span> <span class="nv">rem</span><span class="p">))]</span>
    <span class="p">(</span><span class="ss">:lines</span> <span class="p">(</span><span class="nf">layout</span> <span class="nv">words</span> <span class="nv">width</span><span class="p">))))</span></pre>
<p>This is an exercise I prepared for a Lambda Next workshop but that we never used.</p>
]]></content:encoded>
			<wfw:commentRss>http://clj-me.cgrand.net/2014/08/29/optimal-justification-of-text-with-dynamic-programming/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Macros, closures and unexpected object retention</title>
		<link>http://clj-me.cgrand.net/2013/09/11/macros-closures-and-unexpected-object-retention/</link>
		<comments>http://clj-me.cgrand.net/2013/09/11/macros-closures-and-unexpected-object-retention/#comments</comments>
		<pubDate>Wed, 11 Sep 2013 10:37:11 +0000</pubDate>
		<dc:creator><![CDATA[cgrand]]></dc:creator>
				<category><![CDATA[unsorted]]></category>

		<guid isPermaLink="false">http://clj-me.cgrand.net/?p=619</guid>
		<description><![CDATA[The common advice about macros is that they should emit as little code as possible and delegate to ancillary functions as soon as possible. Here is an example from clojure.java.jdbc: (defmacro transaction [&#38; body] `(transaction* (fn [] ~@body))) I still think this is good advice but it has unintended consequences. The problem with this piece [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>The common advice about macros is that they should emit as little code as possible and delegate to ancillary functions as soon as possible. Here is an example from <code class="highlight"><span class="nv">clojure</span><span class="o">.</span><span class="nv">java</span><span class="o">.</span><span class="nv">jdbc</span></code>:</p>
<pre class="highlight"><span class="p">(</span><span class="k">defmacro </span><span class="nv">transaction</span>
  <span class="p">[</span><span class="nv">&amp;</span> <span class="nv">body</span><span class="p">]</span>
  <span class="o">`</span><span class="p">(</span><span class="nf">transaction*</span> <span class="p">(</span><span class="k">fn </span><span class="p">[]</span> <span class="nv">~@body</span><span class="p">)))</span></pre>
<p>I still think this is good advice but it has unintended consequences. The problem with this piece of code is that all closed-over objects in <code class="highlight"><span class="nv">body</span></code> are going to be retained longer than expected, longer than they would have been retained if the macro had emitted all the logic implemented in <code class="highlight"><span class="nv">transaction*</span></code> instead of delegating to it. (<a href='https://groups.google.com/d/msg/clojure/iw7Rwp7wmjo/VSw40hboo1YJ'>See this discussion</a> as an example of issues created by such code.)</p>
<p>The closure object has references to all closed-over objects and since a closure can be called many times, it can&#8217;t get rid of them. So the only time where they are going to be garbage collectible is once the closure itself becomes collectible&#8230; and a closure can&#8217;t be collected while it&#8217;s executing.</p>
<p>Helpfully there&#8217;s a low-level feature for that:</p>
<pre class="highlight"><span class="p">(</span><span class="k">defmacro </span><span class="nv">transaction</span>
  <span class="p">[</span><span class="nv">&amp;</span> <span class="nv">body</span><span class="p">]</span>
  <span class="o">`</span><span class="p">(</span><span class="nf">transaction*</span> <span class="p">(</span><span class="nf">^:once</span> <span class="nv">fn*</span> <span class="p">[]</span> <span class="nv">~@body</span><span class="p">)))</span></pre>
<p>It instructs the compiler that the closure is one-shot and that closed-over references should be cleared, thus allowing referenced objects to be garbage collected before the closure returns.</p>
<p>This problem is not specific to macros but can easily be solved in most cases: the closure is an implementation detail and the macro writer knows enough about its life-cycle to fix it. However any regular closure (fn or reify) is going to prevent closed-overs to be garbage-collected while one of its (java) methods is running because the closure is referenced by the stack.</p>
<p>During the last <a href="http://lambdanext.eu/">LambdaNext workshop</a> a delegate stumbled on such a case while experimenting with reducers (and incidentally it made me understand a memory issue I worked around last year):</p>
<pre class="highlight"><span class="nv">=&gt;</span> <span class="p">(</span><span class="nb">time </span><span class="p">(</span><span class="nb">reduce </span><span class="nv">+</span> <span class="mi">0</span> <span class="p">(</span><span class="nb">map </span><span class="nv">identity</span> <span class="p">(</span><span class="nb">range </span><span class="mi">1</span><span class="nv">e8</span><span class="p">))))</span>
<span class="s">&quot;Elapsed time: 5729.579 msecs&quot;</span>
<span class="mi">4999999950000000</span>
<span class="nv">=&gt;</span> <span class="p">(</span><span class="nb">time </span><span class="p">(</span><span class="nb">reduce </span><span class="nv">+</span> <span class="mi">0</span> <span class="p">(</span><span class="nf">r/map</span> <span class="nv">identity</span> <span class="p">(</span><span class="nb">range </span><span class="mi">1</span><span class="nv">e8</span><span class="p">))))</span>
<span class="c1">;; Interrupting...</span>
<span class="nv">Expression</span> <span class="nv">was</span> <span class="nv">interrupted:</span> <span class="nv">null</span></pre>
<p>(Depending on your memory settings, you may have to tweak the length of the range to exhibit the problem; more details <a href="https://groups.google.com/forum/#!topic/clojure-dev/t6NhGnYNH1A">here</a>)</p>
<p>If one modifies reducers to not use (java) methods but external extensions:</p>
<pre class="highlight"><span class="p">(</span><span class="nb">in-ns </span><span class="ss">&#39;clojure</span><span class="o">.</span><span class="nv">core</span><span class="o">.</span><span class="nv">reducers</span><span class="p">)</span>

<span class="p">(</span><span class="nf">defrecord</span> <span class="nv">Folder</span> <span class="p">[</span><span class="nv">coll</span> <span class="nv">xf</span><span class="p">])</span>

<span class="p">(</span><span class="k">defn </span><span class="nv">folder</span>
  <span class="s">&quot;Given a foldable collection, and a transformation function xf,</span>
<span class="s">  returns a foldable collection, where any supplied reducing</span>
<span class="s">  fn will be transformed by xf. xf is a function of reducing fn to</span>
<span class="s">  reducing fn.&quot;</span>
  <span class="p">{</span><span class="nv">:added</span> <span class="s">&quot;1.5&quot;</span><span class="p">}</span>
  <span class="p">([</span><span class="nv">coll</span> <span class="nv">xf</span><span class="p">]</span>
     <span class="p">(</span><span class="nf">Folder</span><span class="o">.</span> <span class="nv">coll</span> <span class="nv">xf</span><span class="p">)))</span>

<span class="p">(</span><span class="nf">extend-type</span> <span class="nv">Folder</span>
      <span class="nv">clojure</span><span class="o">.</span><span class="nv">core</span><span class="o">.</span><span class="nv">protocols/CollReduce</span>
      <span class="p">(</span><span class="nf">coll-reduce</span> <span class="p">[</span><span class="nv">fldr</span> <span class="nv">f1</span><span class="p">]</span>
                   <span class="p">(</span><span class="nf">clojure</span><span class="o">.</span><span class="nv">core</span><span class="o">.</span><span class="nv">protocols/coll-reduce</span> <span class="p">(</span><span class="nf">:coll</span> <span class="nv">fldr</span><span class="p">)</span> <span class="p">((</span><span class="nf">:xf</span> <span class="nv">fldr</span><span class="p">)</span> <span class="nv">f1</span><span class="p">)</span> <span class="p">(</span><span class="nf">f1</span><span class="p">)))</span>
      <span class="p">(</span><span class="nf">coll-reduce</span> <span class="p">[</span><span class="nv">fldr</span> <span class="nv">f1</span> <span class="nv">init</span><span class="p">]</span>
                   <span class="p">(</span><span class="nf">clojure</span><span class="o">.</span><span class="nv">core</span><span class="o">.</span><span class="nv">protocols/coll-reduce</span> <span class="p">(</span><span class="nf">:coll</span> <span class="nv">fldr</span><span class="p">)</span> <span class="p">((</span><span class="nf">:xf</span> <span class="nv">fldr</span><span class="p">)</span> <span class="nv">f1</span><span class="p">)</span> <span class="nv">init</span><span class="p">))</span>

      <span class="nv">CollFold</span>
      <span class="p">(</span><span class="nf">coll-fold</span> <span class="p">[</span><span class="nv">fldr</span> <span class="nv">n</span> <span class="nv">combinef</span> <span class="nv">reducef</span><span class="p">]</span>
                 <span class="p">(</span><span class="nf">coll-fold</span> <span class="p">(</span><span class="nf">:coll</span> <span class="nv">fldr</span><span class="p">)</span> <span class="nv">n</span> <span class="nv">combinef</span> <span class="p">((</span><span class="nf">:xf</span> <span class="nv">fldr</span><span class="p">)</span> <span class="nv">reducef</span><span class="p">))))</span></pre>
<p>Then the problem disappears:</p>
<pre class="highlight"><span class="p">(</span><span class="nb">in-ns </span><span class="ss">&#39;user</span><span class="p">)</span>
<span class="nv">=&gt;</span> <span class="p">(</span><span class="nb">time </span><span class="p">(</span><span class="nb">reduce </span><span class="nv">+</span> <span class="mi">0</span> <span class="p">(</span><span class="nf">r/map</span> <span class="nv">identity</span> <span class="p">(</span><span class="nb">range </span><span class="mi">1</span><span class="nv">e8</span><span class="p">))))</span>
<span class="s">&quot;Elapsed time: 4437.012 msecs&quot;</span>
<span class="mi">4999999950000000</span></pre>
<p>This is because the protocol methods is not a java method of the reducer object anymore and thus it can be reclaimed while the (protocol) method is executing.</p>
<p>So next time you have a memory issue, look for closures tying the life-cycle of their closed-overs to theirs!</p>
]]></content:encoded>
			<wfw:commentRss>http://clj-me.cgrand.net/2013/09/11/macros-closures-and-unexpected-object-retention/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Tarjan&#8217;s strongly connected components algorithm</title>
		<link>http://clj-me.cgrand.net/2013/03/18/tarjans-strongly-connected-components-algorithm/</link>
		<comments>http://clj-me.cgrand.net/2013/03/18/tarjans-strongly-connected-components-algorithm/#comments</comments>
		<pubDate>Mon, 18 Mar 2013 17:48:42 +0000</pubDate>
		<dc:creator><![CDATA[cgrand]]></dc:creator>
				<category><![CDATA[unsorted]]></category>

		<guid isPermaLink="false">http://clj-me.cgrand.net/?p=605</guid>
		<description><![CDATA[I dislike algorithms that are full of indices and mutations. Not because they are bad but because I always have the feeling that the core idea is buried. As such, Tarjan&#8217;s SCC algorithm irked me. So I took the traditional algorithm, implemented it in Clojure with explicit environment passing, then I replaced indices by explicit [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>I dislike algorithms that are full of indices and mutations. Not because they are bad but because I always have the feeling that the core idea is buried. As such, <a href="http://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm">Tarjan&#8217;s SCC algorithm</a> irked me.</p>
<p>So I took the traditional algorithm, <a href="https://gist.github.com/cgrand/5188919/33e2152da2c0eb5bb91e023b23db7395cf9c9d66">implemented it in Clojure with explicit environment passing</a>, then I <a href="https://gist.github.com/cgrand/5188919/a2d7347f24d0121eaa955863c71cacab196cc7a7">replaced indices by explicit stacks</a> (thanks to persistence!) and <a href="https://gist.github.com/cgrand/5188919/715bcdf1da0500008e6fd2227fb4cf5787223006">after some tweaks</a>, I realized that I&#8217;ve gone full circle and could <a href="https://gist.github.com/cgrand/5188919/4cdd7d9383e3a88ce02fd7ea23bcdd3d4ecc1e4f">switch to stacks lengths</a> instead of stacks themselves and <a href="https://gist.github.com/cgrand/5188919/a7b208521c9bef3632effc3b47e262f41f92f580">get rid of the loop</a>. However the whole process made the code cleaner to my eye. You can <a href="https://gist.github.com/cgrand/5188919/revisions">look at the whole history</a>.</p>
<p>Here is the resulting code:</p>
<pre class="highlight"><span class="p">(</span><span class="k">defn </span><span class="nv">tarjan</span> 
  <span class="s">&quot;Returns the strongly connected components of a graph specified by its nodes</span>
<span class="s">   and a successor function succs from node to nodes.</span>
<span class="s">   The used algorithm is Tarjan&#39;s one.&quot;</span>
  <span class="p">[</span><span class="nv">nodes</span> <span class="nv">succs</span><span class="p">]</span>
  <span class="p">(</span><span class="nf">letfn</span> <span class="p">[(</span><span class="nf">sc</span> <span class="p">[</span><span class="nv">env</span> <span class="nv">node</span><span class="p">]</span>
            <span class="c1">; env is a map from nodes to stack length or nil,</span>
            <span class="c1">; nil means the node is known to belong to another SCC</span>
            <span class="c1">; there are two special keys: ::stack for the current stack </span>
            <span class="c1">; and ::sccs for the current set of SCCs</span>
            <span class="p">(</span><span class="k">if </span><span class="p">(</span><span class="nb">contains? </span><span class="nv">env</span> <span class="nv">node</span><span class="p">)</span>
              <span class="nv">env</span>
              <span class="p">(</span><span class="k">let </span><span class="p">[</span><span class="nv">stack</span> <span class="p">(</span><span class="nf">::stack</span> <span class="nv">env</span><span class="p">)</span>
                    <span class="nv">n</span> <span class="p">(</span><span class="nb">count </span><span class="nv">stack</span><span class="p">)</span>
                    <span class="nv">env</span> <span class="p">(</span><span class="nb">assoc </span><span class="nv">env</span> <span class="nv">node</span> <span class="nv">n</span> <span class="nv">::stack</span> <span class="p">(</span><span class="nb">conj </span><span class="nv">stack</span> <span class="nv">node</span><span class="p">))</span>
                    <span class="nv">env</span> <span class="p">(</span><span class="nb">reduce </span><span class="p">(</span><span class="k">fn </span><span class="p">[</span><span class="nv">env</span> <span class="nv">succ</span><span class="p">]</span>
                                  <span class="p">(</span><span class="k">let </span><span class="p">[</span><span class="nv">env</span> <span class="p">(</span><span class="nf">sc</span> <span class="nv">env</span> <span class="nv">succ</span><span class="p">)]</span>
                                    <span class="p">(</span><span class="nb">assoc </span><span class="nv">env</span> <span class="nv">node</span> <span class="p">(</span><span class="nb">min </span><span class="p">(</span><span class="nb">or </span><span class="p">(</span><span class="nf">env</span> <span class="nv">succ</span><span class="p">)</span> <span class="nv">n</span><span class="p">)</span> <span class="p">(</span><span class="nf">env</span> <span class="nv">node</span><span class="p">)))))</span>
                          <span class="nv">env</span> <span class="p">(</span><span class="nf">succs</span> <span class="nv">node</span><span class="p">))]</span>
                <span class="p">(</span><span class="k">if </span><span class="p">(</span><span class="nb">= </span><span class="nv">n</span> <span class="p">(</span><span class="nf">env</span> <span class="nv">node</span><span class="p">))</span> <span class="c1">; no link below us in the stack, call it a SCC</span>
                  <span class="p">(</span><span class="k">let </span><span class="p">[</span><span class="nv">nodes</span> <span class="p">(</span><span class="nf">::stack</span> <span class="nv">env</span><span class="p">)</span>
                        <span class="nv">scc</span> <span class="p">(</span><span class="nb">set </span><span class="p">(</span><span class="nb">take </span><span class="p">(</span><span class="nb">- </span><span class="p">(</span><span class="nb">count </span><span class="nv">nodes</span><span class="p">)</span> <span class="nv">n</span><span class="p">)</span> <span class="nv">nodes</span><span class="p">))</span>
                        <span class="c1">; clear all stack lengths for these nodes since this SCC is done</span>
                        <span class="nv">env</span> <span class="p">(</span><span class="nb">reduce </span><span class="o">#</span><span class="p">(</span><span class="nv">assoc</span> <span class="nv">%1</span> <span class="nv">%2</span> <span class="nv">nil</span><span class="p">)</span> <span class="nv">env</span> <span class="nv">scc</span><span class="p">)]</span>
                    <span class="p">(</span><span class="nb">assoc </span><span class="nv">env</span> <span class="nv">::stack</span> <span class="nv">stack</span> <span class="nv">::sccs</span> <span class="p">(</span><span class="nb">conj </span><span class="p">(</span><span class="nf">::sccs</span> <span class="nv">env</span><span class="p">)</span> <span class="nv">scc</span><span class="p">)))</span>
                  <span class="nv">env</span><span class="p">))))]</span>
    <span class="p">(</span><span class="nf">::sccs</span> <span class="p">(</span><span class="nb">reduce </span><span class="nv">sc</span> <span class="p">{</span><span class="nv">::stack</span> <span class="p">()</span> <span class="nv">::sccs</span> <span class="o">#</span><span class="p">{}}</span> <span class="nv">nodes</span><span class="p">))))</span></pre>
<p>As always, if you need some short-term help with Clojure (code review, consulting, training etc.), contact me!</p>
]]></content:encoded>
			<wfw:commentRss>http://clj-me.cgrand.net/2013/03/18/tarjans-strongly-connected-components-algorithm/feed/</wfw:commentRss>
		<slash:comments>13</slash:comments>
		</item>
		<item>
		<title>Decaying lists: log scale for lists</title>
		<link>http://clj-me.cgrand.net/2013/02/12/decaying-lists-log-scale-for-lists/</link>
		<comments>http://clj-me.cgrand.net/2013/02/12/decaying-lists-log-scale-for-lists/#comments</comments>
		<pubDate>Tue, 12 Feb 2013 11:44:05 +0000</pubDate>
		<dc:creator><![CDATA[cgrand]]></dc:creator>
				<category><![CDATA[pondering]]></category>

		<guid isPermaLink="false">http://clj-me.cgrand.net/?p=588</guid>
		<description><![CDATA[The concept of exponentially decaying lists by David Barbour piqued my interest and I implemented it. It can be summed up as: log scale for lists! As for log scale, decaying lists allow to manage large range of values and thus to get a better understanding of the data. So a decaying list grows logarithmically [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>The concept of <a href="http://awelonblue.wordpress.com/2013/01/24/exponential-decay-of-history-improved/">exponentially decaying lists</a> by David Barbour piqued my interest and <a href="https://gist.github.com/cgrand/4722914">I implemented it</a>. It can be summed up as: log scale for lists!</p>
<p>As for log scale, decaying lists allow to manage large range of values and thus to get a better understanding of the data.</p>
<p>So a decaying list grows logarithmically with the number of <code class="highlight"><span class="nv">conj</span></code>ed items. It follows that some items are dropped when others are inserted. Let&#8217;s see:</p>
<pre class="highlight"><span class="nv">=&gt;</span> <span class="p">(</span><span class="nb">seq </span><span class="p">(</span><span class="nb">into </span><span class="p">(</span><span class="nf">decaying-list</span><span class="p">)</span> <span class="p">(</span><span class="nb">range </span><span class="mi">100</span><span class="p">)))</span>
<span class="p">(</span><span class="mi">99</span> <span class="mi">98</span> <span class="mi">97</span> <span class="mi">96</span> <span class="mi">95</span> <span class="mi">94</span> <span class="mi">92</span> <span class="mi">91</span> <span class="mi">90</span> <span class="mi">89</span> <span class="mi">88</span> <span class="mi">87</span> <span class="mi">86</span> <span class="mi">84</span> <span class="mi">83</span> <span class="mi">80</span> <span class="mi">70</span> <span class="mi">65</span> <span class="mi">61</span> <span class="mi">59</span> <span class="mi">57</span> <span class="mi">49</span> <span class="mi">44</span> <span class="mi">30</span> <span class="mi">29</span> <span class="mi">27</span> <span class="mi">25</span> <span class="mi">23</span> <span class="mi">22</span> <span class="mi">18</span> <span class="mi">12</span> <span class="mi">4</span> <span class="mi">0</span><span class="p">)</span></pre>
<p>So most of the recent items are there but the older elements have a greater probability to have been dropped.</p>
<p>A decaying list is parametrized by its half-life. The default half-life is 20, it means that an item in the list has one chance out of two to &#8220;survive&#8221; the insertion of 20 other items.</p>
<pre class="highlight"><span class="nv">=&gt;</span> <span class="p">(</span><span class="nb">seq </span><span class="p">(</span><span class="nb">into </span><span class="p">(</span><span class="nf">decaying-list</span> <span class="mi">5</span><span class="p">)</span> <span class="p">(</span><span class="nb">range </span><span class="mi">100</span><span class="p">)))</span> <span class="c1">; a half-life of 5 conjs</span>
<span class="p">(</span><span class="mi">99</span> <span class="mi">98</span> <span class="mi">97</span> <span class="mi">96</span> <span class="mi">95</span> <span class="mi">94</span> <span class="mi">93</span> <span class="mi">91</span> <span class="mi">83</span> <span class="mi">81</span> <span class="mi">79</span> <span class="mi">78</span> <span class="mi">68</span> <span class="mi">61</span> <span class="mi">57</span> <span class="mi">54</span> <span class="mi">52</span> <span class="mi">31</span> <span class="mi">15</span><span class="p">)</span></pre>
<p>You can know where the next decay (if any: <code class="highlight"><span class="nv">nil</span></code> is returned when no decay) is going to happen:</p>
<pre class="highlight"><span class="nv">=&gt;</span> <span class="p">(</span><span class="k">def </span><span class="nv">dl</span> <span class="p">(</span><span class="nb">into </span><span class="p">(</span><span class="nf">decaying-list</span> <span class="mi">5</span><span class="p">)</span> <span class="p">(</span><span class="nb">range </span><span class="mi">100</span><span class="p">)))</span>
<span class="o">#</span><span class="ss">&#39;net</span><span class="o">.</span><span class="nv">cgrand</span><span class="o">.</span><span class="nv">decay/dl</span>
<span class="nv">=&gt;</span> <span class="p">(</span><span class="nf">decay-loc</span> <span class="nv">dl</span><span class="p">)</span>
<span class="p">[(</span><span class="mi">93</span> <span class="mi">95</span> <span class="mi">97</span> <span class="mi">98</span> <span class="mi">99</span><span class="p">)</span> <span class="p">(</span><span class="mi">92</span> <span class="mi">91</span> <span class="mi">89</span> <span class="mi">87</span> <span class="mi">85</span> <span class="mi">81</span> <span class="mi">77</span> <span class="mi">72</span> <span class="mi">71</span> <span class="mi">63</span> <span class="mi">54</span> <span class="mi">52</span> <span class="mi">46</span> <span class="mi">31</span> <span class="mi">20</span> <span class="mi">16</span><span class="p">)]</span></pre>
<p>So here the decay is going to happen between 93 and 92 (the first items of the &#8220;left&#8221; and &#8220;right&#8221; sequences). By default the most recent one is kept.</p>
<pre class="highlight"><span class="nv">=&gt;</span> <span class="p">(</span><span class="nb">seq </span><span class="p">(</span><span class="nb">conj </span><span class="nv">dl</span> <span class="mi">100</span><span class="p">))</span>
<span class="p">(</span><span class="mi">100</span> <span class="mi">99</span> <span class="mi">98</span> <span class="mi">97</span> <span class="mi">95</span> <span class="mi">93</span> <span class="mi">91</span> <span class="mi">89</span> <span class="mi">87</span> <span class="mi">85</span> <span class="mi">81</span> <span class="mi">77</span> <span class="mi">72</span> <span class="mi">71</span> <span class="mi">63</span> <span class="mi">54</span> <span class="mi">52</span> <span class="mi">46</span> <span class="mi">31</span> <span class="mi">20</span> <span class="mi">16</span><span class="p">)</span></pre>
<p>Indeed 92 has been dropped. (Repeated calls to <code class="highlight"><span class="nv">decay-loc</span></code> always yield the same result.)</p>
<p>However we may elect to synthetize a new value rather than just keep one of the two candidates to decay. For example we can compute their average:</p>
<pre class="highlight"><span class="nv">=&gt;</span> <span class="p">(</span><span class="nb">seq </span><span class="p">(</span><span class="nb">into </span><span class="p">(</span><span class="nf">decaying-list</span> <span class="mi">5</span> 
                <span class="nv">:collapse</span> <span class="p">(</span><span class="k">fn </span><span class="p">[</span><span class="nv">dl</span><span class="p">]</span>
                            <span class="p">(</span><span class="k">let </span><span class="p">[[[</span><span class="nv">l</span><span class="p">]</span> <span class="p">[</span><span class="nv">r</span><span class="p">]]</span> <span class="p">(</span><span class="nf">decay-loc</span> <span class="nv">dl</span><span class="p">)]</span> 
                              <span class="p">(</span><span class="nb">/ </span><span class="p">(</span><span class="nb">+ </span><span class="nv">l</span> <span class="nv">r</span><span class="p">)</span> <span class="mf">2.0</span><span class="p">))))</span>
          <span class="p">(</span><span class="nb">range </span><span class="mi">100</span><span class="p">)))</span>
<span class="p">(</span><span class="mi">99</span> <span class="mi">98</span> <span class="mi">97</span> <span class="mf">95.5</span> <span class="mf">93.5</span> <span class="mf">91.5</span> <span class="mi">90</span> <span class="mi">89</span> <span class="mf">87.125</span> <span class="mf">82.75</span> <span class="mf">79.5</span> <span class="mf">72.875</span> <span class="mf">64.8125</span> <span class="mf">60.875</span> <span class="mi">58</span> <span class="mf">50.732421875</span> <span class="mf">27.0</span> <span class="mf">17.75</span> <span class="mf">11.25</span> <span class="mf">2.8125</span><span class="p">)</span></pre>
<p>Or something a bit more elaborate (and precise):</p>
<pre class="highlight"><span class="nv">=&gt;</span> <span class="p">(</span><span class="k">defn </span><span class="nv">stats</span> <span class="p">[</span><span class="nv">x</span><span class="p">]</span>
     <span class="p">(</span><span class="k">if </span><span class="p">(</span><span class="nb">map? </span><span class="nv">x</span><span class="p">)</span>
       <span class="nv">x</span>
       <span class="p">{</span><span class="nv">:min</span> <span class="nv">x</span> <span class="nv">:max</span> <span class="nv">x</span> <span class="nv">:avg</span> <span class="nv">x</span> <span class="nv">:n</span> <span class="mi">1</span><span class="p">}))</span>
<span class="o">#</span><span class="ss">&#39;net</span><span class="o">.</span><span class="nv">cgrand</span><span class="o">.</span><span class="nv">decay/stats</span>
<span class="nv">=&gt;</span> <span class="p">(</span><span class="k">defn </span><span class="nv">merge-stats</span> <span class="p">[{</span><span class="nv">mina</span> <span class="nv">:min</span> <span class="nv">maxa</span> <span class="nv">:max</span> <span class="nv">avga</span> <span class="nv">:avg</span> <span class="nv">na</span> <span class="nv">:n</span><span class="p">}</span>
                      <span class="p">{</span><span class="nv">minb</span> <span class="nv">:min</span> <span class="nv">maxb</span> <span class="nv">:max</span> <span class="nv">avgb</span> <span class="nv">:avg</span> <span class="nv">nb</span> <span class="nv">:n</span><span class="p">}]</span>
     <span class="p">{</span><span class="nv">:min</span> <span class="p">(</span><span class="nb">min </span><span class="nv">mina</span> <span class="nv">minb</span><span class="p">)</span>
      <span class="nv">:max</span> <span class="p">(</span><span class="nb">max </span><span class="nv">maxa</span> <span class="nv">maxb</span><span class="p">)</span>
      <span class="nv">:avg</span> <span class="p">(</span><span class="nb">/ </span><span class="p">(</span><span class="nb">+ </span><span class="p">(</span><span class="nb">* </span><span class="nv">na</span> <span class="nv">avga</span><span class="p">)</span> <span class="p">(</span><span class="nb">* </span><span class="nv">nb</span> <span class="nv">avgb</span><span class="p">))</span> <span class="p">(</span><span class="nb">double </span><span class="p">(</span><span class="nb">+ </span><span class="nv">na</span> <span class="nv">nb</span><span class="p">)))</span>
      <span class="nv">:n</span> <span class="p">(</span><span class="nb">+ </span><span class="nv">na</span> <span class="nv">nb</span><span class="p">)})</span>
<span class="o">#</span><span class="ss">&#39;net</span><span class="o">.</span><span class="nv">cgrand</span><span class="o">.</span><span class="nv">decay/merge-stats</span>
<span class="nv">=&gt;</span> <span class="p">(</span><span class="nb">seq </span><span class="p">(</span><span class="nb">into </span><span class="p">(</span><span class="nf">decaying-list</span> <span class="mi">5</span> 
                <span class="nv">:collapse</span> <span class="p">(</span><span class="k">fn </span><span class="p">[</span><span class="nv">dl</span><span class="p">]</span>
                            <span class="p">(</span><span class="k">let </span><span class="p">[[[</span><span class="nv">l</span><span class="p">]</span> <span class="p">[</span><span class="nv">r</span><span class="p">]]</span> <span class="p">(</span><span class="nf">decay-loc</span> <span class="nv">dl</span><span class="p">)]</span> 
                              <span class="p">(</span><span class="nf">merge-stats</span> <span class="p">(</span><span class="nf">stats</span> <span class="nv">l</span><span class="p">)</span> <span class="p">(</span><span class="nf">stats</span> <span class="nv">r</span><span class="p">)))))</span>
          <span class="p">(</span><span class="nb">range </span><span class="mi">100</span><span class="p">)))</span>
<span class="p">(</span><span class="mi">99</span> <span class="mi">98</span> <span class="mi">97</span> <span class="p">{</span><span class="nv">:min</span> <span class="mi">92</span><span class="o">,</span> <span class="nv">:max</span> <span class="mi">96</span><span class="o">,</span> <span class="nv">:avg</span> <span class="mf">94.0</span><span class="o">,</span> <span class="nv">:n</span> <span class="mi">5</span><span class="p">}</span> <span class="mi">91</span> <span class="p">{</span><span class="nv">:min</span> <span class="mi">87</span><span class="o">,</span> <span class="nv">:max</span> <span class="mi">90</span><span class="o">,</span> <span class="nv">:avg</span> <span class="mf">88.5</span><span class="o">,</span> <span class="nv">:n</span> <span class="mi">4</span><span class="p">}</span> <span class="mi">86</span> <span class="mi">85</span> <span class="mi">84</span> <span class="mi">83</span> <span class="p">{</span><span class="nv">:min</span> <span class="mi">80</span><span class="o">,</span> <span class="nv">:max</span> <span class="mi">82</span><span class="o">,</span> <span class="nv">:avg</span> <span class="mf">81.0</span><span class="o">,</span> <span class="nv">:n</span> <span class="mi">3</span><span class="p">}</span> <span class="p">{</span><span class="nv">:min</span> <span class="mi">78</span><span class="o">,</span> <span class="nv">:max</span> <span class="mi">79</span><span class="o">,</span> <span class="nv">:avg</span> <span class="mf">78.5</span><span class="o">,</span> <span class="nv">:n</span> <span class="mi">2</span><span class="p">}</span> <span class="mi">77</span> <span class="p">{</span><span class="nv">:min</span> <span class="mi">70</span><span class="o">,</span> <span class="nv">:max</span> <span class="mi">76</span><span class="o">,</span> <span class="nv">:avg</span> <span class="mf">73.0</span><span class="o">,</span> <span class="nv">:n</span> <span class="mi">7</span><span class="p">}</span> <span class="mi">69</span> <span class="mi">68</span> <span class="p">{</span><span class="nv">:min</span> <span class="mi">49</span><span class="o">,</span> <span class="nv">:max</span> <span class="mi">67</span><span class="o">,</span> <span class="nv">:avg</span> <span class="mf">58.0</span><span class="o">,</span> <span class="nv">:n</span> <span class="mi">19</span><span class="p">}</span> <span class="p">{</span><span class="nv">:min</span> <span class="mi">41</span><span class="o">,</span> <span class="nv">:max</span> <span class="mi">48</span><span class="o">,</span> <span class="nv">:avg</span> <span class="mf">44.5</span><span class="o">,</span> <span class="nv">:n</span> <span class="mi">8</span><span class="p">}</span> <span class="p">{</span><span class="nv">:min</span> <span class="mi">36</span><span class="o">,</span> <span class="nv">:max</span> <span class="mi">40</span><span class="o">,</span> <span class="nv">:avg</span> <span class="mf">38.0</span><span class="o">,</span> <span class="nv">:n</span> <span class="mi">5</span><span class="p">}</span> <span class="mi">35</span> <span class="p">{</span><span class="nv">:min</span> <span class="mi">32</span><span class="o">,</span> <span class="nv">:max</span> <span class="mi">34</span><span class="o">,</span> <span class="nv">:avg</span> <span class="mf">33.0</span><span class="o">,</span> <span class="nv">:n</span> <span class="mi">3</span><span class="p">}</span> <span class="p">{</span><span class="nv">:min</span> <span class="mi">10</span><span class="o">,</span> <span class="nv">:max</span> <span class="mi">31</span><span class="o">,</span> <span class="nv">:avg</span> <span class="mf">20.5</span><span class="o">,</span> <span class="nv">:n</span> <span class="mi">22</span><span class="p">}</span> <span class="p">{</span><span class="nv">:min</span> <span class="mi">3</span><span class="o">,</span> <span class="nv">:max</span> <span class="mi">9</span><span class="o">,</span> <span class="nv">:avg</span> <span class="mf">6.0</span><span class="o">,</span> <span class="nv">:n</span> <span class="mi">7</span><span class="p">}</span> <span class="p">{</span><span class="nv">:min</span> <span class="mi">0</span><span class="o">,</span> <span class="nv">:max</span> <span class="mi">2</span><span class="o">,</span> <span class="nv">:avg</span> <span class="mf">1.0</span><span class="o">,</span> <span class="nv">:n</span> <span class="mi">3</span><span class="p">})</span></pre>
<p>Decaying lists can also maintain a state – that is updated after each conj or decay. Below the implementation, there is an <a href="https://gist.github.com/cgrand/4722914#file-decay-clj-L112">example of state management</a>.</p>
<p>You can also cap the length of the decaying list by using the <code class="highlight"><span class="nv">:capacity</span></code> option. A quick note on capacity: increasing the capacity by the half-life value (eg going from 1000 to 1050 when half-life is 50), <strong>doubles</strong> the range the decaying list remembers.</p>
]]></content:encoded>
			<wfw:commentRss>http://clj-me.cgrand.net/2013/02/12/decaying-lists-log-scale-for-lists/feed/</wfw:commentRss>
		<slash:comments>42</slash:comments>
		</item>
		<item>
		<title>From lazy seqs to reducers and back</title>
		<link>http://clj-me.cgrand.net/2013/02/11/from-lazy-seqs-to-reducers-and-back/</link>
		<comments>http://clj-me.cgrand.net/2013/02/11/from-lazy-seqs-to-reducers-and-back/#comments</comments>
		<pubDate>Mon, 11 Feb 2013 15:27:21 +0000</pubDate>
		<dc:creator><![CDATA[cgrand]]></dc:creator>
				<category><![CDATA[unsorted]]></category>

		<guid isPermaLink="false">http://clj-me.cgrand.net/?p=570</guid>
		<description><![CDATA[Sometimes in a seq pipeline, you know that some intermediate results are, well, intermediate and as such don&#8217;t need to be persistent but, on the whole, you still need the laziness. You can&#8217;t always opt for reducers because while being non-persistent (and thus faster), they imply getting rid of laziness. So you can&#8217;t mix and [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Sometimes in a seq pipeline, you know that some intermediate results are, well, intermediate and as such don&#8217;t need to be persistent but, on the whole, you still need the laziness.</p>
<p>You can&#8217;t always opt for <a href="http://clojure.com/blog/2012/05/08/reducers-a-library-and-model-for-collection-processing.html">reducers</a> because while being non-persistent (and thus faster), they imply getting rid of laziness.</p>
<p>So you can&#8217;t mix and match transformations on sequences and on reducers when you care for laziness. Or, wait!, maybe you can.</p>
<p>At core, reducers are just a clever way to compose big functions while giving the user the illusion of manipulating collections. So we should be able to apply a reducer pipeline if we get hold of the composed function. This is exactly what the below <code class="highlight"><span class="nv">seq-seq</span></code> function does:</p>
<pre class="highlight"><span class="p">(</span><span class="k">defn </span><span class="nv">reverse-conses</span> 
  <span class="p">([</span><span class="nv">s</span> <span class="nv">tail</span><span class="p">]</span> 
    <span class="p">(</span><span class="k">if </span><span class="p">(</span><span class="nb">identical? </span><span class="p">(</span><span class="nb">rest </span><span class="nv">s</span><span class="p">)</span> <span class="nv">tail</span><span class="p">)</span>
      <span class="nv">s</span>
      <span class="p">(</span><span class="nf">reverse-conses</span> <span class="nv">s</span> <span class="nv">tail</span> <span class="nv">tail</span><span class="p">)))</span>
  <span class="p">([</span><span class="nv">s</span> <span class="nv">from-tail</span> <span class="nv">to-tail</span><span class="p">]</span>
    <span class="p">(</span><span class="nb">loop </span><span class="p">[</span><span class="nv">f</span> <span class="nv">s</span> <span class="nv">b</span> <span class="nv">to-tail</span><span class="p">]</span>
      <span class="p">(</span><span class="k">if </span><span class="p">(</span><span class="nb">identical? </span><span class="nv">f</span> <span class="nv">from-tail</span><span class="p">)</span>
        <span class="nv">b</span>
        <span class="p">(</span><span class="nf">recur</span> <span class="p">(</span><span class="nb">rest </span><span class="nv">f</span><span class="p">)</span> <span class="p">(</span><span class="nb">cons </span><span class="p">(</span><span class="nb">first </span><span class="nv">f</span><span class="p">)</span> <span class="nv">b</span><span class="p">))))))</span>

<span class="p">(</span><span class="k">defn </span><span class="nv">seq-seq</span> <span class="p">[</span><span class="nv">f</span> <span class="nv">s</span><span class="p">]</span>
  <span class="p">(</span><span class="k">let </span><span class="p">[</span><span class="nv">f1</span> <span class="p">(</span><span class="nb">reduce </span><span class="o">#</span><span class="p">(</span><span class="nv">cons</span> <span class="nv">%2</span> <span class="nv">%1</span><span class="p">)</span> <span class="nv">nil</span> 
              <span class="p">(</span><span class="nf">f</span> <span class="p">(</span><span class="nf">reify</span> <span class="nv">clojure</span><span class="o">.</span><span class="nv">core</span><span class="o">.</span><span class="nv">protocols</span><span class="o">.</span><span class="nv">CollReduce</span>
                   <span class="p">(</span><span class="nf">coll-reduce</span> <span class="p">[</span><span class="nv">this</span> <span class="nv">f1</span> <span class="nv">init</span><span class="p">]</span>
                     <span class="nv">f1</span><span class="p">))))]</span>
    <span class="p">((</span><span class="k">fn </span><span class="nv">this</span> <span class="p">[</span><span class="nv">s</span><span class="p">]</span>
       <span class="p">(</span><span class="nf">lazy-seq</span> 
         <span class="p">(</span><span class="nb">when-let </span><span class="p">[</span><span class="nv">s</span> <span class="p">(</span><span class="nb">seq </span><span class="nv">s</span><span class="p">)]</span>
           <span class="p">(</span><span class="k">let </span><span class="p">[</span><span class="nv">more</span> <span class="p">(</span><span class="nf">this</span> <span class="p">(</span><span class="nb">rest </span><span class="nv">s</span><span class="p">))</span> 
                 <span class="nv">x</span> <span class="p">(</span><span class="nf">f1</span> <span class="nv">more</span> <span class="p">(</span><span class="nb">first </span><span class="nv">s</span><span class="p">))]</span>
             <span class="p">(</span><span class="k">if </span><span class="p">(</span><span class="nf">reduced?</span> <span class="nv">x</span><span class="p">)</span>
               <span class="p">(</span><span class="nf">reverse-conses</span> <span class="nv">@x</span> <span class="nv">more</span> <span class="nv">nil</span><span class="p">)</span>
               <span class="p">(</span><span class="nf">reverse-conses</span> <span class="nv">x</span> <span class="nv">more</span><span class="p">))))))</span> <span class="nv">s</span><span class="p">)))</span>

<span class="p">(</span><span class="k">defmacro </span><span class="nv">seq-&gt;&gt;</span> <span class="p">[</span><span class="nv">s</span> <span class="nv">&amp;</span> <span class="nv">forms</span><span class="p">]</span>
  <span class="o">`</span><span class="p">(</span><span class="nf">seq-seq</span> <span class="p">(</span><span class="k">fn </span><span class="p">[</span><span class="nv">n</span><span class="o">#</span><span class="p">]</span> <span class="p">(</span><span class="nf">-&gt;&gt;</span> <span class="nv">n</span><span class="o">#</span> <span class="nv">~@forms</span><span class="p">))</span> <span class="nv">~s</span><span class="p">))</span></pre>
<p>Note that the captured function (<code class="highlight"><span class="nv">f1</span></code>) may be impure, so don&#8217;t share it!</p>
<p>Now one can specifies non-persistent lazy seq pipelines:</p>
<pre class="highlight"><span class="nv">=&gt;</span> <span class="p">(</span><span class="nf">seq-&gt;&gt;</span> <span class="p">(</span><span class="nf">range</span><span class="p">)</span> <span class="p">(</span><span class="nf">r/map</span> <span class="nv">str</span><span class="p">)</span> <span class="p">(</span><span class="nf">r/take</span> <span class="mi">25</span><span class="p">)</span> <span class="p">(</span><span class="nf">r/drop</span> <span class="mi">5</span><span class="p">))</span>
<span class="p">(</span><span class="s">&quot;5&quot;</span> <span class="s">&quot;6&quot;</span> <span class="s">&quot;7&quot;</span> <span class="s">&quot;8&quot;</span> <span class="s">&quot;9&quot;</span> <span class="s">&quot;10&quot;</span> <span class="s">&quot;11&quot;</span> <span class="s">&quot;12&quot;</span> <span class="s">&quot;13&quot;</span> <span class="s">&quot;14&quot;</span> <span class="s">&quot;15&quot;</span> <span class="s">&quot;16&quot;</span> 
 <span class="s">&quot;17&quot;</span> <span class="s">&quot;18&quot;</span> <span class="s">&quot;19&quot;</span> <span class="s">&quot;20&quot;</span> <span class="s">&quot;21&quot;</span> <span class="s">&quot;22&quot;</span> <span class="s">&quot;23&quot;</span> <span class="s">&quot;24&quot;</span><span class="p">)</span></pre>
<p>To prove laziness is at play here:</p>
<pre class="highlight"><span class="nv">=&gt;</span> <span class="p">(</span><span class="nb">take </span><span class="mi">2</span> <span class="p">(</span><span class="nf">seq-&gt;&gt;</span> <span class="p">(</span><span class="nf">range</span><span class="p">)</span> <span class="p">(</span><span class="nf">r/map</span> <span class="o">#</span><span class="p">(</span><span class="nv">str</span> <span class="p">(</span><span class="nb">doto </span><span class="nv">%</span> <span class="nv">prn</span><span class="p">)))</span> <span class="p">(</span><span class="nf">r/take</span> <span class="mi">25</span><span class="p">)</span> <span class="p">(</span><span class="nf">r/drop</span> <span class="mi">5</span><span class="p">)))</span>
<span class="p">(</span><span class="mi">0</span>
<span class="mi">1</span>
<span class="mi">2</span>
<span class="mi">3</span>
<span class="mi">4</span>
<span class="mi">5</span>
<span class="mi">6</span>
<span class="s">&quot;5&quot;</span> <span class="s">&quot;6&quot;</span><span class="p">)</span></pre>
<p>Of course <code class="highlight"><span class="nv">seq-seq</span></code> could be made to support chunked sequences and, if you try to play with it, <a href="http://dev.clojure.org/jira/browse/CLJ-1160">beware of <code class="highlight"><span class="nv">r/mapcat</span></code></a>.</p>
<h4>Update:</h4>
<p>I added <code class="highlight"><span class="nv">reverse-conses</span></code> to account for the fact that when several items are added during a single call to <code class="highlight"><span class="nv">f1</span></code> (eg during a <code class="highlight"><span class="nv">r/mapcat</span></code> &#8220;step&#8221;) they were added in the wrong order – <a href="http://twitter.com/cgrand/status/300303928493481984">if only everything was more set-like<a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://clj-me.cgrand.net/2013/02/11/from-lazy-seqs-to-reducers-and-back/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>
