<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"><title>Eli Bendersky's website - Clojure</title><link href="https://eli.thegreenplace.net/" rel="alternate"></link><link href="https://eli.thegreenplace.net/feeds/clojure.atom.xml" rel="self"></link><id>https://eli.thegreenplace.net/</id><updated>2024-05-04T19:46:23-07:00</updated><entry><title>Building abstractions using higher-order functions</title><link href="https://eli.thegreenplace.net/2023/building-abstractions-using-higher-order-functions/" rel="alternate"></link><published>2023-02-04T05:40:00-08:00</published><updated>2023-03-06T13:26:10-08:00</updated><author><name>Eli Bendersky</name></author><id>tag:eli.thegreenplace.net,2023-02-04:/2023/building-abstractions-using-higher-order-functions/</id><summary type="html">&lt;p&gt;A &lt;em&gt;higher-order function&lt;/em&gt; is a function that takes other functions as arguments,
or returns a function as its result. Higher-order functions are an exceptionally
powerful software design tool because they can easily create new abstractions
and are composable. In this post I will present a case study - a set of …&lt;/p&gt;</summary><content type="html">&lt;p&gt;A &lt;em&gt;higher-order function&lt;/em&gt; is a function that takes other functions as arguments,
or returns a function as its result. Higher-order functions are an exceptionally
powerful software design tool because they can easily create new abstractions
and are composable. In this post I will present a case study - a set of
functions that defines an interesting problem domain. By reading and
understanding this code, hopefully anyone can appreciate the power and beauty of
higher-order functions and how they enable constructing powerful abstractions
from basic building blocks.&lt;/p&gt;
&lt;p&gt;One of my &lt;a class="reference external" href="https://eli.thegreenplace.net/2005/06/12/lessons-from-paip"&gt;all-time favorite&lt;/a&gt; programming
books is Peter Norvig's &lt;a class="reference external" href="https://norvig.github.io/paip-lisp/#/"&gt;PAIP&lt;/a&gt; . In
section &lt;em&gt;6.4 - A set of Searching Tools&lt;/em&gt;, it presents some code for defining
different variants of tree searching that I've always found very elegant.&lt;/p&gt;
&lt;p&gt;Here's a quick reimplementation of the main idea in Clojure (see &lt;a class="reference external" href="https://github.com/eliben/paip-in-clojure/tree/master/src/paip/6_tools"&gt;this
repository&lt;/a&gt; for
the full, runnable code); I'm using Clojure since it's a modern Lisp that &lt;a class="reference external" href="https://eli.thegreenplace.net/2017/clojure-the-perfect-language-to-expand-your-brain/"&gt;I
enjoy learning and using&lt;/a&gt;
from time to time.&lt;/p&gt;
&lt;p&gt;First, some prerequisites. As is often the case in dynamically-typed Lisp,
entities can be described in a very abstract way. The code presented here
searches trees, but there is no tree data structure per-se; it's defined using
functions. Specifically, there's a notion of a &amp;quot;state&amp;quot; (tree node) and a way
to get from a given state to its children states (successors); a function maps
between the two.&lt;/p&gt;
&lt;p&gt;In our case let's have integers as states; then, an infinite binary tree can
be defined using the following successor function:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;defn &lt;/span&gt;&lt;span class="nv"&gt;binary-tree&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;A successors function representing a binary tree.&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;x&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;list &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;* &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;+ &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;* &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;x&lt;/span&gt;&lt;span class="p"&gt;))))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Given a state (a number), it returns its children as a list. Simplistically, in
this tree, node N has the children 2N and 2N+1.&lt;/p&gt;
&lt;p&gt;Here are the first few layers of such a tree:&lt;/p&gt;
&lt;object class="align-center" data="https://eli.thegreenplace.net/images/2023/binary-tree-graph.svg" type="image/svg+xml"&gt;Binary tree with 15 nodes 1-15&lt;/object&gt;
&lt;p&gt;In one sense, the tree is infinite because &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;binary-tree&lt;/span&gt;&lt;/tt&gt; will happily return
the successors for any node we ask:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;paip.core=&amp;gt; (binary-tree 9999)
(19998 19999)
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;But in another sense, &lt;em&gt;there is no tree&lt;/em&gt;. This is a beautiful implication
of using functions instead of concrete data - they easily enable &lt;em&gt;lazy
evaluation&lt;/em&gt;. We cannot materialize an infinite tree inside a
necessarily finite computer, but we can operate on it all the same because of
this abstraction. As far as the search algorithm is concerned, there exists an
abstract &lt;em&gt;state space&lt;/em&gt; and we tell it how to navigate and interpret it.&lt;/p&gt;
&lt;p&gt;Now we're ready to look at the generic search function:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;defn &lt;/span&gt;&lt;span class="nv"&gt;tree-search&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Finds a state that satisfies goal?-fn; Starts with states, and searches&lt;/span&gt;
&lt;span class="s"&gt;  according to successors and combiner. If successful, returns the state;&lt;/span&gt;
&lt;span class="s"&gt;  otherwise returns nil.&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;states&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;goal?-fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;successors&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;combiner&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;cond &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;empty?&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;states&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;nil&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;goal?-fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;first &lt;/span&gt;&lt;span class="nv"&gt;states&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;first &lt;/span&gt;&lt;span class="nv"&gt;states&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="ss"&gt;:else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;tree-search&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;combiner&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;successors&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;first &lt;/span&gt;&lt;span class="nv"&gt;states&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                                     &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;rest &lt;/span&gt;&lt;span class="nv"&gt;states&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                           &lt;/span&gt;&lt;span class="nv"&gt;goal?-fn&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                           &lt;/span&gt;&lt;span class="nv"&gt;successors&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                           &lt;/span&gt;&lt;span class="nv"&gt;combiner&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Let's dig in. The function accepts the following parameters:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;states&lt;/tt&gt;: a list of starting states for the search. When invoked by the
user, this list will typically have a single element; when &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;tree-search&lt;/span&gt;&lt;/tt&gt;
calls itself, this list is the states that it plans to explore next.&lt;/li&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;goal?-fn&lt;/span&gt;&lt;/tt&gt;: a goal detection function. The search doesn't know anything
about states and what the goal of the search is, so this is parameterized
by a function. &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;goal?-fn&lt;/span&gt;&lt;/tt&gt; is expected to return &lt;tt class="docutils literal"&gt;true&lt;/tt&gt; for a goal
state (the state we were searching for) and &lt;tt class="docutils literal"&gt;false&lt;/tt&gt; for all other states.&lt;/li&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;successors&lt;/tt&gt;: the search function also doesn't know anything about what
kind of tree it's searching through; what are the children of a given state?
Is it searching a binary tree? A N-nary tree? Something more exotic? All of
this is parameterized via the &lt;tt class="docutils literal"&gt;successors&lt;/tt&gt; function provided by the user.&lt;/li&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;combiner&lt;/tt&gt;: finally, the search strategy can be parameterized as well.
There are many different kinds of searches possible - BFS, DFS and others.
&lt;tt class="docutils literal"&gt;combiner&lt;/tt&gt; takes a list of successors for the current state the search is
looking at, as well as a list of all the other states the search still plans
to look at. It combines these into a single list &lt;em&gt;somehow&lt;/em&gt;, and thus guides
the order in which the search happens.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Even before we see how this function is used, it's already apparent that this
is quite a powerful abstraction. &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;tree-search&lt;/span&gt;&lt;/tt&gt; defines the essence of what
it means to &amp;quot;search a tree&amp;quot;, while being oblivious to what the tree contains,
how it's structured and even what order it should be searched in; all of this
is supplied by functions passed in as parameters.&lt;/p&gt;
&lt;p&gt;Let's see an example, doing a BFS search on our infinite binary tree. First,
we define a &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;breadth-first-search&lt;/span&gt;&lt;/tt&gt; function:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;defn &lt;/span&gt;&lt;span class="nv"&gt;breadth-first-search&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Search old states first until goal is reached.&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;start&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;goal?-fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;successors&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;tree-search&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;list &lt;/span&gt;&lt;span class="nv"&gt;start&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;goal?-fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;successors&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;prepend&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This function takes a start state (a single state, not a list), &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;goal?-fn&lt;/span&gt;&lt;/tt&gt; and
&lt;tt class="docutils literal"&gt;successors&lt;/tt&gt;, but it sets the &lt;tt class="docutils literal"&gt;combiner&lt;/tt&gt; parameter to the &lt;tt class="docutils literal"&gt;prepend&lt;/tt&gt;
function, which is defined as follows:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;defn &lt;/span&gt;&lt;span class="nv"&gt;prepend&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;y&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;concat &lt;/span&gt;&lt;span class="nv"&gt;y&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;x&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;It defines the search strategy (BFS = first look at the rest of the states and
only then at successors of the current state), but still leaves the tree
structure and the notion of what a goal is to parameters. Let's see it in
action:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;paip.core=&amp;gt; (breadth-first-search 1 #(= % 9) binary-tree)
9
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Here we pass the anonymous function literal &lt;tt class="docutils literal"&gt;#(= % 9)&lt;/tt&gt; as the &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;goal?-fn&lt;/span&gt;&lt;/tt&gt;
parameter. This function simply checks whether the state passed to it is the
number 9. We also pass &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;binary-tree&lt;/span&gt;&lt;/tt&gt; as the &lt;tt class="docutils literal"&gt;successors&lt;/tt&gt;, since we're going
to be searching in our infinite binary tree. BFS works layer by layer, so it
has no issue with that and finds the state quickly.&lt;/p&gt;
&lt;p&gt;We can turn on verbosity (refer to &lt;a class="reference external" href="https://github.com/eliben/paip-in-clojure/tree/master/src/paip/6_tools"&gt;the full code&lt;/a&gt; to
see how it works) to see what &lt;tt class="docutils literal"&gt;states&lt;/tt&gt; parameter &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;tree-search&lt;/span&gt;&lt;/tt&gt; gets called
with, observing the progression of the search:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;paip.core=&amp;gt; (with-verbose (breadth-first-search 1 #(= % 9) binary-tree))
;; Search: (1)
;; Search: (2 3)
;; Search: (3 4 5)
;; Search: (4 5 6 7)
;; Search: (5 6 7 8 9)
;; Search: (6 7 8 9 10 11)
;; Search: (7 8 9 10 11 12 13)
;; Search: (8 9 10 11 12 13 14 15)
;; Search: (9 10 11 12 13 14 15 16 17)
9
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This is the &lt;tt class="docutils literal"&gt;prepend&lt;/tt&gt; combiner in action; for example, after &lt;tt class="docutils literal"&gt;(3 4 5)&lt;/tt&gt;, the
combiner prepends &lt;tt class="docutils literal"&gt;(4 5)&lt;/tt&gt; to the successors of 3 (the list &lt;tt class="docutils literal"&gt;(6 7)&lt;/tt&gt;), getting
&lt;tt class="docutils literal"&gt;(4 5 6 7)&lt;/tt&gt; as the set of states to search through. Overall, observing the
first element in the &lt;tt class="docutils literal"&gt;states&lt;/tt&gt; list through the printed lines, it's clear this
is classical BFS where the tree is visited in &amp;quot;layers&amp;quot;.&lt;/p&gt;
&lt;p&gt;Implementing DFS using &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;tree-search&lt;/span&gt;&lt;/tt&gt; is similarly easy:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;defn &lt;/span&gt;&lt;span class="nv"&gt;depth-first-search&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Search new states first until goal is reached.&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;start&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;goal?-fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;successors&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;tree-search&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;list &lt;/span&gt;&lt;span class="nv"&gt;start&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;goal?-fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;successors&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;concat&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The only difference from BFS is the &lt;tt class="docutils literal"&gt;combiner&lt;/tt&gt; parameter - here we use
&lt;tt class="docutils literal"&gt;concat&lt;/tt&gt; since we want to examine the successors of the first state &lt;em&gt;before&lt;/em&gt;
we examine the other states on the list. If we run &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;depth-first-search&lt;/span&gt;&lt;/tt&gt; on our
infinite binary tree we'll get a stack overflow (unless we're looking for a
state that's on the left-most path), so let's create a safer tree first. This
function can serve as a &lt;tt class="docutils literal"&gt;successors&lt;/tt&gt; to define a &amp;quot;finite&amp;quot; binary tree, with
the given maximal state value:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;defn &lt;/span&gt;&lt;span class="nv"&gt;finite-binary-tree&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Returns a successor function that generates a binary tree with n nodes.&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;fn &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;x&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;filter &lt;/span&gt;&lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;&amp;lt;= &lt;/span&gt;&lt;span class="nv"&gt;%&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;binary-tree&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;x&lt;/span&gt;&lt;span class="p"&gt;))))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Note the clever use of higher-order functions here. &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;finite-binary-tree&lt;/span&gt;&lt;/tt&gt; is
not a &lt;tt class="docutils literal"&gt;successors&lt;/tt&gt; function itself - rather it's a generator of such
functions; given a value, it creates a new function that acts as &lt;tt class="docutils literal"&gt;successors&lt;/tt&gt;
but limits the the states' value to &lt;tt class="docutils literal"&gt;n&lt;/tt&gt;.&lt;/p&gt;
&lt;p&gt;For example, &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;(finite-binary-tree&lt;/span&gt; 15)&lt;/tt&gt; will create a &lt;tt class="docutils literal"&gt;successors&lt;/tt&gt; function
that represents exactly the binary tree on the diagram above; if we ask it about
successors of states on the fourth layer, it will say there are none:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;paip.core=&amp;gt; (def f15 (finite-binary-tree 15))
#&amp;#39;paip.core/f15
paip.core=&amp;gt; (f15 4)
(8 9)
paip.core=&amp;gt; (f15 8)
()
paip.core=&amp;gt; (f15 7)
(14 15)
paip.core=&amp;gt; (f15 15)
()
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;As another test, let's try to look for a state that's not in our finite tree.
Out infinite tree theoretically has &lt;em&gt;all&lt;/em&gt; the states:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;paip.core=&amp;gt; (breadth-first-search 1 #(= % 33) binary-tree)
33
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;But not the finite tree:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;paip.core=&amp;gt; (breadth-first-search 1 #(= % 33) (finite-binary-tree 15))
nil
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;With our finite tree, we are ready to use &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;depth-first-search&lt;/span&gt;&lt;/tt&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;paip.core=&amp;gt; (with-verbose (depth-first-search 1 #(= % 9) (finite-binary-tree 15)))
;; Search: (1)
;; Search: (2 3)
;; Search: (4 5 3)
;; Search: (8 9 5 3)
;; Search: (9 5 3)
9
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Note the search order; when &lt;tt class="docutils literal"&gt;(2 3)&lt;/tt&gt; is explored, 2's successors &lt;tt class="docutils literal"&gt;(4 5)&lt;/tt&gt; then
come &lt;em&gt;before&lt;/em&gt; 3 in the next call; this is the definition of DFS.&lt;/p&gt;
&lt;p&gt;We can implement more advanced search strategies using this infrastructure. For
example, suppose we have a heuristic that tells us which states to prioritize in
order to get to the goal faster (akin to A* search on graphs). We can define
a &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;best-first-search&lt;/span&gt;&lt;/tt&gt; that sorts the states according to our heuristic and
tries the most promising states first (&amp;quot;best&amp;quot; as in &amp;quot;best looking among the
current candidates&amp;quot;, not as in &amp;quot;globally best&amp;quot;).&lt;/p&gt;
&lt;p&gt;First, let's define a couple of helper higher-order functions:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;defn &lt;/span&gt;&lt;span class="nv"&gt;diff&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Given n, returns a function that computes the distance of its argument from n.&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;fn &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;x&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;Math/abs&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;- &lt;/span&gt;&lt;span class="nv"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="p"&gt;))))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;defn &lt;/span&gt;&lt;span class="nv"&gt;sorter&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Returns a combiner function that sorts according to cost-fn.&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;cost-fn&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;fn &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;new &lt;/span&gt;&lt;span class="nv"&gt;old&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;sort-by &lt;/span&gt;&lt;span class="nv"&gt;cost-fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;concat &lt;/span&gt;&lt;span class="k"&gt;new &lt;/span&gt;&lt;span class="nv"&gt;old&lt;/span&gt;&lt;span class="p"&gt;))))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;tt class="docutils literal"&gt;diff&lt;/tt&gt; is a function generator like &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;finite-binary-tree&lt;/span&gt;&lt;/tt&gt;; it takes a target
number &lt;tt class="docutils literal"&gt;n&lt;/tt&gt; and returns a function that computes its parameter &lt;tt class="docutils literal"&gt;x&lt;/tt&gt;'s distance
from &lt;tt class="docutils literal"&gt;n&lt;/tt&gt;.&lt;/p&gt;
&lt;p&gt;&lt;tt class="docutils literal"&gt;sorter&lt;/tt&gt; returns a function that serves as the &lt;tt class="docutils literal"&gt;combiner&lt;/tt&gt; for our
search, based on a cost function. This is done by concatenating the two lists
(successors of first state and the rest of the states) first, and then sorting
them by the cost function. &lt;tt class="docutils literal"&gt;sorter&lt;/tt&gt; is a powerful example of modeling with
higher-order functions.&lt;/p&gt;
&lt;p&gt;With these building blocks in place, we can define &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;best-first-search&lt;/span&gt;&lt;/tt&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;defn &lt;/span&gt;&lt;span class="nv"&gt;best-first-search&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Search lowest cost states first until goal is reached.&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;start&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;goal?-fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;successors&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;cost-fn&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;tree-search&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;list &lt;/span&gt;&lt;span class="nv"&gt;start&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;goal?-fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;successors&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;sorter&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;cost-fn&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Once again, this is just like the earlier BFS and DFS - only the strategy
(&lt;tt class="docutils literal"&gt;combiner&lt;/tt&gt;) changes. Let's use it to find 9 again:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;paip.core=&amp;gt; (with-verbose (best-first-search 1 #(= % 9) (finite-binary-tree 15) (diff 9)))
;; Search: (1)
;; Search: (3 2)
;; Search: (7 6 2)
;; Search: (6 14 15 2)
;; Search: (12 13 14 15 2)
;; Search: (13 14 15 2)
;; Search: (14 15 2)
;; Search: (15 2)
;; Search: (2)
;; Search: (5 4)
;; Search: (10 11 4)
;; Search: (11 4)
;; Search: (4)
;; Search: (9 8)
9
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;While it finds the state eventually, we discover that our heuristic is not a
great match for this problem, as it sends the search astray. The goal of this
post is to demonstrate the power of higher-order functions in building modular
code, not to discover an optimal heuristic for searching in binary trees, though
:-)&lt;/p&gt;
&lt;p&gt;One last search variant before we're ready to wrap up. As we've seen with the
infinite tree, sometimes the search space is too large and we have to compromise
on which states to look at and which to ignore. This technique works
particularly well if the target is not some single value that we must find, but
rather we want to get a &amp;quot;good enough&amp;quot; result in a sea of bad options. We can
use a technique called &lt;em&gt;beam search&lt;/em&gt;; think of a beam of light a flashlight
produces in a very dark room; we can see what the beam points at, but not much
else.&lt;/p&gt;
&lt;p&gt;Beam search is somewhat similar to our &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;best-first-search&lt;/span&gt;&lt;/tt&gt;, but after combining
and sorting the list of states to explore, it only keeps the first N, where
N is given by the &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;beam-width&lt;/span&gt;&lt;/tt&gt; parameter:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;defn &lt;/span&gt;&lt;span class="nv"&gt;beam-search&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Search highest scoring states first until goal is reached, but never consider&lt;/span&gt;
&lt;span class="s"&gt;  more than beam-width states at a time.&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;start&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;goal?-fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;successors&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;cost-fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;beam-width&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;tree-search&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;list &lt;/span&gt;&lt;span class="nv"&gt;start&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;goal?-fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;successors&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;               &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;fn &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;old&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;new&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                 &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;let &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;sorted&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nf"&gt;sorter&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;cost-fn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;old&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;new&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                   &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;take &lt;/span&gt;&lt;span class="nv"&gt;beam-width&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;sorted&lt;/span&gt;&lt;span class="p"&gt;)))))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Once again, higher-order functions at play: as its &lt;tt class="docutils literal"&gt;combiner&lt;/tt&gt;, &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;beam-search&lt;/span&gt;&lt;/tt&gt;
creates an anonymous function that sorts the list based on &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;cost-fn&lt;/span&gt;&lt;/tt&gt;, and then
keeps only the first &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;beam-width&lt;/span&gt;&lt;/tt&gt; states on that list.&lt;/p&gt;
&lt;p&gt;Exercise: Try to run it - what beam width do you need to set in order to
successfully find 9 using our cost heuristic? How can this be improved?&lt;/p&gt;
&lt;div class="section" id="conclusion"&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;This post attempts a code-walkthrough approach to demonstrating the power of
higher-order functions. I always found this particular example from PAIP very
elegant; a particularly powerful insight is the distilled difference between
DFS and BFS. While most programmers intuitively understand the difference and
could write down the pseudo-code for both search strategies, modeling the
problem with higher-order functions lets us really get to the essence of the
difference - &lt;tt class="docutils literal"&gt;concat&lt;/tt&gt; vs. &lt;tt class="docutils literal"&gt;prepend&lt;/tt&gt; as the combiner step.&lt;/p&gt;
&lt;p&gt;See also: &lt;a class="reference external" href="https://eli.thegreenplace.net/2023/higher-order-functions-in-go/"&gt;this code sample ported to Go&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
</content><category term="misc"></category><category term="Clojure"></category><category term="Lisp"></category><category term="Programming"></category></entry><entry><title>Clojure - the perfect language to expand your brain?</title><link href="https://eli.thegreenplace.net/2017/clojure-the-perfect-language-to-expand-your-brain/" rel="alternate"></link><published>2017-08-04T05:25:00-07:00</published><updated>2022-10-04T14:08:24-07:00</updated><author><name>Eli Bendersky</name></author><id>tag:eli.thegreenplace.net,2017-08-04:/2017/clojure-the-perfect-language-to-expand-your-brain/</id><summary type="html">&lt;p&gt;I sometimes get asked for recommendations of what programming language to &amp;quot;learn
next&amp;quot;. It's great that folks appreciate the fact that being exposed to several
sufficiently different programming languages is an important step on the path
to programming enlightenment. But it's also true that, given limited free time,
the choice …&lt;/p&gt;</summary><content type="html">&lt;p&gt;I sometimes get asked for recommendations of what programming language to &amp;quot;learn
next&amp;quot;. It's great that folks appreciate the fact that being exposed to several
sufficiently different programming languages is an important step on the path
to programming enlightenment. But it's also true that, given limited free time,
the choice of which languages to learn is important. As the famous quote by
&lt;a class="reference external" href="https://en.wikiquote.org/wiki/Alan_Perlis"&gt;Alan Perlis&lt;/a&gt; says:&lt;/p&gt;
&lt;blockquote&gt;
A language that doesn't affect the way you think about programming, is not
worth knowing.&lt;/blockquote&gt;
&lt;p&gt;In this post I want to explain why I think Clojure is a &lt;em&gt;terrific&lt;/em&gt; language for
this task. Whatever your background, it's &lt;a class="reference external" href="http://www.paulgraham.com/icad.html"&gt;almost guaranteed&lt;/a&gt; to affect the way you think about
programming. It's a fairly new language (from 2007) that did a good job of
collecting insights and paradigms from many existing languages and organizing
them into a coherent whole. It's chock-full of great ideas. In
other words, the &lt;em&gt;perfect language to expand your brain&lt;/em&gt;.&lt;/p&gt;
&lt;img alt="Brain with Clojure inside" class="align-center" src="https://eli.thegreenplace.net/images/2017/brainclojure.png" /&gt;
&lt;div class="section" id="it-s-a-lisp"&gt;
&lt;h2&gt;It's a Lisp!&lt;/h2&gt;
&lt;p&gt;First and foremost, Clojure belongs to the Lisp family of languages, like Common
Lisp, Scheme and Racket. Lisp is one of the oldest and still most important
families of programming languages to be familiar with. Being a Lisp in this case
means several things:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Clojure is a dynamic language. No matter where you stand on the static vs.
dynamic typing debate, knowing languages in both camps is important. Clojure
has a kind of optional typing, but in essence it's dynamic.&lt;/li&gt;
&lt;li&gt;It promotes combinations of built-in data structures (lists, maps, vectors)
over objects and has very good reasons for doing so.&lt;/li&gt;
&lt;li&gt;It promotes programming with higher-order functions. Some built-in features
like &lt;a class="reference external" href="https://eli.thegreenplace.net/2017/reducers-transducers-and-coreasync-in-clojure/"&gt;reducers and transducers&lt;/a&gt;
rely heavily on composing higher order functions for transforming other
functions.&lt;/li&gt;
&lt;li&gt;It has uniform syntax with full Lisp-style macro support! This capability
has proved to be very elusive for non-Lisp languages, and seeing some &lt;em&gt;real&lt;/em&gt;
macros in action is enlightening. Clojure has a whole Go-like CSP equivalent
implemented using macros in &lt;tt class="docutils literal"&gt;core.async&lt;/tt&gt;.&lt;/li&gt;
&lt;li&gt;It encourages REPL-based development, where functionality is built and testsed
gradually from the bottom up in an interactive terminal.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Importantly, Clojure is a very &lt;em&gt;modern&lt;/em&gt; Lisp, with tons of libraries for tasks
common in our day and age. It also builds upon important recent research in data
structures, such as efficient persistent vectors, that only appeared in the
1990s or later. I've been dabbling with various Lisps for almost 15 years, and
Clojure is the first Lisp I'd consider using in production.&lt;/p&gt;
&lt;p&gt;I want the stress the importance of full Lisp-style macros once again. Lisp's
(and Clojure's) uniform syntax and macros force us to think about the
&lt;a class="reference external" href="https://en.wikipedia.org/wiki/Meta-circular_evaluator"&gt;Meta-circular abstraction&lt;/a&gt; - there's just no way
around it! We have to think of our code as data, and this has profound
implications. Back in 2005, when I was still a programming neophyte, I faced a
performance challenge for a data-decoding program I was hacking on in Perl.
Having learned some Lisp, I had the insight of &lt;a class="reference external" href="https://eli.thegreenplace.net/2005/09/04/cool-hack-creating-custom-subroutines-on-the-fly-in-perl"&gt;generating and evaluating new
Perl code on the fly&lt;/a&gt;,
which turned out to be key to the success of that program. I'm confident I could
not have come up with that solution back then without being aware of the &amp;quot;Lisp
way&amp;quot;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="pragmatism-and-hard-won-experience"&gt;
&lt;h2&gt;Pragmatism and hard-won experience&lt;/h2&gt;
&lt;p&gt;The designers of Clojure are extremely pragmatic, building upon decades of
industry experience. I strongly recommend watching some &lt;a class="reference external" href="https://www.youtube.com/user/ClojureTV"&gt;YouTube videos of talks&lt;/a&gt; by leading Clojure developers. In
particular, watch a few of the more popular talks by Rich Hickey - Clojure's
original designer. The Alan Perlis quote mentioned above may be his most
popular, but there's another I find at least as insightful:&lt;/p&gt;
&lt;blockquote&gt;
Simplicity does not precede complexity, but follows it.&lt;/blockquote&gt;
&lt;p&gt;There's a certain quality in programmers I believe we can all recognize. It can
only come from &lt;em&gt;real&lt;/em&gt;, hard-won experience of building systems for many years
and pondering about how to build such systems more effectively next time. Rich
Hickey certainly belongs to this quality category - his talks are very
insightful, and this philosophy reigns in the design and implementation of
Clojure, as well as its (friendly and vibrant) community.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="sequences-and-laziness-for-powerful-in-language-data-processing"&gt;
&lt;h2&gt;Sequences and laziness for powerful in-language data processing&lt;/h2&gt;
&lt;p&gt;Applications that process and extract useful bits of information from large
datasets all look alike in many programming languages, at least to some extent.
What we &lt;em&gt;really&lt;/em&gt; want in many cases is SQL-like primitives built into our
languages, but this is often challenging (.NET's LINQ is one example of a
successful approach).&lt;/p&gt;
&lt;p&gt;Clojure combines pervasive sequence protocols with persistent data structures
and laziness to make this kind of task natural, using only built-in tools.
Here's a realistic example of a function taken from the &lt;a class="reference external" href="https://pragprog.com/book/vmclojeco/clojure-applied"&gt;Clojure Applied&lt;/a&gt; book:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;defn &lt;/span&gt;&lt;span class="nv"&gt;revenue-by-department&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;carts&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;-&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;filter &lt;/span&gt;&lt;span class="ss"&gt;:settled?&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;carts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;mapcat &lt;/span&gt;&lt;span class="ss"&gt;:line-items&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;map &lt;/span&gt;&lt;span class="nv"&gt;line-summary&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;group-by&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;:dept&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;reduce-kv&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;dept-total&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;All the functions used here are built-ins, including the &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;-&amp;gt;&amp;gt;&lt;/span&gt;&lt;/tt&gt; macro. This
code reads like SQL and it's efficient too. In fact, it can be made somewhat
more efficient and even seamlessly parallelized using &lt;a class="reference external" href="https://eli.thegreenplace.net/2017/reducers-transducers-and-coreasync-in-clojure/"&gt;Reducers and Transducers&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The &lt;a class="reference external" href="https://clojure.org/guides/spec"&gt;clojure.spec&lt;/a&gt; library provides a degree
of type-safety for nested data structures. If you've ever written comments like
&amp;quot;this maps strings to lists, where each list element is a map of ...&amp;quot;,
&lt;tt class="docutils literal"&gt;clojure.spec&lt;/tt&gt; makes it more formal and verifiable. This is very useful when
working with data, and is another example of where Clojure's pragmatism shines;
the language is dynamic in its core, but when you need static checking - it's
there, optionally (&lt;tt class="docutils literal"&gt;core.typed&lt;/tt&gt; is another option for a more statically typed
flavor).&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="the-right-approach-to-object-orientation"&gt;
&lt;h2&gt;The right approach to object-orientation&lt;/h2&gt;
&lt;p&gt;Historically, Lisp programmers weren't the biggest proponents of OOP. This
doesn't mean that OOP has absolutely no value in Lisp-y languages, however.
Common Lisp has had CLOS for decades, and Clojure also comes with an array of
OO-like features.&lt;/p&gt;
&lt;p&gt;That said, Clojure's flavor of OOP is particularly powerful and tends to
discourage bad practices. Clojure uses &amp;quot;protocols&amp;quot;, which are a kind of
interfaces, and encourages thinking in terms of protocols rather than in terms
of classes with inheritance hierarchies, sort of like Go. Add to that an ability
to do true &lt;a class="reference external" href="https://eli.thegreenplace.net/2016/a-polyglots-guide-to-multiple-dispatch-part-4/"&gt;multiple dispatch&lt;/a&gt;
and you have a powerful modeling tool at your fingertips.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="built-in-support-for-concurrency-and-parallelism"&gt;
&lt;h2&gt;Built-in support for concurrency and parallelism&lt;/h2&gt;
&lt;p&gt;It wouldn't be a real language of the 2000s without powerful support for
concurrency and parallelism right at the core. Clojure supports this in many
ways, which are interleaved.&lt;/p&gt;
&lt;p&gt;First, it's a functional language with persistent data structures. Persistent
data structures are effectively immutable, which makes them very attractive in a
multi-threaded context. Clojure has a great implementation of persistent data
structures even for things like vectors (which are quite challenging to
implement in an efficient manner). This is a bigger deal than may originally
appear. Pure functions are often great in theory but fail in practice due to too
much copying of non-trivial data structures; Clojure's elegant usage of
persistent data structures solves this problem, making pure functions efficient
and thus much more applicable to a wide array of problems.&lt;/p&gt;
&lt;p&gt;Second, Clojure doesn't lock itself in the closet of purism and does support
lower-level primitives for concurrency and mutation, where needed. Atoms are
built-in mutable state units with atomic updates. &lt;a class="reference external" href="https://clojure.org/reference/refs"&gt;Refs and transactions&lt;/a&gt; go further, implementing STM.&lt;/p&gt;
&lt;p&gt;Third, Clojure comes with a bunch of concurrency tools built in. Promises,
futures and threads leverage the underlying JVM's threading utilities.&lt;/p&gt;
&lt;p&gt;Finally, Clojure has a pretty good implementation of Go's CSP in the
&lt;tt class="docutils literal"&gt;core.async&lt;/tt&gt; module. It provides two useful things:&lt;/p&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;Channels and Go &lt;tt class="docutils literal"&gt;select&lt;/tt&gt;-like functionality (&lt;tt class="docutils literal"&gt;alts!!&lt;/tt&gt;) which makes it
easy to work with safe concurrent queues and &amp;quot;share data by communicating&amp;quot;.&lt;/li&gt;
&lt;li&gt;go-blocks with non-blocking primitives that &lt;a class="reference external" href="https://eli.thegreenplace.net/2017/clojure-concurrency-and-blocking-with-coreasync/"&gt;make it possible&lt;/a&gt;
to write cooperative &amp;quot;green threads&amp;quot; with ease.&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class="section" id="conclusion-try-it"&gt;
&lt;h2&gt;Conclusion - try it&lt;/h2&gt;
&lt;p&gt;Finally, it's important to mention that Clojure is far from being an academic
exercise. It's used in production by several companies, and has strong roots in
the massive Java ecosystem. Clojure's interoperability with Java is seamless -
Java code can be called from Clojure with no special provisions, and all core
Clojure entities are Java objects deep under the hood.&lt;/p&gt;
&lt;p&gt;On the client side, Clojurescript has been gaining traction recently as another
language-compiled-to-JS option. It brings the elegance of Clojure to client-side
programming, among with some unique features like &lt;tt class="docutils literal"&gt;core.async&lt;/tt&gt; for
callback-free concurrency.&lt;/p&gt;
&lt;p&gt;This doesn't mean that you should only consider Clojure as a fit for your next
project. On the contrary, I recommend learning if even if there's little chance
of using it in production any time soon. In fact, this was exactly my situation,
Clojure is a great language to expand your programming horizons; who knows,
maybe in the future you'll find it useful for some real work. If you do, great!
If you don't, learning it will positively affect how you use other programming
languages.&lt;/p&gt;
&lt;/div&gt;
</content><category term="misc"></category><category term="Clojure"></category><category term="Lisp"></category><category term="Programming"></category></entry><entry><title>Clojure concurrency and blocking with core.async</title><link href="https://eli.thegreenplace.net/2017/clojure-concurrency-and-blocking-with-coreasync/" rel="alternate"></link><published>2017-06-23T06:01:00-07:00</published><updated>2024-05-04T19:46:23-07:00</updated><author><name>Eli Bendersky</name></author><id>tag:eli.thegreenplace.net,2017-06-23:/2017/clojure-concurrency-and-blocking-with-coreasync/</id><summary type="html">&lt;p&gt;This article is an attempt to dig into the performance problem of concurrent
applications using &lt;tt class="docutils literal"&gt;core.async&lt;/tt&gt; in situations where blocking operations are
involved. &amp;quot;Blocking&amp;quot; operations happen when the running program has to wait for
something happening outside it; a canonical example is issuing an HTTP request
and waiting for …&lt;/p&gt;</summary><content type="html">&lt;p&gt;This article is an attempt to dig into the performance problem of concurrent
applications using &lt;tt class="docutils literal"&gt;core.async&lt;/tt&gt; in situations where blocking operations are
involved. &amp;quot;Blocking&amp;quot; operations happen when the running program has to wait for
something happening outside it; a canonical example is issuing an HTTP request
and waiting for the remote server to respond. Such operations are also sometimes
called &amp;quot;synchronous&amp;quot;.&lt;/p&gt;
&lt;p&gt;The &lt;tt class="docutils literal"&gt;core.async&lt;/tt&gt; library comes with many high-level features like transducers
and pipelines; in this article I want to focus on the two fundamental mechanisms
it provides for launching a new computation concurrently: threads and go-blocks.&lt;/p&gt;
&lt;p&gt;New threads can be created with &lt;tt class="docutils literal"&gt;(thread &lt;span class="pre"&gt;...)&lt;/span&gt;&lt;/tt&gt;. This call runs the body in a
new thread and (immediately) returns a channel to which the result of the body
will be posted. Similarly, a go-block is created with &lt;tt class="docutils literal"&gt;(go &lt;span class="pre"&gt;...)&lt;/span&gt;&lt;/tt&gt; - it also
launches the computation concurrently, but instead of creating a new thread it
posts the computation onto a &lt;em&gt;thread pool&lt;/em&gt; of fixed size that the library
maintains for all its go-blocks. Most of the article is focusing on exploring
the differences between these two methods.&lt;/p&gt;
&lt;div class="section" id="the-go-block-thread-pool"&gt;
&lt;h2&gt;The go-block thread pool&lt;/h2&gt;
&lt;p&gt;In any given executing Clojure process, a single thread pool is dedicated to
running all go-blocks. A quick glance at the Clojure source code shows that the
size of this pool is 8, meaning that 8 physical threads are launched &lt;a class="footnote-reference" href="#footnote-1" id="footnote-reference-1"&gt;[1]&lt;/a&gt;. This
number is hard-coded, though it can be modified by setting the
&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;clojure.core.async.pool-size&lt;/span&gt;&lt;/tt&gt; property for the JVM running the program. So 8
is the default number of threads &lt;tt class="docutils literal"&gt;core.async&lt;/tt&gt; has at its disposal to implement
its ad-hoc cooperative multitasking.&lt;/p&gt;
&lt;p&gt;Let's start with a cute little experiment to determine the size of the thread
pool empirically; this exercise will also shed some light on the effect of
blocking calls inside go-blocks:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;defn &lt;/span&gt;&lt;span class="nv"&gt;launch-n-go-blocks&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;let &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;async/chan&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;dotimes &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;async/go&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;Thread/sleep&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;async/&amp;gt;!&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;receive-n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This function launches &lt;tt class="docutils literal"&gt;n&lt;/tt&gt; go-blocks, each sleeping for 10 milliseconds and
then pushing a number into a shared channel. Then it waits to receive all
numbers from the channel and returns; the effect is to block until all the
go-blocks are done. &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;receive-in&lt;/span&gt;&lt;/tt&gt; is a simple function used throughout this
article:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;defn &lt;/span&gt;&lt;span class="nv"&gt;receive-n&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Receive n items from the given channel and return them as a vector.&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;loop &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="nv"&gt;res&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;= &lt;/span&gt;&lt;span class="nv"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;res&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;recur&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;inc &lt;/span&gt;&lt;span class="nv"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;conj &lt;/span&gt;&lt;span class="nv"&gt;res&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;async/&amp;lt;!!&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="p"&gt;))))))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now let's call &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;launch-n-go-blocks&lt;/span&gt;&lt;/tt&gt; several times, with an increasing &lt;tt class="docutils literal"&gt;n&lt;/tt&gt;
and observe what happens:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;Launching  1 -&amp;gt; &amp;quot;Elapsed time: 11.403985 msecs&amp;quot;
Launching  2 -&amp;gt; &amp;quot;Elapsed time: 11.050685 msecs&amp;quot;
Launching  3 -&amp;gt; &amp;quot;Elapsed time: 10.37412 msecs&amp;quot;
Launching  4 -&amp;gt; &amp;quot;Elapsed time: 10.342037 msecs&amp;quot;
Launching  5 -&amp;gt; &amp;quot;Elapsed time: 10.359517 msecs&amp;quot;
Launching  6 -&amp;gt; &amp;quot;Elapsed time: 10.409539 msecs&amp;quot;
Launching  7 -&amp;gt; &amp;quot;Elapsed time: 10.543612 msecs&amp;quot;
Launching  8 -&amp;gt; &amp;quot;Elapsed time: 10.429726 msecs&amp;quot;
Launching  9 -&amp;gt; &amp;quot;Elapsed time: 20.480441 msecs&amp;quot;
Launching 10 -&amp;gt; &amp;quot;Elapsed time: 20.442724 msecs&amp;quot;
Launching 11 -&amp;gt; &amp;quot;Elapsed time: 21.115002 msecs&amp;quot;
Launching 12 -&amp;gt; &amp;quot;Elapsed time: 21.192993 msecs&amp;quot;
Launching 13 -&amp;gt; &amp;quot;Elapsed time: 21.113135 msecs&amp;quot;
Launching 14 -&amp;gt; &amp;quot;Elapsed time: 21.376159 msecs&amp;quot;
Launching 15 -&amp;gt; &amp;quot;Elapsed time: 20.754207 msecs&amp;quot;
Launching 16 -&amp;gt; &amp;quot;Elapsed time: 20.654873 msecs&amp;quot;
Launching 17 -&amp;gt; &amp;quot;Elapsed time: 31.084513 msecs&amp;quot;
Launching 18 -&amp;gt; &amp;quot;Elapsed time: 31.152651 msecs&amp;quot;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Ignoring the minor fluctuations in measurements, there's a very clear pattern
here; let's plot it:&lt;/p&gt;
&lt;img alt="Runtime of launching go-blocks with sleeps" class="align-center" src="https://eli.thegreenplace.net/images/2017/go-block-sleep-runtime.png" /&gt;
&lt;p&gt;The reason for this behavior is the blocking nature of &lt;tt class="docutils literal"&gt;Thread/sleep&lt;/tt&gt;. This
function blocks the &lt;em&gt;current thread&lt;/em&gt; for the specified duration (10 ms in our
case); so the go-block executing it will block the thread it's currently running
on. This thread is then effectively out of the pool until the sleep finishes.
The plot immediately suggests the pool size is 8; as long as 8 or fewer
go-blocks are launched, they all finish within ~10 ms because they all run
concurrently. As soon as we go above 8, the runtime jumps to ~20 ms because one
of the go-blocks will have to wait until there's a free thread in the pool.&lt;/p&gt;
&lt;p&gt;Let's try the same experiment using &lt;tt class="docutils literal"&gt;thread&lt;/tt&gt; instead of &lt;tt class="docutils literal"&gt;go&lt;/tt&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;defn &lt;/span&gt;&lt;span class="nv"&gt;launch-n-threads&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;let &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;async/chan&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;dotimes &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;async/thread&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;Thread/sleep&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;async/&amp;gt;!!&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;receive-n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Here, each time through the loop &lt;em&gt;a new thread&lt;/em&gt; is launched, regardless of the
number of threads already executing &lt;a class="footnote-reference" href="#footnote-2" id="footnote-reference-2"&gt;[2]&lt;/a&gt;. All these threads can run
concurrently, so the runtime plot is:&lt;/p&gt;
&lt;img alt="Runtime of launching threads with sleeps" class="align-center" src="https://eli.thegreenplace.net/images/2017/thread-sleep-runtime.png" /&gt;
&lt;p&gt;The Clojure documentation and talks / presentations by developers are careful to
warn against running blocking operations in go-blocks &lt;a class="footnote-reference" href="#footnote-3" id="footnote-reference-3"&gt;[3]&lt;/a&gt;; it's also not hard
to understand why this is so by thinking a bit about the fixed thread-pool based
implementation. That said, it's still useful to actually see this in action
using an easy-to-understand experiment. In the next section we'll explore the
real-life performance implications of blocking inside go-blocks.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="blocking-i-o"&gt;
&lt;h2&gt;Blocking I/O&lt;/h2&gt;
&lt;p&gt;The sleeping example shown earlier is artificial, but the perils of blocking
inside go-blocks are real. Blocking happens quite often in realistic programs,
most often in the context of I/O. I/O devices tend to be significantly slower
than the CPU executing our program, especially if by &amp;quot;I/O device&amp;quot; we mean a web
server located half-way across the world to which we issue an HTTP request.&lt;/p&gt;
&lt;p&gt;So the next example is going to be a simple concurrent HTTP client; again, two
versions are studied and compared - one with go-blocks, another with threads.
For this sample, we'll be using the &lt;a class="reference external" href="https://github.com/dakrone/clj-http"&gt;clj-http&lt;/a&gt; library &lt;a class="footnote-reference" href="#footnote-4" id="footnote-reference-4"&gt;[4]&lt;/a&gt;, which provides a simple
API to issue blocking HTTP requests. The full code is &lt;a class="reference external" href="https://github.com/eliben/code-for-blog/blob/main/2017/clojure-blocking-async/src/clojure_blocking_async/http_client.clj"&gt;available on GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;def &lt;/span&gt;&lt;span class="nv"&gt;url-template&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;https://github.com/eliben/pycparser/pull/%d&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;defn &lt;/span&gt;&lt;span class="nv"&gt;blocking-get-page&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;clj-http.client/get&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;url-template&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;defn &lt;/span&gt;&lt;span class="nv"&gt;go-blocking-generator&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;start&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;doseq &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;range &lt;/span&gt;&lt;span class="nv"&gt;start&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;+ &lt;/span&gt;&lt;span class="nv"&gt;start&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="p"&gt;))]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;async/go&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;async/&amp;gt;!&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;blocking-get-page&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)))))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;When &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;go-blocking-generator&lt;/span&gt;&lt;/tt&gt; is called, it launches &lt;tt class="docutils literal"&gt;n&lt;/tt&gt; go-blocks, each
requesting a different page from &lt;a class="reference external" href="https://github.com/eliben/pycparser"&gt;pycparser's&lt;/a&gt; pull requests on GitHub. Fetching one
page takes between 760 and 990 ms on my machine, depending on the exact page.
When run with &lt;tt class="docutils literal"&gt;n=20&lt;/tt&gt;, this version takes about 2300 ms. Now let's do the same
with threads:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;defn &lt;/span&gt;&lt;span class="nv"&gt;thread-blocking-generator&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;start&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;doseq &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;range &lt;/span&gt;&lt;span class="nv"&gt;start&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;+ &lt;/span&gt;&lt;span class="nv"&gt;start&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="p"&gt;))]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;async/thread&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;async/&amp;gt;!!&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;blocking-get-page&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)))))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;With &lt;tt class="docutils literal"&gt;n=20&lt;/tt&gt;, this version takes only 1000 ms. As expected, all threads
manage to run at the same time, which is mostly spent waiting on the remote
server. In the go-blocks version, only 8 blocks run concurrently because of the
thread pool size; this example should really drive home the notion of just how
bad blocking I/O in go-blocks is. Most of the blocks sit there waiting for the
thread pool to have a vacant spot, when all they have to do is just issue a HTTP
request and wait anyway.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="parallelizing-cpu-bound-tasks"&gt;
&lt;h2&gt;Parallelizing CPU-bound tasks&lt;/h2&gt;
&lt;p&gt;We've seen how go-blocks interact with blocking operations; now let's examine
CPU-bound tasks, which spend their time doing actual computations on the CPU
rather than waiting for I/O. In an older post, I explored the effects of using
threads and processes &lt;a class="reference external" href="https://eli.thegreenplace.net/2012/01/16/python-parallelizing-cpu-bound-tasks-with-multiprocessing"&gt;in Python to parallelize a simple numeric problem&lt;/a&gt;.
Here I'll be using a similar example: naïvely factorizing a large integer.&lt;/p&gt;
&lt;p&gt;Here's the function that factorizes a number into a vector of factors:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;defn &lt;/span&gt;&lt;span class="nv"&gt;factorize&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Naive factorization function; takes an integer n and returns a vector of&lt;/span&gt;
&lt;span class="s"&gt;  factors.&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;&amp;lt; &lt;/span&gt;&lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;loop &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;factors&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="nv"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;cond &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;= &lt;/span&gt;&lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;factors&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;= &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;mod&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;p&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;recur&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;conj &lt;/span&gt;&lt;span class="nv"&gt;factors&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;p&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;quot &lt;/span&gt;&lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;p&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;p&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;&amp;gt;= &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;* &lt;/span&gt;&lt;span class="nv"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;p&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;conj &lt;/span&gt;&lt;span class="nv"&gt;factors&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;&amp;gt; &lt;/span&gt;&lt;span class="nv"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;recur&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;factors&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;+ &lt;/span&gt;&lt;span class="nv"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="ss"&gt;:else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;recur&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;factors&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;+ &lt;/span&gt;&lt;span class="nv"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))))))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;It takes around 2.3 ms to factorize the number 29 * 982451653; I'll refer to it
as &lt;tt class="docutils literal"&gt;mynum&lt;/tt&gt; from now on &lt;a class="footnote-reference" href="#footnote-5" id="footnote-reference-5"&gt;[5]&lt;/a&gt;. Let's examine a few strategies of factorizing a
large set of numbers in parallel. We'll start with a simple &amp;quot;serial&amp;quot; factorizer,
which should also introduce the API:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;defn &lt;/span&gt;&lt;span class="nv"&gt;serial-factorizer&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Simple serial factorizer.&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;zipmap &lt;/span&gt;&lt;span class="nv"&gt;nums&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;map &lt;/span&gt;&lt;span class="nv"&gt;factorize&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Each factorizer function in this sample takes a sequence of numbers and returns
a new map, which maps a number to its vector of factors. If we run
&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;serial-factorizer&lt;/span&gt;&lt;/tt&gt; on a sequence of 1000 &lt;tt class="docutils literal"&gt;mynum&lt;/tt&gt;s, it takes ~2.3 seconds;
no surprises here!&lt;/p&gt;
&lt;p&gt;Now, a parallel factorizer using go-blocks:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;defn &lt;/span&gt;&lt;span class="nv"&gt;async-go-factorizer&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Parallel factorizer for nums, launching n go blocks.&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;nums&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;;;; Push nums into an input channel; spin up n go-blocks to read from this&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;;;; channel and add numbers to an output channel.&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;let &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;in-c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;async/chan&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nv"&gt;out-c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;async/chan&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;async/onto-chan&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;in-c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;dotimes &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;async/go-loop&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;when-let &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;nextnum&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;async/&amp;lt;!&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;in-c&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;async/&amp;gt;!&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;out-c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;nextnum&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;factorize&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;nextnum&lt;/span&gt;&lt;span class="p"&gt;)})&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;recur&lt;/span&gt;&lt;span class="p"&gt;))))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;receive-n-maps&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;out-c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;count &lt;/span&gt;&lt;span class="nv"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;))))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In a pattern that should be familiar by now, this function creates a couple of
local channels and spins up a number of go-blocks to read and write from these
channels; the code should be self-explanatory. &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;receive-n-maps&lt;/span&gt;&lt;/tt&gt; is similar to
the &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;receive-n&lt;/span&gt;&lt;/tt&gt; function we've seen earlier in the article, just with maps
instead of vectors.&lt;/p&gt;
&lt;p&gt;Knowing that my machine has 8 CPU threads (4 cores, hyper-threaded), I
benchmarked &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;async-go-factorizer&lt;/span&gt;&lt;/tt&gt; with &lt;tt class="docutils literal"&gt;n=8&lt;/tt&gt;, and it took around 680 ms, a
3.4x speedup over the serial version &lt;a class="footnote-reference" href="#footnote-6" id="footnote-reference-6"&gt;[6]&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Let's try the same with threads instead of go-blocks:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;defn &lt;/span&gt;&lt;span class="nv"&gt;async-thread-factorizer&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Same as async-go-factorizer, but with thread instead of go.&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;nums&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;let &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;in-c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;async/chan&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nv"&gt;out-c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;async/chan&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;async/onto-chan&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;in-c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;dotimes &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;async/thread&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;loop &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;when-let &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;nextnum&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;async/&amp;lt;!!&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;in-c&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;async/&amp;gt;!!&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;out-c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;nextnum&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;factorize&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;nextnum&lt;/span&gt;&lt;span class="p"&gt;)})&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;recur&lt;/span&gt;&lt;span class="p"&gt;)))))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;receive-n-maps&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;out-c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;count &lt;/span&gt;&lt;span class="nv"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;))))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The performance is pretty much the same - 680 ms for 1000 numbers with
parallelism of &lt;tt class="docutils literal"&gt;n=8&lt;/tt&gt;.&lt;/p&gt;
&lt;p&gt;This is an important point! On purely CPU-bound workloads, go-blocks are no
worse than threads because all the physical cores are kept busy doing useful
work at all time. There's no waiting involved, so there's no opportunity to
steal an idle core for a different thread. One minor gotcha is to be wary of
the go-block thread pool size; if you run your program on a dual socket machine
with dozens of cores, you may want to bump that number up and use a wider
parallelism setting.&lt;/p&gt;
&lt;p&gt;For completeness (and fun!) let's try a couple more methods of parallelizing
this computation. The pattern in these parallel factorizers is so common that
&lt;tt class="docutils literal"&gt;core.async&lt;/tt&gt; has a function for it - &lt;tt class="docutils literal"&gt;pipeline&lt;/tt&gt;; here's how we use it:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;defn &lt;/span&gt;&lt;span class="nv"&gt;async-with-pipeline&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Parallel factorizer using async/pipeline.&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;nums&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;let &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;in-c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;async/chan&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nv"&gt;out-c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;async/chan&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;async/onto-chan&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;in-c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;async/pipeline&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;out-c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;map &lt;/span&gt;&lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;hash-map &lt;/span&gt;&lt;span class="nv"&gt;%&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;factorize&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;%&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;in-c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;receive-n-maps&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;out-c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;count &lt;/span&gt;&lt;span class="nv"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;))))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;tt class="docutils literal"&gt;async/pipeline&lt;/tt&gt; takes an input channel, output channel and a transducer, as
well as the parallelism. It takes care of spinning go-blocks and connecting all
the channels properly &lt;a class="footnote-reference" href="#footnote-7" id="footnote-reference-7"&gt;[7]&lt;/a&gt;. This takes about the same amount of time as the
other versions shown earlier, which isn't surprising.&lt;/p&gt;
&lt;p&gt;Finally, let's try something slightly different and use Clojure's parallel
&lt;tt class="docutils literal"&gt;fold&lt;/tt&gt; from the &lt;tt class="docutils literal"&gt;clojure.core.reducers&lt;/tt&gt; library (both &lt;tt class="docutils literal"&gt;fold&lt;/tt&gt; and
transducers are described in &lt;a class="reference external" href="https://eli.thegreenplace.net/2017/reducers-transducers-and-coreasync-in-clojure/"&gt;my earlier article&lt;/a&gt;
- check it out!)&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;defn &lt;/span&gt;&lt;span class="nv"&gt;conjmap&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nv"&gt;xs&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;x&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;conj &lt;/span&gt;&lt;span class="nv"&gt;xs&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;x&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{}))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;defn &lt;/span&gt;&lt;span class="nv"&gt;rfold&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Parallel factorizer using r/fold.&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;r/fold&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;conjmap&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;r/map&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;hash-map &lt;/span&gt;&lt;span class="nv"&gt;%&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;factorize&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;%&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Here we don't have to set the parallelism; &lt;tt class="docutils literal"&gt;r/fold&lt;/tt&gt; determines it on its own.
This approach takes 1.15 seconds on 1000 numbers, quite a bit slower than the
earlier attempts. It's entirely possible that the fork-join approach used by
&lt;tt class="docutils literal"&gt;r/fold&lt;/tt&gt; is less efficient than the manual chunking to different threads done
by the other versions.&lt;/p&gt;
&lt;p&gt;The conclusion from this section, however, should be that for purely CPU-bound
tasks it doesn't matter much whether go-blocks or explicit threads are used -
the performance should be more-or-less the same. That said, realistic programs
don't often spend time purely in CPU-bound tasks; the reality is usually
somewhere in between - some tasks do computations, other tasks wait on things.
Let's see a benchmark that combines the two.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="combining-blocking-and-cpu-bound-tasks"&gt;
&lt;h2&gt;Combining blocking and CPU-bound tasks&lt;/h2&gt;
&lt;p&gt;This section shows an artificial benchmark that explores how a combination of
blocking and CPU-bound tasks behaves when launched on go-blocs vs. threads. The
CPU bound task will be the same factorization but this time with a larger number
that was carefully tuned to take about 230 ms to factorize on my machine. The
blocking &amp;quot;task&amp;quot; will be &lt;tt class="docutils literal"&gt;(Thread/sleep 250)&lt;/tt&gt;. I deliberately choose the same
duration for the two kinds of tasks here to make comparisons easier, but the
principle applies more generally.&lt;/p&gt;
&lt;p&gt;Here is the go-block version of the benchmark:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;defn &lt;/span&gt;&lt;span class="nv"&gt;launch-go-blocking-and-compute&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;nblock&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;ncompute&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;let &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;async/chan&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;dotimes &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;nblock&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;async/go&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;Thread/sleep&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;250&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;async/&amp;gt;!&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;dotimes &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;ncompute&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;async/go&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;async/&amp;gt;!&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;factorize&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;mynum&lt;/span&gt;&lt;span class="p"&gt;))))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;receive-n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;+ &lt;/span&gt;&lt;span class="nv"&gt;nblock&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;ncompute&lt;/span&gt;&lt;span class="p"&gt;))))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;tt class="docutils literal"&gt;nblock&lt;/tt&gt; is the number of blocking tasks to launch; &lt;tt class="docutils literal"&gt;ncompute&lt;/tt&gt; is the number
of CPU-bound tasks to launch. The rest of the code is straightforward. You can
guess what the threading version looks like by now - check out the &lt;a class="reference external" href="https://github.com/eliben/code-for-blog/blob/main/2017/clojure-blocking-async/src/clojure_blocking_async/combine_cpubound_blocking.clj"&gt;full code
sample&lt;/a&gt;
if not.&lt;/p&gt;
&lt;p&gt;The parameter space here is pretty large; let's try 32 blocking and 16 compute
tasks in parallel:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;nblock=32, ncompute=16

launch-go-blocking-and-compute: 1521 ms
launch-thread-blocking-and-compute: 530 ms
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The larger we set &lt;tt class="docutils literal"&gt;nblock&lt;/tt&gt;, the worse the situation becomes for the go-block
version:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;nblock=64, ncompute=16

launch-go-blocking-and-compute: 3200 ms
launch-thread-blocking-and-compute: 530 ms
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Up to some limit, the threading version is only limited by &lt;tt class="docutils literal"&gt;ncompute&lt;/tt&gt;, since
these actually occupy the CPU cores; all the blocking tasks are run in the
background and can complete at the same time (after the initial 250 ms).&lt;/p&gt;
&lt;p&gt;The go-block version fares much worse, because the blocking tasks can occupy
threads while the compute tasks just wait in a queue. Depending on the exact
mixture of blocking and compute-bound tasks, this can range from more-or-less
the same to &lt;em&gt;exteremely&lt;/em&gt; bad for the go-blocks version. YMMV!&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="managing-callback-hell-with-go-blocks"&gt;
&lt;h2&gt;Managing callback-hell with go-blocks&lt;/h2&gt;
&lt;p&gt;We've seen the issues that come up when mixing blocking I/o with go-blocks. The
reason for this is the cooperative concurrency approach implemented by go-blocks
on top of a fixed thread pool. For cooperative concurrency to work well with
I/O, the language should either make the scheduler aware of the I/O calls (to be
able to switch to another context while blocking) or the I/O should be
non-blocking. The former requires runtime support in the language, like Go; the
latter is what programming environments like Python (with &lt;tt class="docutils literal"&gt;asyncio&lt;/tt&gt;) and
Node.js (with its fully non-blocking standard library) do. The same applies to
Clojure, where &lt;tt class="docutils literal"&gt;core.async&lt;/tt&gt; is just a library without actual runtime support.&lt;/p&gt;
&lt;p&gt;The good news is that non-blocking I/O libraries are very popular these days,
and Clojure has a good number of them for all the common tasks you can think of.
Another good news is that &lt;tt class="docutils literal"&gt;core.async&lt;/tt&gt;'s channels make it very easy to deal
with non-blocking I/O without sliding into &lt;a class="reference external" href="http://callbackhell.com/"&gt;callback hell&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Here's a code sample that uses the asynchronous mode of &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;clj-http&lt;/span&gt;&lt;/tt&gt; to repeat
the concurrent HTTP request benchmark:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;defn &lt;/span&gt;&lt;span class="nv"&gt;go-async-generator&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;start&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;doseq &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;range &lt;/span&gt;&lt;span class="nv"&gt;start&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;+ &lt;/span&gt;&lt;span class="nv"&gt;start&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="p"&gt;))]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;clj-http.client/get&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;url-template&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:async?&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;true&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;fn &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;response&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;async/go&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;async/&amp;gt;!&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="c1"&gt;;; Exception callback.&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;fn &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;exc&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;throw&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;exc&lt;/span&gt;&lt;span class="p"&gt;)))))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;When passed the &lt;tt class="docutils literal"&gt;{:async? true}&lt;/tt&gt; option, &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;clj-http.client/get&lt;/span&gt;&lt;/tt&gt; does a
non-blocking request with a callback for the response (and another callback for
an error). Our &amp;quot;response callback&amp;quot; simply spins a go-block that places the
response into a channel. Now another go-block (or thread) can wait on the
channel to perform the next step; compare that to cascading callbacks!&lt;/p&gt;
&lt;p&gt;The performance is good too - when run with multiple requests in parallel, this
version runs as fast as the thread-launching example from earlier in the article
(the full code &lt;a class="reference external" href="https://github.com/eliben/code-for-blog/blob/main/2017/clojure-blocking-async/src/clojure_blocking_async/http_client_async.clj"&gt;is here&lt;/a&gt;).
All the &lt;tt class="docutils literal"&gt;get&lt;/tt&gt; requests are launched one after another, with no blocking. When
the results arrive, go-blocks patiently &amp;quot;park&amp;quot; while sending them into a
channel, but this is an explicit context-switch operation, so all of them
peacefully run concurrently on the underlying thread pool.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="conclusion"&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Would launching a thread inside the callback work as well in the last example?
Yes, I think it would. So why use go-blocks?&lt;/p&gt;
&lt;p&gt;The reason is scalability. Launching threads is fine as long as you don't have
too many, and as long as the latency of the launch is not too important. Threads
are OS constructs and have fairly heavy resource requirements - in terms of
memory consumption and context-switching time. go-blocks are extremely
lightweight in comparison.&lt;/p&gt;
&lt;p&gt;Therefore, if you want to serve 1000s of connections concurrently from a single
machine - go-blocks are the way to go, combined with non-blocking APIs. Note
that go-blocks use a thread pool that can use multipe cores, so this isn't just
a single-core concurrent multitasking solution (such as you may encounter in
Node.js or Python's &lt;tt class="docutils literal"&gt;asyncio&lt;/tt&gt;).&lt;/p&gt;
&lt;p&gt;If the number of concurrent tasks is not too large or blocking I/O is involved,
I'd recommend using &lt;tt class="docutils literal"&gt;async/thread&lt;/tt&gt;. It avoids the pitfalls of blocking I/O,
and in other cases performance is the same. &lt;tt class="docutils literal"&gt;core.async&lt;/tt&gt;'s wonderful tools
like channels and &lt;tt class="docutils literal"&gt;alts!!&lt;/tt&gt; are still available, making concurrent programming
much more pleasant.&lt;/p&gt;
&lt;p&gt;However, note that Clojure is a multi-environment language, and in some
environments (most notably ClojureScript), threads are simply unavailable. In
these cases using go-blocks is your only chance at any kind of reasonable
concurrency (the alternative being callbacks).&lt;/p&gt;
&lt;p&gt;Another use case for go-blocks is to implement coroutines which can be useful in
some cases - such as agents in games, as a &lt;a class="reference external" href="https://eli.thegreenplace.net/2009/08/29/co-routines-as-an-alternative-to-state-machines"&gt;replacement for complex state
machines&lt;/a&gt;,
etc. But here again, beware of the actual scale. If it's possible to use
threads, just use threads. go-blocks are trickier to use correctly and one has
to be always aware of what may block, lest performance is dramatically degraded.&lt;/p&gt;
&lt;p&gt;If there's something I'm missing, please let me know!&lt;/p&gt;
&lt;hr class="docutils" /&gt;
&lt;table class="docutils footnote" frame="void" id="footnote-1" rules="none"&gt;
&lt;colgroup&gt;&lt;col class="label" /&gt;&lt;col /&gt;&lt;/colgroup&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td class="label"&gt;&lt;a class="fn-backref" href="#footnote-reference-1"&gt;[1]&lt;/a&gt;&lt;/td&gt;&lt;td&gt;This is for the standard JVM implementation of Clojure; in ClojureScript
there would just be a single thread, since JS doesn't support in-browser
threads (yet).&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table class="docutils footnote" frame="void" id="footnote-2" rules="none"&gt;
&lt;colgroup&gt;&lt;col class="label" /&gt;&lt;col /&gt;&lt;/colgroup&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td class="label"&gt;&lt;a class="fn-backref" href="#footnote-reference-2"&gt;[2]&lt;/a&gt;&lt;/td&gt;&lt;td&gt;The JVM also has some limit on the number of threads it runs at the same
time, but it's fairly high so we'll ignore it here.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table class="docutils footnote" frame="void" id="footnote-3" rules="none"&gt;
&lt;colgroup&gt;&lt;col class="label" /&gt;&lt;col /&gt;&lt;/colgroup&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td class="label"&gt;&lt;a class="fn-backref" href="#footnote-reference-3"&gt;[3]&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;p class="first"&gt;W.r.t. transgressions committed in the code sample show here,
&lt;tt class="docutils literal"&gt;Thread/sleep&lt;/tt&gt; is a big no-no inside go-blocks. By now I hope that it's
obvious why. &lt;tt class="docutils literal"&gt;timeout&lt;/tt&gt; is the right function for &amp;quot;waiting&amp;quot; inside
go-blocks, since it &amp;quot;parks&amp;quot; the go-block rather than blocking it. Parking
is go-block friendly since it actually frees up the thread the go-block
is running on. Similarly, &lt;tt class="docutils literal"&gt;&amp;gt;!&lt;/tt&gt; is the right channel sending function to
use inside go-blocks; &lt;tt class="docutils literal"&gt;&amp;gt;!!&lt;/tt&gt; blocks the whole thread.&lt;/p&gt;
&lt;p class="last"&gt;This is also a good place to mention that similar thread pool size
&amp;quot;artifacts&amp;quot; &lt;a class="reference external" href="https://www.future-processing.pl/blog/on-problems-with-threads-in-node-js/"&gt;can be found in Node.js&lt;/a&gt;,
which uses &lt;tt class="docutils literal"&gt;libuv&lt;/tt&gt; to handle events. &lt;tt class="docutils literal"&gt;libuv&lt;/tt&gt; uses its own thread pool
to execute blocking calls, thus giving the calling application a sense of
concurrency (up to some thread pool size).&lt;/p&gt;
&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table class="docutils footnote" frame="void" id="footnote-4" rules="none"&gt;
&lt;colgroup&gt;&lt;col class="label" /&gt;&lt;col /&gt;&lt;/colgroup&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td class="label"&gt;&lt;a class="fn-backref" href="#footnote-reference-4"&gt;[4]&lt;/a&gt;&lt;/td&gt;&lt;td&gt;This sample is inspired by &lt;a class="reference external" href="http://martintrojer.github.io/clojure/2013/07/07/coreasync-and-blocking-io"&gt;Martin Trojer's blog post&lt;/a&gt;,
which is the best introduction to the issues with blocking I/O in
go-blocks I found before starting this article.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table class="docutils footnote" frame="void" id="footnote-5" rules="none"&gt;
&lt;colgroup&gt;&lt;col class="label" /&gt;&lt;col /&gt;&lt;/colgroup&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td class="label"&gt;&lt;a class="fn-backref" href="#footnote-reference-5"&gt;[5]&lt;/a&gt;&lt;/td&gt;&lt;td&gt;Why this particular number? The second factor is a large-ish prime, so it
will make the factorizer sweat a bit (by iterating over all the odd numbers
up to its square root); the multiplication by another (prime) factor
ensures more of the paths in the &lt;tt class="docutils literal"&gt;factorize&lt;/tt&gt; function are exercised.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table class="docutils footnote" frame="void" id="footnote-6" rules="none"&gt;
&lt;colgroup&gt;&lt;col class="label" /&gt;&lt;col /&gt;&lt;/colgroup&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td class="label"&gt;&lt;a class="fn-backref" href="#footnote-reference-6"&gt;[6]&lt;/a&gt;&lt;/td&gt;&lt;td&gt;Benchmarking multi-core CPU performance with modern CPUs is notoriously
tricky; CPUs regulate their frequency based on load, so it's entirely
possible that a single core runs faster than each one core in a group of
4; also, hyper-threading reuses some CPU resources within each core so
its speedup is rarely linear.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table class="docutils footnote" frame="void" id="footnote-7" rules="none"&gt;
&lt;colgroup&gt;&lt;col class="label" /&gt;&lt;col /&gt;&lt;/colgroup&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td class="label"&gt;&lt;a class="fn-backref" href="#footnote-reference-7"&gt;[7]&lt;/a&gt;&lt;/td&gt;&lt;td&gt;Note that &lt;tt class="docutils literal"&gt;pipeline&lt;/tt&gt; spins up go-blocks by default, so the cautions
explored in this article apply. There's also &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;pipeline-blocking&lt;/span&gt;&lt;/tt&gt; if you
need blocking operations. Looking at the &lt;a class="reference external" href="https://github.com/clojure/core.async/blob/2afc2dc5102f60713135ffca6fab993fb35809f0/src/main/clojure/clojure/core/async.clj#L475"&gt;implementation if pipeline&lt;/a&gt;
is actually pretty illuminating, and should be easy to understand given
what we discuss here.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
</content><category term="misc"></category><category term="Clojure"></category><category term="Lisp"></category><category term="Programming"></category><category term="Concurrency"></category></entry><entry><title>Reducers, transducers and core.async in Clojure</title><link href="https://eli.thegreenplace.net/2017/reducers-transducers-and-coreasync-in-clojure/" rel="alternate"></link><published>2017-06-07T05:32:00-07:00</published><updated>2024-05-04T19:46:23-07:00</updated><author><name>Eli Bendersky</name></author><id>tag:eli.thegreenplace.net,2017-06-07:/2017/reducers-transducers-and-coreasync-in-clojure/</id><summary type="html">&lt;p&gt;This is a whirlwind tour of some of the cool new features that appeared
in Clojure in the past few years. I find it fascinating how one good idea
(reducers) morphed into another (transducers), and ended up mating with yet
another, apparently unrelated concept (concurrent pipelines) to produce some
really …&lt;/p&gt;</summary><content type="html">&lt;p&gt;This is a whirlwind tour of some of the cool new features that appeared
in Clojure in the past few years. I find it fascinating how one good idea
(reducers) morphed into another (transducers), and ended up mating with yet
another, apparently unrelated concept (concurrent pipelines) to produce some
really powerful coding abstractions.&lt;/p&gt;
&lt;p&gt;The article is not for beginners; otherwise it'd take a small book to cover all
this material. Some experience with Clojure or a similar functional language is
required.&lt;/p&gt;
&lt;div class="section" id="sequences-iterators-and-laziness"&gt;
&lt;h2&gt;Sequences, iterators and laziness&lt;/h2&gt;
&lt;p&gt;Let's start with the basics. Suppose we want to iterate over a sequence of
items, performing some combination of transforming and filtering on the
items in it. Here's an example:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nv"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;def &lt;/span&gt;&lt;span class="nv"&gt;s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;range &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="ss"&gt;&amp;#39;simplerepl.core/s&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="nv"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;reduce + &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;map inc &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;filter &lt;/span&gt;&lt;span class="nv"&gt;even?&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;It's very simple, but our imagination and experience tell us that it is
representative of many real data processing pipelines. Mapping, filtering and
reducing is the bread and butter of functional programming, after all. However,
our eternal concern with efficiency should sound the sirens here; it seems like
we take a sequence and pull it through several operations that need the whole
sequence to operate. Are there copies involved? The way the Clojure code is
written above, the answer is &lt;em&gt;no&lt;/em&gt; - because of laziness.&lt;/p&gt;
&lt;p&gt;&lt;tt class="docutils literal"&gt;range&lt;/tt&gt; returns a lazy sequence - a sequence whose members are not really
materialized until we try to use them. Further, Clojure's functional primitives
like map and filter respect laziness by not materializing more than they need
for any given step (sans a bit of chunking/buffering for efficiency).&lt;/p&gt;
&lt;p&gt;In other words, the code above does not create intermediate sequences between
steps. It creates &lt;em&gt;lazy&lt;/em&gt; sequences, which are just thunks holding a function to
materialize the next item.&lt;/p&gt;
&lt;p&gt;Python has iterators for the same purpose. When writing a function to generate a
sequence of items in modern Python, returning a list is discouraged because this
may incur unnecessary copying. Rather, such functions ought to return
&lt;em&gt;iterators&lt;/em&gt; (which is very easy using &lt;tt class="docutils literal"&gt;yield&lt;/tt&gt;). Moreover, functions consuming
sequences should be careful about not materializing the whole sequence but
rather using elementwise iteration (which is the default in &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;for...in&lt;/span&gt;&lt;/tt&gt; loops).
Python 3 made this style prevalent by switching &lt;tt class="docutils literal"&gt;range&lt;/tt&gt; to return an iterable;
same for &lt;tt class="docutils literal"&gt;map&lt;/tt&gt;. In Python 2 both &lt;tt class="docutils literal"&gt;range&lt;/tt&gt; and &lt;tt class="docutils literal"&gt;map&lt;/tt&gt; return fully
materialized lists.&lt;/p&gt;
&lt;p&gt;In an imperative programming style, we'd probably have a loop to perform the
operation shown above:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;It's easy to reason about the efficiency of this code, but it's also structured
in a less modular way. A composition of &lt;tt class="docutils literal"&gt;map&lt;/tt&gt;s, &lt;tt class="docutils literal"&gt;filter&lt;/tt&gt;s and reductions
could be easier to reason about because it maps well to the actual business
logic of our application. The imperative implementation does not compose as
well.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="reducers"&gt;
&lt;h2&gt;Reducers&lt;/h2&gt;
&lt;img alt="Pipe reducers" class="align-center" src="https://eli.thegreenplace.net/images/2017/reducers.jpg" /&gt;
&lt;p&gt;Alright, so laziness ensures that Clojure code as shown above is not as
inefficient as we may have feared. But still, is it as efficient as an
imperative implementation? It turns out the answer is no; while laziness avoids
large copying costs, it &lt;em&gt;does&lt;/em&gt; incur a constant overhead for boxing and unboxing
thunks representing the rest of the sequence; it would be nice to avoid these
costs as well. This brings us to reducers.&lt;/p&gt;
&lt;p&gt;Expressing data transformation with reducers starts with the observation that
&lt;tt class="docutils literal"&gt;reduce&lt;/tt&gt; is a fundamental building block that can express other
transformations fairly easily. Here's how we can perform the job of a &lt;tt class="docutils literal"&gt;map&lt;/tt&gt;
with &lt;tt class="docutils literal"&gt;reduce&lt;/tt&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nv"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;reduce &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;fn &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;acc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;item&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;conj &lt;/span&gt;&lt;span class="nv"&gt;acc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;inc &lt;/span&gt;&lt;span class="nv"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;tt class="docutils literal"&gt;filter&lt;/tt&gt; is only slightly trickier:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nv"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;reduce &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;fn &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;acc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;item&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;even?&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="nv"&gt;_=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;                          &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;conj &lt;/span&gt;&lt;span class="nv"&gt;acc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="nv"&gt;_=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;                          &lt;/span&gt;&lt;span class="nv"&gt;acc&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="nv"&gt;_=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This is cool, but note something slightly disturbing. This code will work fine
only on collections for which &lt;tt class="docutils literal"&gt;conj&lt;/tt&gt; works well; it will blow up on lists.
Also, we've just spent time talking about &lt;em&gt;not&lt;/em&gt; building temporary collections
in between transformations, but this exactly what this code is doing with that
&lt;tt class="docutils literal"&gt;conj&lt;/tt&gt;.&lt;/p&gt;
&lt;p&gt;The &lt;tt class="docutils literal"&gt;clojure.core.reducers&lt;/tt&gt; library solves both these problems by conceptually
inverting the process of applying multiple transformations to a sequence
inside-out. Reducers are now integrated into Clojure core, but it's worth
spending a few minutes getting an intuitive feel for how they work by
implementing a simplistic variant. For the full scoop, read &lt;a class="reference external" href="https://clojure.org/news/2012/05/15/anatomy-of-reducer"&gt;Rich Hickey's
article&lt;/a&gt;. Here's
an abridged version.&lt;/p&gt;
&lt;p&gt;We start by defining a &amp;quot;reducing function&amp;quot;. A reducing function is what
&lt;tt class="docutils literal"&gt;reduce&lt;/tt&gt; takes - a function accepting an accumulator and a new item, and
returning the new accumulator value. In classical reductions this function can
just be &lt;tt class="docutils literal"&gt;+&lt;/tt&gt;; in the sense of implementing-map-with-a-reduce, it can be as
shown above. In pseudo-type-notation, it's something like &lt;a class="footnote-reference" href="#footnote-1" id="footnote-reference-1"&gt;[1]&lt;/a&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;reducingf :: acc -&amp;gt; item -&amp;gt; acc
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Next, let's define the concept of &amp;quot;transforming&amp;quot; a reducing function. This is
simply a function that takes a reducing function and returns another reducing
function:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;transformingf :: (acc -&amp;gt; item -&amp;gt; acc) -&amp;gt; (acc -&amp;gt; item -&amp;gt; acc)
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The main insight is that we can express all kinds of data transformations simply
by transforming a reducing function. In the end we'll end up with a single
reducing function that can be passed to &lt;tt class="docutils literal"&gt;reduce&lt;/tt&gt;.&lt;/p&gt;
&lt;p&gt;Here's another take at representing &lt;tt class="docutils literal"&gt;map&lt;/tt&gt; with &lt;tt class="docutils literal"&gt;reduce&lt;/tt&gt;, this time using the
generalized approach described above:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;defn &lt;/span&gt;&lt;span class="nv"&gt;mapping-transform&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;mapf&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;fn &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;reducingf&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;fn &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;acc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;item&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;reducingf&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;acc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;mapf&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)))))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;It may look scary, but it's just an code embodiment of the textual description
above. A call to &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;mapping-transform&lt;/span&gt;&lt;/tt&gt; will create a function that transforms
a reducing function into another reducing function. The actual parameter passed
to &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;mapping-transform&lt;/span&gt;&lt;/tt&gt; is used to modify every item in the collection before
that item is passed to the original reducing function. Here's how we can use
this to compute a sum of squares for a given vector:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nv"&gt;reducers.core=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;reduce &lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nf"&gt;mapping-transform&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;* &lt;/span&gt;&lt;span class="nv"&gt;%&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;%&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;+&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="mi"&gt;91&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;There's nothing more magical than some higher-order function munging going on
here. &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;(mapping-transform&lt;/span&gt; #(* % %))&lt;/tt&gt; returns a function that takes a reducing
function as argument, and returns another reducing function. Since the actual
reduction we want to perform is &lt;tt class="docutils literal"&gt;+&lt;/tt&gt;, this is what we pass in &lt;a class="footnote-reference" href="#footnote-2" id="footnote-reference-2"&gt;[2]&lt;/a&gt;. The
returned reducing function is then given to &lt;tt class="docutils literal"&gt;reduce&lt;/tt&gt;. Take a couple of minutes
to convince yourself how this works. It may help tracing the &lt;tt class="docutils literal"&gt;+&lt;/tt&gt; in the REPL:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;reducers.core=&amp;gt; (trace-vars +)
#&amp;#39;clojure.core/+
reducers.core=&amp;gt; (reduce ((mapping-transform #(* % %)) +) 0 [1 2 3 4 5 6])
TRACE t8399: (clojure.core/+ 1 4)
TRACE t8399: =&amp;gt; 5
TRACE t8400: (clojure.core/+ 5 9)
TRACE t8400: =&amp;gt; 14
TRACE t8401: (clojure.core/+ 14 16)
TRACE t8401: =&amp;gt; 30
TRACE t8402: (clojure.core/+ 30 25)
TRACE t8402: =&amp;gt; 55
TRACE t8403: (clojure.core/+ 55 36)
TRACE t8403: =&amp;gt; 91
91
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Question: how many times do we process each item in the input vector? Note that
we do &lt;em&gt;two&lt;/em&gt; data transformation operations:&lt;/p&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;Map the square function &lt;tt class="docutils literal"&gt;#(* % %)&lt;/tt&gt; over each item.&lt;/li&gt;
&lt;li&gt;Sum all squared items together.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;However, this code only walks over the input sequence &lt;strong&gt;once&lt;/strong&gt;. What happens
here is that, instead of generating a new lazy thunk after each step, we combine
all steps into a single traversal. This combination is achieved via a
composition of functions orchestrated by &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;mapping-transform&lt;/span&gt;&lt;/tt&gt;. We can take this
approach further, and define a &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;filtering-transform&lt;/span&gt;&lt;/tt&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;defn &lt;/span&gt;&lt;span class="nv"&gt;filtering-transform&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;predicate&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;fn &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;reducingf&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;fn &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;acc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;item&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;predicate&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;reducingf&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;acc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nv"&gt;acc&lt;/span&gt;&lt;span class="p"&gt;))))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Here's how we sum up the all the even numbers in a vector:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;reducers.core=&amp;gt; (reduce ((filtering-transform even?) +) 0 [1 2 3 4 5 6])
12
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now it's time to go back to the first example we started the article with. Let's
take all the even numbers in a sequence, increment them and sum them up, using
the higher-order reducing transforms. Here goes:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;reducers.core=&amp;gt; (reduce ((filtering-transform even?)
           #_=&amp;gt;            ((mapping-transform inc) +)) 0 (range 0 10))
25
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Remember the mention of inverting the transformation process inside-out? The
order of transformations is inverted from the usual Clojure function application
order. We first filter the evens, then increment, then add them all up. The
&amp;quot;standard&amp;quot; Clojure code is:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;reduce + &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;map inc &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;filter &lt;/span&gt;&lt;span class="nv"&gt;even?&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;But we've flipped it with &lt;tt class="docutils literal"&gt;even?&lt;/tt&gt; on the outside and &lt;tt class="docutils literal"&gt;+&lt;/tt&gt; on the inside
(with &lt;tt class="docutils literal"&gt;inc&lt;/tt&gt; still in-between), due to the way our &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;mapping-transform&lt;/span&gt;&lt;/tt&gt; and
&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;filtering-transform&lt;/span&gt;&lt;/tt&gt; are defined. The order doesn't really matter, and the
actual Clojure reducers library lets us write it in the more expected order, as
we will soon see &lt;a class="footnote-reference" href="#footnote-3" id="footnote-reference-3"&gt;[3]&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;What &lt;em&gt;really&lt;/em&gt; matters is that this approach only walks the input sequence
&lt;em&gt;once&lt;/em&gt;, without any temporary sequences or lazy thunks in the interim. It really
is similar to the imperative-style loop &lt;a class="footnote-reference" href="#footnote-4" id="footnote-reference-4"&gt;[4]&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="is-it-faster-in-practice"&gt;
&lt;h2&gt;Is it faster in practice?&lt;/h2&gt;
&lt;p&gt;Let's leave this explanatory framework behind and just use
&lt;tt class="docutils literal"&gt;clojure.core.reducers&lt;/tt&gt; that exports its own versions of &lt;tt class="docutils literal"&gt;map&lt;/tt&gt; and
&lt;tt class="docutils literal"&gt;filter&lt;/tt&gt;, which are designed to be passed to &lt;tt class="docutils literal"&gt;reduce&lt;/tt&gt;. These functions do
essentially the same thing as the trick explained above, but with a bit more
sophistication so that invoking them looks exactly like invoking the built-in
&lt;tt class="docutils literal"&gt;map&lt;/tt&gt; and &lt;tt class="docutils literal"&gt;filter&lt;/tt&gt;.&lt;/p&gt;
&lt;p&gt;To use them in the REPL, we'll first &lt;tt class="docutils literal"&gt;require&lt;/tt&gt; the module:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;reducers.core=&amp;gt; (require &amp;#39;[clojure.core.reducers :as r])
nil
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now we can distinguish between the built-in &lt;tt class="docutils literal"&gt;map&lt;/tt&gt; and the transforming
&lt;tt class="docutils literal"&gt;r/map&lt;/tt&gt;. Here is a benchmark that compares this new way of transforming
collections &lt;a class="footnote-reference" href="#footnote-5" id="footnote-reference-5"&gt;[5]&lt;/a&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;reducers.core=&amp;gt; (def s (range 0 9999999))
#&amp;#39;reducers.core/s
reducers.core=&amp;gt; (time (reduce + 0 (map inc (filter even? s))))
&amp;quot;Elapsed time: 599.985027 msecs&amp;quot;
25000000000000
reducers.core=&amp;gt; (time (reduce + 0 (r/map inc (r/filter even? s))))
&amp;quot;Elapsed time: 432.453733 msecs&amp;quot;
25000000000000
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The &lt;tt class="docutils literal"&gt;reducers&lt;/tt&gt; version is quite a bit faster. As an excercise, try to make the
transforming chain longer by adding several more mapping and filtering steps.
How does it affect the performance difference?&lt;/p&gt;
&lt;p&gt;Great, so we can speed up our data processing with &lt;em&gt;this one weird trick&lt;/em&gt;.
However, if you have some experience in working on compiler backends, you may be
feeling underwhelmed. Isn't this just loop fusion? Indeed, it is. Our original
code had multiple loops going over the same data; but we could just fuse all the
operations done on every element into a single loop. Indeed, this is what the
imperative code in the beginning of the article does.&lt;/p&gt;
&lt;p&gt;I suspect that Clojure is too dynamic and there are too many layers of
abstraction (such as laziness, sequences, etc) to expect a perfect automatic
loop fusion from the JVM here. This is why we resort to fusing the loops
manually; well, not really manually - we actually use some higher-order function
goodness to accomplish this for us. If you squint hard at the
&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;mapping-transform&lt;/span&gt;&lt;/tt&gt; function above, you may notice that it fuses the mapping
function into the reducing function.&lt;/p&gt;
&lt;p&gt;All of this makes me wonder - what if we &lt;em&gt;really&lt;/em&gt; fuse the loops manually, can
we go even faster? It turns out yes, but only for some types of sequences. Let's
start by changing the &lt;tt class="docutils literal"&gt;s&lt;/tt&gt; in the benchmark to a materialized vector (&lt;tt class="docutils literal"&gt;range&lt;/tt&gt;
actually produces a lazy sequence):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;reducers.core=&amp;gt; (def sv (vec s))
#&amp;#39;reducers.core/sv
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And now let's re-run the benchmark of regular filter-map-reduce with the
reducers-infused filter-map-reduce:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;reducers.core=&amp;gt; (time (reduce + 0 (map inc (filter even? sv))))
&amp;quot;Elapsed time: 555.125033 msecs&amp;quot;
25000000000000
reducers.core=&amp;gt; (time (reduce + 0 (r/map inc (r/filter even? sv))))
&amp;quot;Elapsed time: 371.145887 msecs&amp;quot;
25000000000000
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;But now let's add another contender - a manually fused reducing function that
combines the addition, filtering and increment mapping:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;reducers.core=&amp;gt; (time (reduce (fn [acc item] (if (even? item)
                                               (+ acc (inc item))
                                               acc))
                               0 sv))
&amp;quot;Elapsed time: 324.793784 msecs&amp;quot;
25000000000000
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Hah, even faster! Of course, writing such pipelines manually is not always
practical, isn't composable and quickly gets unreadable, so in most cases using
reducers is preferred. But that's not all. Reducers have another trick in the
sleeve - effortless parallelism.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="folding-in-parallel"&gt;
&lt;h2&gt;Folding in parallel&lt;/h2&gt;
&lt;p&gt;Let's begin this section right with the punchline:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;reducers.core=&amp;gt; (time (r/fold + (r/map inc (r/filter even? sv))))
&amp;quot;Elapsed time: 145.529636 msecs&amp;quot;
25000000000000
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Whoa, what happened? Given an appropriate collection (such as a vector) that is
&lt;em&gt;foldable&lt;/em&gt;, and an appropriate reducing function that is &lt;em&gt;associative&lt;/em&gt;, we can
actually perform a reduction in parallel on multiple cores. The trick is
breaking the input sequence into chunks, reducing each chunk and then reducing
the results of the chunks. For foldable collections and associative reducing
functions this is mathematically equivalent to the original task; and the big
win is that we can reduce separate chunk in parallel, on different CPU cores.
Which is exactly what &lt;tt class="docutils literal"&gt;r/fold&lt;/tt&gt; does for us, automatically. Even though the
operation done on each item is trivial, &lt;tt class="docutils literal"&gt;r/fold&lt;/tt&gt; generates a 2x speedup on an
8-core CPU. For longer operations, the speedup could be even better.&lt;/p&gt;
&lt;p&gt;How awesome is that? We barely changed the code and get a considerably better
performance, leveraging parallelism. All of this is possible due to the
abstraction created by the reducers library. Remember the part about decoupling
the actual collection from the operations to reduce it? This comes useful here.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="transducers"&gt;
&lt;h2&gt;Transducers&lt;/h2&gt;
&lt;p&gt;Remember our discussion of transforming reducing functions above? A transforming
function (such as &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;mapping-transform&lt;/span&gt;&lt;/tt&gt;) has the pseudo-type:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;transformingf :: (acc -&amp;gt; item -&amp;gt; acc) -&amp;gt; (acc -&amp;gt; item -&amp;gt; acc)
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;It takes a reducing function and returns another reducing function. We've just
seen how this concept is used in the reducers library to decouple the
transformation from the actual process of reduction.&lt;/p&gt;
&lt;p&gt;Shortly after introducing reducers, the designers of Clojure had another
insight. Such transforming functions are useful not just in the context of
reductions. The Clojure core developers were designing utility functions for
&lt;tt class="docutils literal"&gt;core.async&lt;/tt&gt; to transform channels (more on this later), and found themselves
rewriting a bunch of existing logic from existing mapping and transforming
functions. The solution? Use the concept of transforming functions to define
sequence transformations in a more abstract way, completely decoupling them from
the underlying sequences.&lt;/p&gt;
&lt;p&gt;So transforming functions got a new name - &lt;em&gt;transducers&lt;/em&gt;, and got integrated
more tightly into the language. Now many of the built-in sequence processing
like &lt;tt class="docutils literal"&gt;map&lt;/tt&gt; have an additional arity where no sequence is actually passed in.
&lt;tt class="docutils literal"&gt;(map inc)&lt;/tt&gt;, for example, simply returns a &lt;em&gt;transducer&lt;/em&gt; - a transforming
function for other reducers. These transducers are composable, so another way
to write the non-parallel reduction we've been using in the benchmarks is:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;reduce &lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nb"&gt;comp &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;filter &lt;/span&gt;&lt;span class="nv"&gt;even?&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;map &lt;/span&gt;&lt;span class="nv"&gt;inc&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;+&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;sv&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Note that the order here is similar to the one we had to apply with our own
&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;filtering-transform&lt;/span&gt;&lt;/tt&gt; and &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;mapping-transform&lt;/span&gt;&lt;/tt&gt;, to convey that we first
filter and then map (it's also similar to the Clojure &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;-&amp;gt;&lt;/span&gt;&lt;/tt&gt; macro).&lt;/p&gt;
&lt;p&gt;Aimed with the insights of this article, we can actually look under the hood
of Clojure's built-in &lt;tt class="docutils literal"&gt;map&lt;/tt&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;defn &lt;/span&gt;&lt;span class="nv"&gt;map&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nv"&gt;f&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;fn &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;rf&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;fn&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;rf&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nv"&gt;result&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;rf&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;result&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nv"&gt;result&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;input&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;rf&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;result&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;f&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;input&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nv"&gt;result&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;input&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;inputs&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;rf&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;result&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;apply &lt;/span&gt;&lt;span class="nv"&gt;f&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;input&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;inputs&lt;/span&gt;&lt;span class="p"&gt;))))))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nv"&gt;f&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;coll&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="c1"&gt;;; Implementation of other, non-transducer arities.&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="c1"&gt;;; ...&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To be a true transducer, a Clojure function must have three arities. I'll skip
the no-argument and single-argument versions (please read a more comprehensive
reference on transducers for the full scoop). The 2-arity version is where the
real meat is and, oh wait, it's &lt;em&gt;exactly&lt;/em&gt; the same as our &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;mapping-transform&lt;/span&gt;&lt;/tt&gt;
from this article!&lt;/p&gt;
&lt;p&gt;So OK, now &amp;quot;functions that transform reducing functions&amp;quot; have a shorter name -
&lt;em&gt;transducers&lt;/em&gt;; but what has actually changed?&lt;/p&gt;
&lt;p&gt;What's really changed is that the &lt;tt class="docutils literal"&gt;map&lt;/tt&gt; transducer has a wider range of
applicability than just mapping collections. Its implementation has no
collection-specific code. Let's see how it can be used to transform
communication channels.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="pipelines-and-transducers"&gt;
&lt;h2&gt;Pipelines and transducers&lt;/h2&gt;
&lt;p&gt;Clojure has borrowed go-routines and channels from Go, and placed them in a
standard libray module named &lt;tt class="docutils literal"&gt;core.async&lt;/tt&gt;. Unfortunately, a thorough
discussion of &lt;tt class="docutils literal"&gt;core.async&lt;/tt&gt; is outside the scope of this article. I'll just say
that &lt;tt class="docutils literal"&gt;core.async&lt;/tt&gt; is awesome; that it was implemented as a library without
changing the language is beyond awesome - it's a terrific example of the power
of Lisps to &lt;em&gt;grow the language&lt;/em&gt; towards the problem domain.&lt;/p&gt;
&lt;p&gt;That said, I do want to mention &lt;tt class="docutils literal"&gt;core.async&lt;/tt&gt; in the context of transducers,
since the two mix in an interesting way.&lt;/p&gt;
&lt;p&gt;Let's take the simple squaring pipeline from &lt;a class="reference external" href="https://blog.golang.org/pipelines"&gt;Go concurrency patterns&lt;/a&gt; and rewrite it in Clojure. The first
version is a pretty-much verbatim transcription:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;defn &lt;/span&gt;&lt;span class="nv"&gt;gen-1&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;let &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;async/chan&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;async/go&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;doseq &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;async/&amp;gt;!&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;async/close!&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;defn &lt;/span&gt;&lt;span class="nv"&gt;sq-1&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;cin&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;let &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;cout&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;async/chan&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;async/go-loop&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;async/&amp;lt;!&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;cin&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;do&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;async/&amp;gt;!&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;cout&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;* &lt;/span&gt;&lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;recur&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;async/&amp;lt;!&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;cin&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;async/close!&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;cout&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;cout&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;defn &lt;/span&gt;&lt;span class="nv"&gt;main-1&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;let &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;c-gen&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;gen-1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nv"&gt;c-sq&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;sq-1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;c-gen&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;loop &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;async/&amp;lt;!!&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;c-sq&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;when &lt;/span&gt;&lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;println &lt;/span&gt;&lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;recur&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;async/&amp;lt;!!&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;c-sq&lt;/span&gt;&lt;span class="p"&gt;))))))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;There are two pipeline stages; the first, &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;gen-1&lt;/span&gt;&lt;/tt&gt; generates a sequence of
numbers into a channel. The second, &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;sq-1&lt;/span&gt;&lt;/tt&gt; takes a channel of inputs,
transforms them (by squaring each number) and puts the results in another
channel. &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;main-1&lt;/span&gt;&lt;/tt&gt; connects the two pipeline stages together.&lt;/p&gt;
&lt;p&gt;The second version makes more use of higher-level &lt;tt class="docutils literal"&gt;core.async&lt;/tt&gt; tools:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;defn &lt;/span&gt;&lt;span class="nv"&gt;gen-2&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;async/to-chan&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;defn &lt;/span&gt;&lt;span class="nv"&gt;sq-2&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;cin&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;async/map&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;* &lt;/span&gt;&lt;span class="nv"&gt;%&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;%&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;cin&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;defn &lt;/span&gt;&lt;span class="nv"&gt;main-2&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;let &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;c-gen&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;gen-2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nv"&gt;c-sq&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;sq-2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;c-gen&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;loop &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;async/&amp;lt;!!&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;c-sq&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;when &lt;/span&gt;&lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;println &lt;/span&gt;&lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;recur&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;async/&amp;lt;!!&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;c-sq&lt;/span&gt;&lt;span class="p"&gt;))))))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;gen-2&lt;/span&gt;&lt;/tt&gt;, &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;to-chan&lt;/span&gt;&lt;/tt&gt; places its input collection into a channel, and closes
the channel; all of this in a separate go-block, of course. &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;sq-2&lt;/span&gt;&lt;/tt&gt; uses the
&lt;tt class="docutils literal"&gt;map&amp;lt;&lt;/tt&gt; function to create a mapping channel which takes items from its input
channel, maps some function on them and returns a channel of results.&lt;/p&gt;
&lt;p&gt;If you read the documentation of &lt;tt class="docutils literal"&gt;core.async&lt;/tt&gt;, you'll notice that &lt;tt class="docutils literal"&gt;map&amp;lt;&lt;/tt&gt; is
now deprecated and you're advised to &amp;quot;use transducers instead&amp;quot;. Let's see how to
do that, in this third version:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;defn &lt;/span&gt;&lt;span class="nv"&gt;main-3&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;let &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;c-sq&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;async/chan&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;map &lt;/span&gt;&lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;* &lt;/span&gt;&lt;span class="nv"&gt;%&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;%&lt;/span&gt;&lt;span class="p"&gt;)))]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;async/onto-chan&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;c-sq&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;loop &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;async/&amp;lt;!!&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;c-sq&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;when &lt;/span&gt;&lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;println &lt;/span&gt;&lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;recur&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;async/&amp;lt;!!&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;c-sq&lt;/span&gt;&lt;span class="p"&gt;))))))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Here we create a &lt;em&gt;single&lt;/em&gt; channel named &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;c-sq&lt;/span&gt;&lt;/tt&gt;, with a mapping transducer.
This means that every item going through the channel gets transformed with the
given mapping function before being read out of the channel. We don't need
a separate channel, and &lt;tt class="docutils literal"&gt;core.async&lt;/tt&gt; doesn't need a separate mapping helper.&lt;/p&gt;
&lt;p&gt;In fact, with the introduction of transducers &lt;tt class="docutils literal"&gt;core.async&lt;/tt&gt; deprecated a whole
bunch of functions. &lt;tt class="docutils literal"&gt;map&amp;lt;&lt;/tt&gt;, &lt;tt class="docutils literal"&gt;filter&amp;lt;&lt;/tt&gt;, &lt;tt class="docutils literal"&gt;unique&lt;/tt&gt;, &lt;tt class="docutils literal"&gt;partition&lt;/tt&gt; and so on.
While implementing these for channels, the Clojure core devs had the epiphany
that they're basically reimplementing all sequence processing functions in a
different context &lt;a class="footnote-reference" href="#footnote-6" id="footnote-reference-6"&gt;[6]&lt;/a&gt;. Transducers is an elegant solution to abstract away the
concept of transformation from the underlying context (be it collections or
channels, or...)&lt;/p&gt;
&lt;p&gt;It's easy to compose transducers on channels. Here's a silly example:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;defn &lt;/span&gt;&lt;span class="nv"&gt;square&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;x&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;* &lt;/span&gt;&lt;span class="nv"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;x&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;def &lt;/span&gt;&lt;span class="nv"&gt;xform&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;comp&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;filter &lt;/span&gt;&lt;span class="nv"&gt;even?&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;filter &lt;/span&gt;&lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;&amp;lt; &lt;/span&gt;&lt;span class="nv"&gt;%&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;map &lt;/span&gt;&lt;span class="nv"&gt;square&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;map &lt;/span&gt;&lt;span class="nv"&gt;inc&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;def &lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;async/chan&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;xform&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;async/go&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;async/onto-chan&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;loop &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;async/&amp;lt;!!&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;when &lt;/span&gt;&lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;println &lt;/span&gt;&lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;recur&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;async/&amp;lt;!!&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="p"&gt;))))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Here the transducer is more complex, applying several filtering and mapping
steps on the items going through the channel. That said, as we've seen earlier
in the article this is actually pretty efficient, with no unnecessary copying
involved.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="closing-thoughts-on-the-generality-of-reducing-functions"&gt;
&lt;h2&gt;Closing thoughts - on the generality of reducing functions&lt;/h2&gt;
&lt;p&gt;It's interesting to ponder how reducing functions, from the humble beginning of
the workhorse of &lt;tt class="docutils literal"&gt;reduce&lt;/tt&gt;, became the most important building block of the
concepts discussed in this article. Recall that a reducing function has the
type:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;reducingf :: acc -&amp;gt; item -&amp;gt; acc
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I think the key insight is that taking and returning the new combined value
permits a reducing function to implement things like filtering, because we can
convey the concept of including or not including the current item in the
combined result. Clojure's reductions also support the &lt;tt class="docutils literal"&gt;reduced&lt;/tt&gt; call for
early termination, and keeping state between reductions can help implement more
involved processing steps. For a fairly complete example of all these tools,
take a look at the implementation of the transducer variant of &lt;tt class="docutils literal"&gt;take&lt;/tt&gt; in the
&lt;a class="reference external" href="https://github.com/clojure/clojure/blob/master/src/clj/clojure/core.clj"&gt;Clojure core library sources&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The code snippets shown throughout the article are &lt;a class="reference external" href="https://github.com/eliben/code-for-blog/tree/main/2017/reducers-transducers-async"&gt;available on GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;hr class="docutils" /&gt;
&lt;table class="docutils footnote" frame="void" id="footnote-1" rules="none"&gt;
&lt;colgroup&gt;&lt;col class="label" /&gt;&lt;col /&gt;&lt;/colgroup&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td class="label"&gt;&lt;a class="fn-backref" href="#footnote-reference-1"&gt;[1]&lt;/a&gt;&lt;/td&gt;&lt;td&gt;This is a Haskell-y type notation. &lt;tt class="docutils literal"&gt;x &lt;span class="pre"&gt;-&amp;gt;&lt;/span&gt; y &lt;span class="pre"&gt;-&amp;gt;&lt;/span&gt; z&lt;/tt&gt; means a function
taking a parameter of type &lt;tt class="docutils literal"&gt;x&lt;/tt&gt; and a parameter of type &lt;tt class="docutils literal"&gt;y&lt;/tt&gt; and
returning a value of type &lt;tt class="docutils literal"&gt;z&lt;/tt&gt;. &lt;tt class="docutils literal"&gt;(x &lt;span class="pre"&gt;-&amp;gt;&lt;/span&gt; y) &lt;span class="pre"&gt;-&amp;gt;&lt;/span&gt; z&lt;/tt&gt; means we take one
parameter of type &amp;quot;function taking &lt;tt class="docutils literal"&gt;x&lt;/tt&gt; and returning &lt;tt class="docutils literal"&gt;y&lt;/tt&gt;) and
return a value of type &lt;tt class="docutils literal"&gt;z&lt;/tt&gt;.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table class="docutils footnote" frame="void" id="footnote-2" rules="none"&gt;
&lt;colgroup&gt;&lt;col class="label" /&gt;&lt;col /&gt;&lt;/colgroup&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td class="label"&gt;&lt;a class="fn-backref" href="#footnote-reference-2"&gt;[2]&lt;/a&gt;&lt;/td&gt;&lt;td&gt;Execrise: modify this code to produce a new vector of squares, instead
of summing them up. Your solution will still use &lt;tt class="docutils literal"&gt;reduce&lt;/tt&gt;.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table class="docutils footnote" frame="void" id="footnote-3" rules="none"&gt;
&lt;colgroup&gt;&lt;col class="label" /&gt;&lt;col /&gt;&lt;/colgroup&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td class="label"&gt;&lt;a class="fn-backref" href="#footnote-reference-3"&gt;[3]&lt;/a&gt;&lt;/td&gt;&lt;td&gt;The actual &lt;a class="reference external" href="https://github.com/clojure/clojure/blob/master/src/clj/clojure/core/reducers.clj"&gt;reducers library&lt;/a&gt;
cleverly uses Clojure protocols to make this process even more abstract
and let sequences decide the best way to reduce them. It's worth checking
out, though there's quite a bit of added complexity that obscures away
the main point I want to make in this article.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table class="docutils footnote" frame="void" id="footnote-4" rules="none"&gt;
&lt;colgroup&gt;&lt;col class="label" /&gt;&lt;col /&gt;&lt;/colgroup&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td class="label"&gt;&lt;a class="fn-backref" href="#footnote-reference-4"&gt;[4]&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;p class="first"&gt;We have to give up laziness though, since Clojure's &lt;tt class="docutils literal"&gt;reduce&lt;/tt&gt; is
inherently &lt;em&gt;eager&lt;/em&gt;. It implements left-folding rather than right-folding,
so it can't be run on infinite sequences.&lt;/p&gt;
&lt;p class="last"&gt;This is usually not a very big deal; while infinite sequences are a nice
abstraction in some cases, most of the real data processing tasks we have
are, luckily, finite.&lt;/p&gt;
&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table class="docutils footnote" frame="void" id="footnote-5" rules="none"&gt;
&lt;colgroup&gt;&lt;col class="label" /&gt;&lt;col /&gt;&lt;/colgroup&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td class="label"&gt;&lt;a class="fn-backref" href="#footnote-reference-5"&gt;[5]&lt;/a&gt;&lt;/td&gt;&lt;td&gt;Benchmarking in Clojure is tricky since the JVM needs some warmup for the
heavy-handed JIT to kick-in, so it's worth rerunning such benchmarks
several times and collecting the fastest runtime. The numbers shown here
are representative of the results obtained on my machine.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table class="docutils footnote" frame="void" id="footnote-6" rules="none"&gt;
&lt;colgroup&gt;&lt;col class="label" /&gt;&lt;col /&gt;&lt;/colgroup&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td class="label"&gt;&lt;a class="fn-backref" href="#footnote-reference-6"&gt;[6]&lt;/a&gt;&lt;/td&gt;&lt;td&gt;There's a small caveat here to be aware of, IMHO. Pipelines as
demonstrated in the Go article linked here aren't only useful to decouple
the different steps. They are also useful to actually &lt;em&gt;parallelize&lt;/em&gt; them.
Squaring is a toy example, but imagine this step in the pipeline was time
consuming. Then the go-routines running the generating step (or some
other pipeline step) could actually run in parallel with the squaring
step. When we use transducers as shown here, this flexibility goes away.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
</content><category term="misc"></category><category term="Clojure"></category><category term="Programming"></category><category term="Concurrency"></category></entry><entry><title>Notes on debugging Clojure code</title><link href="https://eli.thegreenplace.net/2017/notes-on-debugging-clojure-code/" rel="alternate"></link><published>2017-05-23T20:02:00-07:00</published><updated>2022-10-04T14:08:24-07:00</updated><author><name>Eli Bendersky</name></author><id>tag:eli.thegreenplace.net,2017-05-23:/2017/notes-on-debugging-clojure-code/</id><summary type="html">&lt;p&gt;Clojure is a great programming language, but a recurring complaint one keeps
hearing from developers hacking on Clojure code is that debugging can be
unpleasant. First of all, I agree! Debugging Clojure code &lt;em&gt;can&lt;/em&gt; be more daunting
on average than, say, debugging Python code. This is mainly due to two …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Clojure is a great programming language, but a recurring complaint one keeps
hearing from developers hacking on Clojure code is that debugging can be
unpleasant. First of all, I agree! Debugging Clojure code &lt;em&gt;can&lt;/em&gt; be more daunting
on average than, say, debugging Python code. This is mainly due to two reasons:&lt;/p&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;Clojure's Java legacy. Clojure is compiled to Java bytecode, which has some
terminology and idiosyncracies Clojure programmers aren't always familiar
with. These terms tend to pop up in stack traces and cause confusion (e.g.
&lt;tt class="docutils literal"&gt;IFN&lt;/tt&gt;).&lt;/li&gt;
&lt;li&gt;Clojure - being a Lisp - has a certain code structure which is different
from, say, a more common imperative coding style. Rather than being a
sequence of statements, Clojure programs tend to involve long call chains of
nested expressions. Where only part of an expression fails, it's often
non-trivial to figure out why.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;In this post I want to share some notes from my own experience debugging Clojure
programs.&lt;/p&gt;
&lt;div class="section" id="dealing-with-clojure-s-cryptic-exceptions"&gt;
&lt;h2&gt;Dealing with Clojure's cryptic exceptions&lt;/h2&gt;
&lt;p&gt;The first problem with Clojure's runtime exceptions is that we usually don't get
to see the full stack trace &lt;em&gt;by default&lt;/em&gt;. Let's say we have this silly,
nonsensical, function in a file called &lt;tt class="docutils literal"&gt;sample.clj&lt;/tt&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;defn &lt;/span&gt;&lt;span class="nv"&gt;foo&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;cond &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;&amp;gt; &lt;/span&gt;&lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;+ &lt;/span&gt;&lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;&amp;gt; &lt;/span&gt;&lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;- &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;first &lt;/span&gt;&lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="ss"&gt;:else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Then to try how it works, we load the file into the REPL and type the following
&lt;a class="footnote-reference" href="#footnote-1" id="footnote-reference-1"&gt;[1]&lt;/a&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;debugging.core=&amp;gt; (foo 24)
IllegalArgumentException Don&amp;#39;t know how to create ISeq from: java.lang.Long
  clojure.lang.RT.seqFrom (RT.java:542)
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Uh oh. There are two problems here. First, what does this error message mean?
What's &lt;tt class="docutils literal"&gt;ISeq&lt;/tt&gt; and what's &lt;tt class="docutils literal"&gt;java.lang.Long&lt;/tt&gt;? Second, it's not clear where it
is actually failing (thanks for that pointer to &lt;tt class="docutils literal"&gt;RT.java&lt;/tt&gt; though, Clojure!)
Let's address the second problem first. The magic incantation to show the stack
trace of the last exception is calling the &lt;tt class="docutils literal"&gt;pst&lt;/tt&gt; function:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;debugging.core=&amp;gt; (pst)
IllegalArgumentException Don&amp;#39;t know how to create ISeq from: java.lang.Long
  clojure.lang.RT.seqFrom (RT.java:542)
  clojure.lang.RT.seq (RT.java:523)
  clojure.lang.RT.first (RT.java:668)
  clojure.core/first--4339 (core.clj:55)
  clojure.core/first--4339 (core.clj:55)
  debugging.sample/foo (sample.clj:10)
  debugging.sample/foo (sample.clj:7)
  debugging.core/eval13715 (form-init6539101589609174055.clj:1)
  debugging.core/eval13715 (form-init6539101589609174055.clj:1)
  clojure.lang.Compiler.eval (Compiler.java:6927)
  clojure.lang.Compiler.eval (Compiler.java:6890)
  clojure.core/eval (core.clj:3105)
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This is much better because at least &lt;em&gt;some&lt;/em&gt; files in this trace are familiar.
&lt;tt class="docutils literal"&gt;core.clj&lt;/tt&gt; is not &lt;em&gt;our&lt;/em&gt; &lt;tt class="docutils literal"&gt;core.clj&lt;/tt&gt;, it's Clojure's core library. But
&lt;tt class="docutils literal"&gt;sample.clj&lt;/tt&gt; &lt;em&gt;is&lt;/em&gt; our file, and we can infer that on line 10 we call
&lt;tt class="docutils literal"&gt;clojure,core/first&lt;/tt&gt; and something goes wrong. Line 10 happens to be:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;&amp;gt; &lt;/span&gt;&lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;- &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;first &lt;/span&gt;&lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;So now things become more clear. The call &lt;tt class="docutils literal"&gt;(first n)&lt;/tt&gt; must be bad, and bad in
a way that tries to coerce clojure into creating an &lt;tt class="docutils literal"&gt;ISeq&lt;/tt&gt; from a &lt;tt class="docutils literal"&gt;Long&lt;/tt&gt;.
In other words, we're passing a number into a function that expects a sequence,
and this is, indeed, bad. Learning to map from Clojure values and types to the
JVM's expectations will take time and grit - especially if you (like me) don't
have much Java experience. I suggest doing a bit of reading on Clojure/Java
interoperability, and about other Java-isms Clojure inherits; it ain't pretty,
and you may not always want to use it, but being familiar with the terms can go
a long way in deciphering cryptic stack traces.&lt;/p&gt;
&lt;p&gt;For a more detailed treatment of this debugging issue I highly recommend
&lt;a class="reference external" href="https://aphyr.com/posts/319-clojure-from-the-ground-up-debugging"&gt;Aphyr's article on debugging Clojure&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="finding-which-form-an-exception-comes-from"&gt;
&lt;h2&gt;Finding which form an exception comes from&lt;/h2&gt;
&lt;p&gt;Let's invoke the &lt;tt class="docutils literal"&gt;foo&lt;/tt&gt; function in a different way that demonstrates another
issue with debugging Clojure:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;debugging.core=&amp;gt; (foo nil)

NullPointerException   clojure.lang.Numbers.ops (Numbers.java:1013)
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;OK, we know what to do next:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;debugging.core=&amp;gt; (pst)
NullPointerException
  clojure.lang.Numbers.ops (Numbers.java:1013)
  clojure.lang.Numbers.gt (Numbers.java:229)
  clojure.lang.Numbers.gt (Numbers.java:3864)
  debugging.sample/foo (sample.clj:9)
  debugging.sample/foo (sample.clj:7)
  debugging.core/eval14693 (form-init6539101589609174055.clj:1)
  debugging.core/eval14693 (form-init6539101589609174055.clj:1)
  clojure.lang.Compiler.eval (Compiler.java:6927)
  clojure.lang.Compiler.eval (Compiler.java:6890)
  clojure.core/eval (core.clj:3105)
  clojure.core/eval (core.clj:3101)
  clojure.main/repl/read-eval-print--7408/fn--7411 (main.clj:240)
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;So the exception comes from line 9, which is:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;cond &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;&amp;gt; &lt;/span&gt;&lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;+ &lt;/span&gt;&lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This exception also tells us it comes from &lt;tt class="docutils literal"&gt;clojure.lang.Numbers.gt&lt;/tt&gt; from
which we can infer it's the &lt;tt class="docutils literal"&gt;&amp;gt;&lt;/tt&gt; operator that is complaining. But imagine for
a second that we had two forms with the same operator on that line:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;cond &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;&amp;gt; &lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;* &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;+ &lt;/span&gt;&lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;+ &lt;/span&gt;&lt;span class="nv"&gt;m&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If we got a &lt;tt class="docutils literal"&gt;NullPointerException&lt;/tt&gt; about an addition, we wouldn't know which
one fails. Luckily, Clojure comes with a very useful module that helps
debugging - &lt;a class="reference external" href="https://github.com/clojure/tools.trace"&gt;tools.trace&lt;/a&gt;. In this
particular case, we'd use the &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;trace-forms&lt;/span&gt;&lt;/tt&gt; macro  which tells us which
nested form (expression) is failing. We can modify our function to be:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;defn &lt;/span&gt;&lt;span class="nv"&gt;foo&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;trace-forms&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;cond &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;&amp;gt; &lt;/span&gt;&lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;+ &lt;/span&gt;&lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                     &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;&amp;gt; &lt;/span&gt;&lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;- &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;first &lt;/span&gt;&lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                     &lt;/span&gt;&lt;span class="ss"&gt;:else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And now when called with &lt;tt class="docutils literal"&gt;nil&lt;/tt&gt;, we get:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;debugging.core=&amp;gt; (foo nil)
NullPointerException : No message attached to throwable java.lang.NullPointerException
  Form failed: (&amp;gt; n 40)
  Form failed: (if
 (&amp;gt; n 40)
 (+ n 20)
 (clojure.core/cond (&amp;gt; n 20) (- (first n) 20) :else 0))
  Form failed: (cond (&amp;gt; n 40) (+ n 20) (&amp;gt; n 20) (- (first n) 20) :else 0)
  clojure.lang.Numbers.ops (Numbers.java:1013)
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Neat, huh? &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;trace-forms&lt;/span&gt;&lt;/tt&gt; breaks the form it traces to all the nested forms
and reports precisely which one failed - propagating this information upwards
towards the top form &lt;a class="footnote-reference" href="#footnote-2" id="footnote-reference-2"&gt;[2]&lt;/a&gt;. &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;trace-forms&lt;/span&gt;&lt;/tt&gt; is &lt;em&gt;very&lt;/em&gt; useful when errors manifest
as exceptions.&lt;/p&gt;
&lt;p&gt;Unfortunately, this isn't sufficient for all cases. Our &lt;tt class="docutils literal"&gt;foo&lt;/tt&gt; wasn't designed
to handle &lt;tt class="docutils literal"&gt;nil&lt;/tt&gt;s, and the bug here is in the place where the &lt;tt class="docutils literal"&gt;nil&lt;/tt&gt; came
from. This may be quite a bit removed - and not on the same stack trace - from
where &lt;tt class="docutils literal"&gt;foo&lt;/tt&gt; is invoked. We'll get an exception when &lt;tt class="docutils literal"&gt;foo&lt;/tt&gt; is called, but the
&lt;em&gt;real&lt;/em&gt; challenge is to find where the &lt;tt class="docutils literal"&gt;nil&lt;/tt&gt; came from. More generally, bugs
that manifest as thrown exceptions are the easier kind of bugs. The more
insidious bugs hide in programs that run just fine end-to-end but compute
slightly incorrect results.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="tracing-and-logging"&gt;
&lt;h2&gt;Tracing and logging&lt;/h2&gt;
&lt;p&gt;This gets us into the more general domain of debugging, where the tricks and
tools programmers use are as varied as the bugs hiding in our programs. When it
comes to debugging, I'm firmly in the &lt;tt class="docutils literal"&gt;printf&lt;/tt&gt; camp; I rarely prefer debuggers
over &lt;tt class="docutils literal"&gt;printf&lt;/tt&gt;-based debugging &lt;a class="footnote-reference" href="#footnote-3" id="footnote-reference-3"&gt;[3]&lt;/a&gt;, and Clojure is no exception. In fact, due
to the way Clojure programs look (nested forms), I find that debuggers are even
less useful in Clojure than in other languages. On the other hand, Clojure's
macros make it possible to trace / print stuff in a very nice way.&lt;/p&gt;
&lt;p&gt;For example, I find that it's useful to be able to turn debugging printouts on
and off frequently. So I have this trusty code in my utilities:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;def &lt;/span&gt;&lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="ss"&gt;:dynamic&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;*verbose*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;defmacro &lt;/span&gt;&lt;span class="nv"&gt;printfv&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;fmt&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;args&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;when &lt;/span&gt;&lt;span class="nv"&gt;*verbose*&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;printf&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="nv"&gt;fmt&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;~@&lt;/span&gt;&lt;span class="nv"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Calls to &lt;tt class="docutils literal"&gt;printfv&lt;/tt&gt; can be freely scattered around the code; by default,
they will not print anything. When I do want to see what these &lt;tt class="docutils literal"&gt;printfv&lt;/tt&gt;s
have to say, another macro comes useful:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;defmacro &lt;/span&gt;&lt;span class="nv"&gt;with-verbose&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;body&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;binding &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;*verbose*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;true&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;~@&lt;/span&gt;&lt;span class="nv"&gt;body&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Here's how it works; Suppose we've written this factorial function, with a
debugging printout:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;defn &lt;/span&gt;&lt;span class="nv"&gt;factorial&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;printfv&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;factorial: %d%n&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;&amp;lt; &lt;/span&gt;&lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;* &lt;/span&gt;&lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;factorial&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;- &lt;/span&gt;&lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)))))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now, if we just call it as usual from the REPL, we get:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;debugging.core=&amp;gt; (factorial 6)
720
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;But if we want to actually see the debugging output, we call:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;debugging.core=&amp;gt; (with-verbose (factorial 6))
factorial: 6
factorial: 5
factorial: 4
factorial: 3
factorial: 2
factorial: 1
factorial: 0
720
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This optional verbosity is perfect when you're in the middle of a furious bug
hunt, adding &lt;tt class="docutils literal"&gt;printfv&lt;/tt&gt;s in many places in your code. &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;with-verbose&lt;/span&gt;&lt;/tt&gt; can
turn verbose logging on selectively and control the amount of debugging spew
&lt;a class="footnote-reference" href="#footnote-4" id="footnote-reference-4"&gt;[4]&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This example brings us back to the &lt;tt class="docutils literal"&gt;tools.trace&lt;/tt&gt; library, which provides
another awesome tool that helps trace function calls (the bread and butter of
Clojure programs). Enter &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;trace-vars&lt;/span&gt;&lt;/tt&gt;. After importing it, all we need to do
is invoke it on any functions we want traced; for example:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;debugging.core=&amp;gt; (trace-vars factorial)
#&amp;#39;debugging.core/factorial
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And now invoking our &lt;tt class="docutils literal"&gt;factorial&lt;/tt&gt; produces:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;debugging.core=&amp;gt; (factorial 6)
TRACE t16315: (debugging.core/factorial 6)
TRACE t16316: | (debugging.core/factorial 5)
TRACE t16317: | | (debugging.core/factorial 4)
TRACE t16318: | | | (debugging.core/factorial 3)
TRACE t16319: | | | | (debugging.core/factorial 2)
TRACE t16320: | | | | | (debugging.core/factorial 1)
TRACE t16321: | | | | | | (debugging.core/factorial 0)
TRACE t16321: | | | | | | =&amp;gt; 1
TRACE t16320: | | | | | =&amp;gt; 1
TRACE t16319: | | | | =&amp;gt; 2
TRACE t16318: | | | =&amp;gt; 6
TRACE t16317: | | =&amp;gt; 24
TRACE t16316: | =&amp;gt; 120
TRACE t16315: =&amp;gt; 720
720
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We get to see the full call tree, including values of parameters and what each
call returns. It even works for mutually-recursive functions:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;defn &lt;/span&gt;&lt;span class="nv"&gt;iseven?&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;= &lt;/span&gt;&lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;true&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;isodd?&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;- &lt;/span&gt;&lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;defn &lt;/span&gt;&lt;span class="nv"&gt;isodd?&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;= &lt;/span&gt;&lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;false&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;iseven?&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;- &lt;/span&gt;&lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Let's try it:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;debugging.core=&amp;gt; (trace-vars iseven? isodd?)
#&amp;#39;debugging.core/isodd?
debugging.core=&amp;gt; (iseven? 7)
TRACE t16332: (debugging.core/iseven? 7)
TRACE t16333: | (debugging.core/isodd? 6)
TRACE t16334: | | (debugging.core/iseven? 5)
TRACE t16335: | | | (debugging.core/isodd? 4)
TRACE t16336: | | | | (debugging.core/iseven? 3)
TRACE t16337: | | | | | (debugging.core/isodd? 2)
TRACE t16338: | | | | | | (debugging.core/iseven? 1)
TRACE t16339: | | | | | | | (debugging.core/isodd? 0)
TRACE t16339: | | | | | | | =&amp;gt; false
TRACE t16338: | | | | | | =&amp;gt; false
TRACE t16337: | | | | | =&amp;gt; false
TRACE t16336: | | | | =&amp;gt; false
TRACE t16335: | | | =&amp;gt; false
TRACE t16334: | | =&amp;gt; false
TRACE t16333: | =&amp;gt; false
TRACE t16332: =&amp;gt; false
false
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Note how easy it to see what calls what. Quite often, bugs are uncovered simply
by carefully studying the chain of function calls some input tickles in our
code, and &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;trace-vars&lt;/span&gt;&lt;/tt&gt; is a very low-effort method to enable this kind of
debugging.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="deeper-tracing-inside-cond-forms"&gt;
&lt;h2&gt;Deeper tracing inside &lt;tt class="docutils literal"&gt;cond&lt;/tt&gt; forms&lt;/h2&gt;
&lt;p&gt;Tracing function calls is great, but sometimes insufficient. It's not uncommon
to have &lt;tt class="docutils literal"&gt;cond&lt;/tt&gt; forms in functions, and sometimes it's pretty hard to know
which condition was actually &amp;quot;taken&amp;quot; (this isn't always easy to infer from the
return value of the function). We've seen how to explore where exceptions come
from with &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;trace-forms&lt;/span&gt;&lt;/tt&gt;, but exceptions are just one kind of problem. The more
difficul problem arises when the code throws no exceptions but still produces a
wrong value.&lt;/p&gt;
&lt;p&gt;I've mentioned how Clojure's macro superpowers let us write very powerful
debugging tools. What follows is another example.&lt;/p&gt;
&lt;p&gt;Consider this toy code:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;cond &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;&amp;gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;+ &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;&amp;gt; &lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;- &lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="ss"&gt;:else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;It happens to return 10 since the second condition fires. But suppose it stands
for a much more complicated &lt;tt class="docutils literal"&gt;cond&lt;/tt&gt; where it's not obvious which condition was
taken and where the return value came from. How do we go about debugging this?&lt;/p&gt;
&lt;p&gt;Well, we can always add a &lt;tt class="docutils literal"&gt;printfv&lt;/tt&gt; into every result expression (possibly
wrapping in a &lt;tt class="docutils literal"&gt;do&lt;/tt&gt; form) and see what fires. This would work, but it's quite
tiresome, especially for large &lt;tt class="docutils literal"&gt;cond&lt;/tt&gt;s. To do this automatically, we can
write the following macro:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;defmacro &lt;/span&gt;&lt;span class="nv"&gt;condv&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;clauses&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;when &lt;/span&gt;&lt;span class="nv"&gt;clauses&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;list&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="ss"&gt;&amp;#39;if&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;first &lt;/span&gt;&lt;span class="nv"&gt;clauses&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;next &lt;/span&gt;&lt;span class="nv"&gt;clauses&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;do &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;println &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;str &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;condv &amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;#39;~&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;first &lt;/span&gt;&lt;span class="nv"&gt;clauses&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;second &lt;/span&gt;&lt;span class="nv"&gt;clauses&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;throw&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;IllegalArgumentException.&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;               &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;cond requires an even number of forms&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;cons &lt;/span&gt;&lt;span class="ss"&gt;&amp;#39;condv&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;next &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;next &lt;/span&gt;&lt;span class="nv"&gt;clauses&lt;/span&gt;&lt;span class="p"&gt;))))))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;It behaves just like &lt;tt class="docutils literal"&gt;cond&lt;/tt&gt;, while also printing out the condition that fired.
If we replace the &lt;tt class="docutils literal"&gt;cond&lt;/tt&gt; in the original example with &lt;tt class="docutils literal"&gt;condv&lt;/tt&gt; and evaluate
it, we'll get:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;debugging.core=&amp;gt; (condv (&amp;gt; 10 20) (+ 10 20)
            #_=&amp;gt;        (&amp;gt; 20 10) (- 20 10)
            #_=&amp;gt;        :else 200)
condv (&amp;gt; 20 10)
10
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Note the printout before the return value of 10: &lt;tt class="docutils literal"&gt;condv (&amp;gt; 20 10)&lt;/tt&gt; - it shows
us exactly which condition was taken.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="conclusion"&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;While beginning Clojure programmers may find the debugging experience
challenging, I believe that with some effort and perseverance it's possible to
get used to the unusual environment and even reach new levels of productivity
by developing a set of debugging tools and techniques.&lt;/p&gt;
&lt;p&gt;In this endeavor, Clojure's macro capabilities are an extremely powerful ally.
Coupled with a fast edit-rerun cycle in the REPL, such tools can turn Clojure
debugging into a much less painful activity.&lt;/p&gt;
&lt;hr class="docutils" /&gt;
&lt;table class="docutils footnote" frame="void" id="footnote-1" rules="none"&gt;
&lt;colgroup&gt;&lt;col class="label" /&gt;&lt;col /&gt;&lt;/colgroup&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td class="label"&gt;&lt;a class="fn-backref" href="#footnote-reference-1"&gt;[1]&lt;/a&gt;&lt;/td&gt;&lt;td&gt;Alternatively, we can evaluate the same expression somewhere in our
editor using a Clojure plugin (such as &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;vim-fireplace&lt;/span&gt;&lt;/tt&gt; for Vim).&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table class="docutils footnote" frame="void" id="footnote-2" rules="none"&gt;
&lt;colgroup&gt;&lt;col class="label" /&gt;&lt;col /&gt;&lt;/colgroup&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td class="label"&gt;&lt;a class="fn-backref" href="#footnote-reference-2"&gt;[2]&lt;/a&gt;&lt;/td&gt;&lt;td&gt;The astute reader will notice a slight discrepancy between our code and
the output of &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;trace-form&lt;/span&gt;&lt;/tt&gt;. We don't have an &lt;tt class="docutils literal"&gt;if&lt;/tt&gt; form, or do we?
Quiz: what does &lt;tt class="docutils literal"&gt;cond&lt;/tt&gt; expand to? Complex interactions between macros
and functions is yet another reason debugging Clojure code is sometimes
hard...&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table class="docutils footnote" frame="void" id="footnote-3" rules="none"&gt;
&lt;colgroup&gt;&lt;col class="label" /&gt;&lt;col /&gt;&lt;/colgroup&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td class="label"&gt;&lt;a class="fn-backref" href="#footnote-reference-3"&gt;[3]&lt;/a&gt;&lt;/td&gt;&lt;td&gt;In my professional life I spent far more time writing debuggers than
actually using them.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table class="docutils footnote" frame="void" id="footnote-4" rules="none"&gt;
&lt;colgroup&gt;&lt;col class="label" /&gt;&lt;col /&gt;&lt;/colgroup&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td class="label"&gt;&lt;a class="fn-backref" href="#footnote-reference-4"&gt;[4]&lt;/a&gt;&lt;/td&gt;&lt;td&gt;This method is only recommended when the debugging prinouts are destined
to be eventually eliminated from the code. For more permanent logging
with more verbosity controls, consider using a proper logging library
like &lt;a class="reference external" href="https://github.com/clojure/tools.logging"&gt;tools.logging&lt;/a&gt;.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
</content><category term="misc"></category><category term="Clojure"></category><category term="Lisp"></category></entry></feed>