<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Lisp on John Jacobsen</title>
    <link>http://johnj.com/tags/lisp/</link>
    <description>Recent content in Lisp on John Jacobsen</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en-us</language>
    <lastBuildDate>Fri, 11 Apr 2025 00:00:00 +0000</lastBuildDate><atom:link href="http://johnj.com/tags/lisp/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Lisp Testing Fun</title>
      <link>http://johnj.com/posts/a-fun-little-testing-macro/</link>
      <pubDate>Fri, 11 Apr 2025 00:00:00 +0000</pubDate>
      
      <guid>http://johnj.com/posts/a-fun-little-testing-macro/</guid>
      <description>&lt;p&gt;





&lt;a href=&#34;http://johnj.com/verticals.jpg&#34;&gt;&lt;img class=&#34;resize&#34; src=&#34;http://johnj.com/verticals_hu_67b3acf8c49855f4.jpg&#34; style=&#34;width:400px; border:0px solid black;&#34;/&gt;&lt;/a&gt;

&lt;/p&gt;
&lt;p&gt;
I&amp;#39;ve been making some progress with &lt;code class=&#34;verbatim&#34;&gt;steelcut&lt;/code&gt;, &lt;a href=&#34;https://github.com/eigenhombre/steelcut&#34;&gt;my Common Lisp
template generator&lt;/a&gt; (does every Lisper write one of these as a rite of
passage?), and I keep running into interesting problems which
have been fun to solve.&lt;/p&gt;
&lt;p&gt;
Whenever my code starts to accumulate any sort of complexity, I
try to err on the side of writing more tests, even for
&amp;#34;recreational&amp;#34; projects such as this one.  The tests help make it safe to make
changes, while also documenting the expected functionality.  But test
code can be fairly repetitive, often with many small variations and
lots of boilerplate, in the midst of which it can be hard to see the
forest for the trees.&lt;/p&gt;
&lt;p&gt;
Such was the case for &lt;code class=&#34;verbatim&#34;&gt;steelcut&lt;/code&gt; tests.  I found myself remembering
Paul Graham&amp;#39;s &lt;a href=&#34;https://www.paulgraham.com/icad.html&#34;&gt;line&lt;/a&gt;, &amp;#34;Any other regularity in the code is a sign, to me
at least, that I&amp;#39;m using abstractions that aren&amp;#39;t powerful enough –
often that I&amp;#39;m generating by hand the expansions of some macro that I
need to write.&amp;#34;&lt;/p&gt;
&lt;p&gt;
In my current non-Lisp programming work, I most often miss macros when
writing test code.  But in this case, the macro I (apparently) needed
to write &lt;a href=&#34;https://github.com/eigenhombre/steelcut/blob/1db2122b7cc620510fad030646cc32f4c58a1bcc/test/test.lisp#L82&#34;&gt;is here&lt;/a&gt;.  Very roughly speaking, &lt;code class=&#34;verbatim&#34;&gt;with-setup&lt;/code&gt; creates a
temporary directory, runs the template generator with a given list of
requested features, and allows the user to check properties of the
generated files.&lt;/p&gt;
&lt;p&gt;
The macro grew and shrank as I DRYed out and simplified the test code.
I realized many of my tests were checking the generated dependencies
for the projects (from the .ASD file), so it would be helpful if the
macro would make those available to the test code in the form of a
function the user could name.&lt;/p&gt;
&lt;p&gt;
This wound up being a sweet bit of sugar for my tests, but not every
test needed such a helper function.  Stubborn &amp;#34;unused variable&amp;#34;
warnings ensued, for those tests which don&amp;#39;t use the &lt;code class=&#34;verbatim&#34;&gt;deps&lt;/code&gt; symbol
bound by the macro.  I went back and forth with ChatGPT on this one
(it made several wrong suggestions) until I realized I could give the
variable an explicit &lt;code class=&#34;verbatim&#34;&gt;_&lt;/code&gt; name and change the behavior based on the
name.  This is something I&amp;#39;ve seen in other languages and was tickled
I could get it so easily here.&lt;/p&gt;
&lt;p&gt;
I find the resulting tests pretty easy to read:&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(test needed-files-created
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  (with-setup appname &amp;#34;testingapp&amp;#34; appdir _ +default-features+
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    (loop for file in &amp;#39;(&amp;#34;Makefile&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                        &amp;#34;Dockerfile&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                        &amp;#34;.github/workflows/build.yml&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                        &amp;#34;build.sh&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                        &amp;#34;test.sh&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                        &amp;#34;src/main.lisp&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                        &amp;#34;src/package.lisp&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                        &amp;#34;test/test.lisp&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                        &amp;#34;test/package.lisp&amp;#34;)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;          do
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;             (is (uiop:file-exists-p (join/ appdir file))))))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(test cmd-feature-adds-dependency-and-example
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  (with-setup appname &amp;#34;testingapp&amp;#34; appdir deps +default-features+
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    (let ((main-text (slurp (join/ appdir &amp;#34;src/main.lisp&amp;#34;))))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      ;; :cmd is not there:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      (is (not (find :cmd (deps))))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      ;; It doesn&amp;#39;t contain the example function:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      (is (not (has-cmd-example-p main-text)))))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  ;; Add :cmd to features, should get the new dependency:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  (with-setup appname &amp;#34;test2&amp;#34; appdir deps (cons :cmd +default-features+)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    (let ((main-text (slurp (join/ appdir &amp;#34;src/main.lisp&amp;#34;))))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      ;; :cmd is now there:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      (is (find :cmd (deps)))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      ;; It contains the example function:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      (is (has-cmd-example-p main-text)))))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
&lt;em&gt;N.B.&lt;/em&gt;: A keyword argument would also work, obviously.  For a macro
in production code, I would probably go that route instead.&lt;/p&gt;
&lt;div id=&#34;outline-container-headline-1&#34; class=&#34;outline-2&#34;&gt;
&lt;h2 id=&#34;headline-1&#34;&gt;
Fun
&lt;/h2&gt;
&lt;div id=&#34;outline-text-headline-1&#34; class=&#34;outline-text-2&#34;&gt;
&lt;p&gt;
I&amp;#39;ve also been thinking about &lt;a href=&#34;https://news.ycombinator.com/item?id=43651576&#34;&gt;a recent post on Hacker News&lt;/a&gt;, and the
ensuing discussion, in which both the author and commenters point out
that programming Lisp is &lt;em&gt;fun&lt;/em&gt;.  While I must acknowledge that Lisp
has been a life-long attraction/distraction/diversion, I&amp;#39;m noticing
that the &lt;em&gt;way&lt;/em&gt; it is fun for me is evolving somewhat.&lt;/p&gt;
&lt;p&gt;
First, I used to find Common Lisp pretty painful because of all its
sharp edges – the language is so powerful and flexible, you can shoot
yourself in the foot pretty much any way you like, and it&amp;#39;s not as
easy as some newer languages to get started with.  But now, with LLMs,
it&amp;#39;s much easier to get help when you get into the weeds.  Sure, &amp;#34;the
corpus of training data was smaller for Lisp than for mainstream
languages,&amp;#34; blah, blah.  But often even the wrong answers from ChatGPT
point me in the right direction (some of this is probably just
&lt;a href=&#34;https://en.wikipedia.org/wiki/Rubber_duck_debugging&#34;&gt;rubberducking&lt;/a&gt;).  When one&amp;#39;s own ignorance is less of an obstacle, the
pointy bits become less intimidating.&lt;/p&gt;
&lt;p&gt;
Second, there are some &lt;em&gt;really&lt;/em&gt; good, and fun, books on Lisp.  &lt;a href=&#34;https://github.com/norvig/paip-lisp?tab=readme-ov-file&#34;&gt;PAIP&lt;/a&gt;,
&lt;a href=&#34;https://letoverlambda.com/&#34;&gt;Let Over Lambda&lt;/a&gt;, &lt;a href=&#34;https://gigamonkeys.com/book/&#34;&gt;Practical Common Lisp&lt;/a&gt;, &lt;a href=&#34;http://landoflisp.com/&#34;&gt;Land of Lisp&lt;/a&gt; (plus &lt;a href=&#34;https://www.youtube.com/watch?v=HM1Zb3xmvMc&#34;&gt;video&lt;/a&gt;!).
Lisp has some pretty mind-bending things in it, and I&amp;#39;m enjoying
taking the time to dig into some of these books again, understanding
things better than the first time I swung by.&lt;/p&gt;
&lt;p&gt;
Third, I&amp;#39;m regularly stunned by how fast Lisp is.  All the tests I&amp;#39;ve
been writing run effectively instantly at the REPL on my M1 Macbook
Air.  And now that I&amp;#39;m starting to get good enough at the language
that it is getting out of my way, that speed is more noticeable, and,
well, fun.&lt;/p&gt;
&lt;p&gt;
Finally, I am intrigued by the history of computing, of which Lisp has
been an important part.  This is worth saying more about in a future
post, but for the moment I find a stable, highly-performant, &lt;em&gt;fun&lt;/em&gt;
language that has intrigued people for decades to be more of interest
than the bleeding edge.  (I&amp;#39;m not hating on Rust.  Rust is nice.  But
I don&amp;#39;t find it fun, at least not yet.)&lt;/p&gt;
&lt;p&gt;
Beyond fun, I&amp;#39;m also enjoying &amp;#34;&lt;a href=&#34;https://stevelosh.com/blog/2018/08/a-road-to-common-lisp/#s4-escaping-the-hamster-wheel-of-backwards-incompatibility&#34;&gt;escaping the hamster wheel of backwards
incompatibility&lt;/a&gt;&amp;#34; for awhile.  While so many things around us crumble
and whirl, and new forms of AI scare the pants out of us as much as
they intrigue, older tools and traditions start to feel more like
comfortable tools that weigh down one&amp;#39;s hands satisfyingly and invite
calm creation.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
</description>
    </item>
    
    <item>
      <title>To The Metal... Compiling Your Own Language(s)</title>
      <link>http://johnj.com/posts/to-the-metal/</link>
      <pubDate>Tue, 06 Aug 2024 00:00:00 +0000</pubDate>
      
      <guid>http://johnj.com/posts/to-the-metal/</guid>
      <description>
&lt;p&gt;





&lt;a href=&#34;http://johnj.com/eclipse.jpg&#34;&gt;&lt;img class=&#34;resize&#34; src=&#34;http://johnj.com/eclipse_hu_4b980836f660ca22.jpg&#34; style=&#34;width:400px; border:0px solid black;&#34;/&gt;&lt;/a&gt;

&lt;/p&gt;
&lt;p&gt;
Like many programmers, I have programming &lt;a href=&#34;http://johnj.com/posts/in-defense-of-hobbies/&#34;&gt;hobbies&lt;/a&gt;.  One of these is
implementing new languages.  My most recent language project, &lt;a href=&#34;https://github.com/eigenhombre/l1/&#34;&gt;l1&lt;/a&gt;, was
a Lisp dialect whose primary data types are symbols and
arbitrarily-large integers.&lt;/p&gt;
&lt;p&gt;
I&amp;#39;ve been happy with &lt;code class=&#34;verbatim&#34;&gt;l1&lt;/code&gt;, but it is interpreted; since I was actively
working on it last (2022), I&amp;#39;ve been wondering about the best way to
generate &lt;em&gt;compiled&lt;/em&gt; standalone executable programs, written in &lt;code class=&#34;verbatim&#34;&gt;l1&lt;/code&gt; or
any other language.&lt;/p&gt;
&lt;div id=&#34;outline-container-headline-1&#34; class=&#34;outline-2&#34;&gt;
&lt;h2 id=&#34;headline-1&#34;&gt;
The Problem In General
&lt;/h2&gt;
&lt;div id=&#34;outline-text-headline-1&#34; class=&#34;outline-text-2&#34;&gt;
&lt;p&gt;
Execution models for programming languages take three basic
approaches, listed in increasing order of speed:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Tree-walking interpreter&lt;/strong&gt;: Programs are read and parsed into ASTs
in memory, then executed step-by-step by an interpreter.  This
is the approach &lt;code class=&#34;verbatim&#34;&gt;l1&lt;/code&gt; uses.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Bytecode VM&lt;/strong&gt;: Programs are compiled into a sort of abstract
machine language, simpler than the physical processor&amp;#39;s, and
executed by a virtual machine (VM).  Java and Python work this way.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Machine code generation&lt;/strong&gt;: The code is directly compiled into
machine language and executed on the user&amp;#39;s hardware.  C and C++
programs work this way.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Languages using Option 2 often add just-in-time compilation to machine
code, for extra performance.  Option 3 is typically fastest, but is
sometimes skipped in introductory compiler classes and tutorials.  For
example, Robert Nystrom&amp;#39;s excellent &lt;em&gt;&lt;a href=&#34;https://craftinginterpreters.com/&#34;&gt;Crafting Interpreters&lt;/a&gt;&lt;/em&gt; book
devotes the first section to implementing a tree-walking interpreter
implementation in Java and the second half to a compiler and bytecode
VM written in C, with minimal coverage of how to target physical
hardware.  And the (also excellent) &lt;a href=&#34;https://dabeaz.com/compiler.html&#34;&gt;class on compiler writing&lt;/a&gt; that I
took from David Beazley, in its first incarnation, stopped at the
point of generating of so-called intermediate representation (IR)
output (though students in the current iteration of the class do
compile to native code, using LLVM).&lt;/p&gt;
&lt;p&gt;
Compiling to machine code is tricky because CPUs are inherently
complex. Real hardware is intricate, cumbersome, and unintuitive if
you&amp;#39;re primarily accustomed to high-level languages. Additionally,
there are numerous significant variants to consider (e.g., CPU/GPU,
ARM/Intel, 32-bit/64-bit architectures).&lt;/p&gt;
&lt;p&gt;
But targeting machine code rather than interpreters or bytecode VMs is
appealing, not just because it is an interesting challenge, but also
because the resulting artifacts are small, stand-alone, and typically
very fast.  While running Python, Ruby, and Java programs require the
appropriate infrastructure to be in place on the target machine at all
times, Go, Rust, and C programs (among others) benefit from targeting
the physical hardware: their programs tend to be smaller, and can be
deployed to identical computers simply by copying the executable file,
needing to deploy the interpreter, extra libraries, etc. to the target
machine(s).&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&#34;outline-container-headline-2&#34; class=&#34;outline-2&#34;&gt;
&lt;h2 id=&#34;headline-2&#34;&gt;
Small Is Beautiful
&lt;/h2&gt;
&lt;div id=&#34;outline-text-headline-2&#34; class=&#34;outline-text-2&#34;&gt;
&lt;p&gt;
As a programmer who came up during the dawn of personal computers, I
have some nostalgia for an era when programs or even entire operating
systems fit on a few-hundred-kB floppy disk.  Much existing software
feels bloated to me, though some widespread tools are still lean and
fast. For illustration purposes, here are the physical sizes of some
of the venerable command-line Unix programs I use on a daily basis
(this is on MacOS):&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Program&lt;/th&gt;
&lt;th class=&#34;align-right&#34;&gt;Size (kB)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&#34;verbatim&#34;&gt;wc&lt;/code&gt;&lt;/td&gt;
&lt;td class=&#34;align-right&#34;&gt;100&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&#34;verbatim&#34;&gt;cat&lt;/code&gt;&lt;/td&gt;
&lt;td class=&#34;align-right&#34;&gt;116&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&#34;verbatim&#34;&gt;df&lt;/code&gt;&lt;/td&gt;
&lt;td class=&#34;align-right&#34;&gt;116&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&#34;verbatim&#34;&gt;more&lt;/code&gt;&lt;/td&gt;
&lt;td class=&#34;align-right&#34;&gt;360&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;
These were chosen more or less at random from my &lt;code class=&#34;verbatim&#34;&gt;bash&lt;/code&gt; history and
are representative of old-school Unix utilities.  For comparison,
iMovie on my Mac is &lt;strong&gt;2.8 GB&lt;/strong&gt;, several thousand times larger than the
largest of these.  Of course, the comparison is somewhat ludicrous -
iMovie does many amazing things… but I use all the above programs
hundreds or thousands of times more often than I do iMovie, so it&amp;#39;s
good that that they are compact and run quickly.  In a time of
increasingly bloated software stacks,
I find myself especially drawn to simple tools with small footprints.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&#34;outline-container-headline-3&#34; class=&#34;outline-2&#34;&gt;
&lt;h2 id=&#34;headline-3&#34;&gt;
An Approach
&lt;/h2&gt;
&lt;div id=&#34;outline-text-headline-3&#34; class=&#34;outline-text-2&#34;&gt;
&lt;p&gt;
If targeting physical hardware is hard, what tools can we use to make
the job easier?&lt;/p&gt;
&lt;p&gt;
I recently started learning about &lt;a href=&#34;https://llvm.org/&#34;&gt;LLVM&lt;/a&gt;, a modular set of compiler
tools which &amp;#34;can be used to develop a frontend for any programming
language and a backend for any instruction set architecture&amp;#34;
(&lt;a href=&#34;https://en.wikipedia.org/wiki/LLVM&#34;&gt;Wikipedia&lt;/a&gt;).  LLVM has been used heavily in the Rust toolchain and in
Apple&amp;#39;s developer tools.&lt;/p&gt;
&lt;p&gt;
The &amp;#34;modular&amp;#34; adjective is critical here: LLVM is separated into
front-end, back-end and optimizing parts thanks to a shared
&amp;#34;&lt;a href=&#34;https://en.wikipedia.org/wiki/Intermediate_representation&#34;&gt;intermediate representation&lt;/a&gt;&amp;#34; (IR) – a sort of portable assembly
language which represents simple computation steps in a
machine-independent but low-level manner.&lt;/p&gt;
&lt;p&gt;
The LLVM IR takes a little getting used to but, with a little
practice, is reasonably easy to read, and, more importantly, to
generate.&lt;/p&gt;
&lt;p&gt;
As an example, consider the following simple C program, &lt;code class=&#34;verbatim&#34;&gt;three.c&lt;/code&gt;,
which stores the number 3 in a variable and uses it as its exit code.
We will use &lt;code class=&#34;verbatim&#34;&gt;clang&lt;/code&gt;, the LLVM C/C++/Obj-C/… compiler for the LLVM
ecosystem:&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ cat three.c
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;int x = 3;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;int main() {
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  return x;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ clang three.c -o three
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ ./three; echo $?
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;3&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
One can easily view, and possibly even understand, the assembler
output for such a simple program:&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ clang -O3 -S three.c -o three.s
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ cat -n three.s
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;     1		.section	__TEXT,__text,regular,pure_instructions
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;     2		.build_version macos, 14, 0	sdk_version 14, 4
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;     3		.globl	_main                           ; -- Begin function main
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;     4		.p2align	2
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;     5	_main:                                  ; @main
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;     6		.cfi_startproc
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;     7	; %bb.0:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;     8	Lloh0:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;     9		adrp	x8, _x@PAGE
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    10	Lloh1:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    11		ldr	w0, [x8, _x@PAGEOFF]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    12		ret
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    13		.loh AdrpLdr	Lloh0, Lloh1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    14		.cfi_endproc
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    15	                                        ; -- End function
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    16		.section	__DATA,__data
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    17		.globl	_x                              ; @x
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    18		.p2align	2, 0x0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    19	_x:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    20		.long	3                               ; 0x3
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    21
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    22	.subsections_via_symbols&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
In comparison, here is the LLVM IR for the same program:&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ clang -S -emit-llvm three.c -o three.ll
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ cat -n three.ll
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;     1	; ModuleID = &amp;#39;three.c&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;     2	source_filename = &amp;#34;three.c&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;     3	target datalayout = &amp;#34;e-m:o-i64:64-i128:128-n32:64-S128&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;     4	target triple = &amp;#34;arm64-apple-macosx14.0.0&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;     5
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;     6	@x = global i32 3, align 4
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;     7
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;     8	; Function Attrs: noinline nounwind optnone ssp uwtable(sync)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;     9	define i32 @main() #0 {
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    10	  %1 = alloca i32, align 4
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    11	  store i32 0, ptr %1, align 4
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    12	  %2 = load i32, ptr @x, align 4
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    13	  ret i32 %2
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    14	}
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    15
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    16	attributes #0 = { noinline nounwind optnone ssp ;; .... very long list...
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    17
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    18	!llvm.module.flags = !{!0, !1, !2, !3, !4}
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    19	!llvm.ident = !{!5}
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    20
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    21	!0 = !{i32 2, !&amp;#34;SDK Version&amp;#34;, [2 x i32] [i32 14, i32 4]}
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    22	!1 = !{i32 1, !&amp;#34;wchar_size&amp;#34;, i32 4}
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    23	!2 = !{i32 8, !&amp;#34;PIC Level&amp;#34;, i32 2}
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    24	!3 = !{i32 7, !&amp;#34;uwtable&amp;#34;, i32 1}
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    25	!4 = !{i32 7, !&amp;#34;frame-pointer&amp;#34;, i32 1}
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    26	!5 = !{!&amp;#34;Apple clang version 15.0.0 (clang-1500.3.9.4)&amp;#34;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
There is a fair amount of stuff here, but a lot of it looks
suspiciously like metadata we don&amp;#39;t really care about for our
experiments going forward.  The, uh, &lt;code class=&#34;verbatim&#34;&gt;main&lt;/code&gt; region of interest is from
lines 9-14 – notice that the function definition itself looks a
little more readable than the assembly language version, but slightly
lower-level than the original C program.&lt;/p&gt;
&lt;p&gt;
You can turn the IR into a runnable program:&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ clang -O3 three.ll -o three
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ ./three; echo $?
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;3&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
The approach I explore here is to &lt;em&gt;generate&lt;/em&gt; LLVM IR &amp;#34;by fair means or foul.&amp;#34;
Here, let&amp;#39;s just edit our IR down to something more minimal and see how it goes.
I suspect the &lt;code class=&#34;verbatim&#34;&gt;store&lt;/code&gt; of &lt;code class=&#34;verbatim&#34;&gt;0&lt;/code&gt; in &amp;#34;register&amp;#34; &lt;code class=&#34;verbatim&#34;&gt;%1&lt;/code&gt; is gratuitous, so
let&amp;#39;s try to remove it, along with all the metadata:&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ cat 3.ll
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;target triple = &amp;#34;x86_64-apple-macosx14.0.0&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;@x = global i32 3, align 4
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;define i32 @main() {
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  %1 = load i32, ptr @x, align 4
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  ret i32 %1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ clang -O3 3.ll -o 3
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ ./3; echo $?
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;3&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
This is frankly not much more complicated than the C code, and it
shows a helpful strategy at work:&lt;/p&gt;
&lt;p&gt;
Step 1: To understand how to accomplish something in LLVM IR,
write the corresponding C program and use &lt;code class=&#34;verbatim&#34;&gt;clang&lt;/code&gt; to generate
the IR, being alert for possible &amp;#34;extra stuff&amp;#34; like we saw
in the example.&lt;/p&gt;
&lt;p&gt;
Step 2. Try to generate, and test, working programs from the IR you
write or adapt, making adjustments as desired.&lt;/p&gt;
&lt;p&gt;
There is another, optional step as well:&lt;/p&gt;
&lt;p&gt;
Step 3. Use, or write, language &amp;#34;bindings&amp;#34; to drive LLVM generation
from the language of your choice.  This is the step we will consider next.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&#34;outline-container-headline-4&#34; class=&#34;outline-2&#34;&gt;
&lt;h2 id=&#34;headline-4&#34;&gt;
Enter Babashka
&lt;/h2&gt;
&lt;div id=&#34;outline-text-headline-4&#34; class=&#34;outline-text-2&#34;&gt;
&lt;p&gt;
While one can write LLVM IR directly, as we have seen, we are
interested in compiling other languages (possibly higher-level ones of
our own invention), so we will want to &lt;em&gt;generate&lt;/em&gt; IR somehow.  For
this project I chose &lt;a href=&#34;https://babashka.org/&#34;&gt;Babashka&lt;/a&gt;, an implementation of the &lt;a href=&#34;https://clojure.org/&#34;&gt;Clojure&lt;/a&gt;
programming language I have found ideal for small projects where both
start-up speed and expressiveness are important.&lt;/p&gt;
&lt;p&gt;
(I assume some familiarity with Lisp and Clojure in this post; for those
just getting started, &lt;a href=&#34;https://www.braveclojure.com/&#34;&gt;Clojure for the Brave and True&lt;/a&gt; is a good introduction.)&lt;/p&gt;
&lt;p&gt;
The repo &lt;a href=&#34;https://github.com/eigenhombre/llbb&#34;&gt;https://github.com/eigenhombre/llbb&lt;/a&gt; contains the source files
discussed here.  The bulk of the code in this repo is in &lt;a href=&#34;https://github.com/eigenhombre/llbb/blob/master/llir.bb&#34;&gt;&lt;code class=&#34;verbatim&#34;&gt;llir.bb&lt;/code&gt;&lt;/a&gt;, a
source file which provides alternative definitions in Clojure for
common LLVM idioms.  Some of these are trivial translations:&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(def m1-target &amp;#34;arm64-apple-macosx14.0.0&amp;#34;)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(defn target [t] (format &amp;#34;target triple = \&amp;#34;%s\&amp;#34;&amp;#34; t))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
… whereas other expressions leverage the power of Clojure to a
greater degree.  For example, this section defines translations used
to represent arithmetic operations:&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(defn arithm [op typ a b]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  (format &amp;#34;%s %s %s, %s&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;          (name? op)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;          (name? typ)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;          (sigil a)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;          (sigil b)))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(defn add [typ a b] (arithm :add typ a b))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(defn sub [typ a b] (arithm :sub typ a b))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(defn mul [typ a b] (arithm :mul typ a b))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(defn div [typ a b] (arithm :sdiv typ a b))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(comment
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  (div :i32 :a :b)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  ;;=&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &amp;#34;sdiv i32 %a, %b&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  (add :i8 :x 1)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  ;;=&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &amp;#34;add i8 %x, 1&amp;#34;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
You can see this approach at work by representing the C program
discussed earlier:&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(module
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; (assign-global :i :i32 3)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; (def-fn :i32 :main []
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   (assign :retval (load :i32 :i))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   (ret :i32 :retval)))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
which evaluates to&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;target triple = &amp;#34;arm64-apple-macosx14.0.0&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;@i = global i32 3
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;define i32 @main() nounwind {
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  %retval = load i32, i32* @i, align 4
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  ret i32 %retval
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
I use here a slightly different but equivalent pointer syntax for the
&lt;code class=&#34;verbatim&#34;&gt;load&lt;/code&gt; expression than output by &lt;code class=&#34;verbatim&#34;&gt;clang&lt;/code&gt; in the example above.&lt;/p&gt;
&lt;p&gt;
Two very small helper functions allow me to test out small programs quickly:&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(require &amp;#39;[babashka.process :as sh])
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(defn sh
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  Use `bash` to run command(s) `s`, capturing both stdout/stderr
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  as a concatenated string.  Throw an exception if the exit code
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  is nonzero.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  [s]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  (let [{:keys [out err]}
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        (sh/shell {:out :string, :err :string}
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                  (format &amp;#34;bash -c &amp;#39;%s&amp;#39;&amp;#34; s))]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    (str/join &amp;#34;\n&amp;#34; (remove empty? [out err]))))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
and&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(require &amp;#39;[babashka.fs :as fs])
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(defn compile-to
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  Save IR `body` to a temporary file and compile it, writing the
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  resulting binary to `progname` in the current working directory.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  [progname body]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  (let [ll-file
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        (str (fs/create-temp-file {:prefix &amp;#34;llbb-&amp;#34;, :suffix &amp;#34;.ll&amp;#34;}))]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    (spit ll-file body)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    (sh (format &amp;#34;clang -O3 %s -o %s&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                ll-file
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                progname))))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
These two together allow me to test small programs out quickly at the
REPL.  Some examples follow, obtained by running the C compiler for
equivalent programs, generating and inspecting the LLVM IR, and
translating them into new Clojure bindings as cleanly as possible.&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;Minimum viable program&lt;/strong&gt;: just return zero:&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(compile-to &amp;#34;smallest-prog&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            (module
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;             (def-fn :i32 :main []
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;               (ret :i32 0))))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(sh &amp;#34;./smallest-prog; echo -n $?&amp;#34;)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;;=&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&amp;#34;0&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
&lt;strong&gt;Argument count&lt;/strong&gt;: return, as the exit code, the number of arguments,
including the program name:&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; Argument counting: return number of arguments as an exit code:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(compile-to &amp;#34;argcount&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            (module
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;             (def-fn :i32 :main [[:i32 :arg0]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                                 [:ptr :arg1_unused]]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;               (assign :retptr (alloca :i32))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;               (store :i32 :arg0 :ptr :retptr)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;               (assign :retval (load :i32 :retptr))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;               (ret :i32 :retval))))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(sh &amp;#34;./argcount; echo -n $?&amp;#34;) ;;=&amp;gt; &amp;#34;1&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(sh &amp;#34;./argcount 1 2 3; echo -n $?&amp;#34;) ;;=&amp;gt; &amp;#34;4&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
&lt;strong&gt;Hello, world&lt;/strong&gt;:&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(let [msg &amp;#34;Hello, World.&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      n (inc (count msg))] ;; Includes string terminator
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  (compile-to &amp;#34;hello&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;              (module
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;               (external-fn :i32 :puts :i8*)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;               (def-global-const-str :message msg)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;               (def-fn :i32 :main []
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                 (assign :as_ptr
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                         (gep (fixedarray n :i8)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                              (star (fixedarray n :i8))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                              (sigil :message)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                              [:i64 0]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                              [:i64 0]))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                 (call :i32 :puts [:i8* :as_ptr])
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                 (ret :i32 0)))))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(sh &amp;#34;./hello&amp;#34;) ;;=&amp;gt; &amp;#34;Hello, World.\n&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
This is the first program one typically writes in a new programming
language.  Note that we use here idioms (&lt;code class=&#34;verbatim&#34;&gt;external-fn&lt;/code&gt;, &lt;code class=&#34;verbatim&#34;&gt;call&lt;/code&gt;) to
define and invoke an external function from the C standard library.&lt;/p&gt;
&lt;p&gt;
Let&amp;#39;s see how big the resulting program is:&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(sh &amp;#34;ls -l hello&amp;#34;)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;;=&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&amp;#34;-rwxr-xr-x  1 jacobsen  staff  33432 Aug 14 21:09 hello\n&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
At this point I want to pause to reconsider one of the points of this
exercise, which is to produce small programs. Here are the rough
executable sizes for a &amp;#34;Hello, World&amp;#34; example program in various
languages that I use frequently:&lt;/p&gt;
&lt;table&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Language&lt;/td&gt;
&lt;td&gt;Size&lt;/td&gt;
&lt;td class=&#34;align-right&#34;&gt;Relative Size&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Common Lisp&lt;/td&gt;
&lt;td&gt;38 MB&lt;/td&gt;
&lt;td class=&#34;align-right&#34;&gt;1151&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Clojure&lt;/td&gt;
&lt;td&gt;3.4 MB&lt;/td&gt;
&lt;td class=&#34;align-right&#34;&gt;103&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Go&lt;/td&gt;
&lt;td&gt;1.9 MB&lt;/td&gt;
&lt;td class=&#34;align-right&#34;&gt;58&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;C&lt;/td&gt;
&lt;td&gt;33 kB&lt;/td&gt;
&lt;td class=&#34;align-right&#34;&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;LLVM IR&lt;/td&gt;
&lt;td&gt;33 kB&lt;/td&gt;
&lt;td class=&#34;align-right&#34;&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;
I threw Clojure in there for comparison even though, unlike the other
examples, the resulting überjar also requires a Java bytecode VM in
order to run.  The programs generated from C and from LLVM IR are
equivalent; this is not surprising, given that I used the C program to
guide my writing and translation of the LLVM IR.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&#34;outline-container-headline-5&#34; class=&#34;outline-2&#34;&gt;
&lt;h2 id=&#34;headline-5&#34;&gt;
Building A Compiling Calculator
&lt;/h2&gt;
&lt;div id=&#34;outline-text-headline-5&#34; class=&#34;outline-text-2&#34;&gt;
&lt;p&gt;
We are now ready to implement a &amp;#34;compiler&amp;#34; for something approaching a
useful language, namely, greatly reduced subset of &lt;a href=&#34;https://en.wikipedia.org/wiki/Forth_(programming_language&#34;&gt;Forth&lt;/a&gt;.  Forth is a
stack-based language created in the 1970s and still in use
today, especially for small embedded systems.&lt;/p&gt;
&lt;p&gt;
LLVM will handle the parts commonly known as &amp;#34;compiler backend&amp;#34; tasks,
and Babashka will provide our &amp;#34;frontend,&amp;#34; namely breaking the text into
tokens and parsing them.  This task is made easy for us, because Forth
is syntactically quite simple, and Babashka relatively powerful. Here are
the language rules we will adopt:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Program tokens are separated by whitespace.&lt;/li&gt;
&lt;li&gt;Non-numeric tokens are math operators.&lt;/li&gt;
&lt;li&gt;Only integer operands are allowed.&lt;/li&gt;
&lt;li&gt;Comments begin with &lt;code class=&#34;verbatim&#34;&gt;\\&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Forth expressions typically place the arguments first, and the operator
last (so-called &amp;#34;reverse-Polish notation&amp;#34;).  Here is an example program
which does some math and prints the result:&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(def example &amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;2 2 +  \\ 4
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;5 *    \\ multiply by five to get 20
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;2 /    \\ divide by 2 -&amp;gt; 10
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-1 +   \\ add -1 -&amp;gt; 9
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;8 -    \\ subtract 8 -&amp;gt; 1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;.      \\ prints &amp;#39;1&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&amp;#34;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
The code in &lt;a href=&#34;https://github.com/eigenhombre/llbb/blob/master/forth.bb&#34;&gt;&lt;code class=&#34;verbatim&#34;&gt;forth.bb&lt;/code&gt;&lt;/a&gt; handles the parser, whose goal is to consume the
raw program text and generate an abstract syntax tree (in our case, just
a list) of operations to translate into IR:&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(defn strip-comments
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  Remove parts of lines beginning with backslash
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  [s]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  (str/replace s #&amp;#34;(?sm)^(.*?)\\.*?$&amp;#34; &amp;#34;$1&amp;#34;))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(defn tokenize
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  Split `s` on any kind of whitespace
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  [s]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  (remove empty? (str/split s #&amp;#34;\s+&amp;#34;)))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(defrecord node
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    [typ val] ;; A node has a type and a value
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  Object
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  (toString [this]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    (format &amp;#34;[%s %s]&amp;#34; (:typ this) (:val this))))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; Allowed operations
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(def opmap {&amp;#34;+&amp;#34; :add
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &amp;#34;-&amp;#34; :sub
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &amp;#34;/&amp;#34; :div
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &amp;#34;*&amp;#34; :mul
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &amp;#34;.&amp;#34; :dot
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &amp;#34;drop&amp;#34; :drop})
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(defn ast
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  Convert a list of tokens into an \&amp;#34;abstract syntax tree\&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  which in our Forth is just a list of type/value pairs.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  [tokens]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  (for [t tokens
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        :let [op (get opmap t)]]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    (cond
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      ;; Integers (possibly negative)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      (re-matches #&amp;#34;^\-?\d+$&amp;#34; t)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      (node. :num (Integer. t))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      ;; Operations
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      op (node. :op op)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      :else (node. :invalid :invalid))))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
Running this on our example,&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(-&amp;gt;&amp;gt; example
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;     strip-comments
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;     tokenize
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;     ast
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;     (map str))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;;=&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(&amp;#34;[:num 2]&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &amp;#34;[:num 2]&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &amp;#34;[:op :add]&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &amp;#34;[:num 5]&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &amp;#34;[:op :mul]&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &amp;#34;[:num 2]&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &amp;#34;[:op :div]&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &amp;#34;[:num -1]&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &amp;#34;[:op :add]&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &amp;#34;[:num 8]&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &amp;#34;[:op :sub]&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &amp;#34;[:op :dot]&amp;#34;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
The remainder of &lt;code class=&#34;verbatim&#34;&gt;forth.bb&lt;/code&gt; essentially just implements the needed
operators, as well as the required stack and the reference to the &lt;code class=&#34;verbatim&#34;&gt;printf&lt;/code&gt;
C library function.  It is perhaps a bit lengthy to go through here in
its entirety, so I will share one example where Babashka helps:&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(defn def-arithmetic-op [nam op-fn]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  (def-fn :void nam []
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    (assign :sp (call :i32 :get_stack_cnt))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    (if-lt :i32 :sp 2
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;           (els)  ;; NOP - not enough on stack
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;           (els
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            (assign :value2
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                    (call :i32 :pop))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            (assign :value1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                    (call :i32 :pop))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            (assign :result (op-fn :i32 :value1 :value2))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            (call :void :push [:i32 :result])))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    (ret :void)))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
This makes LLVM IR which does the following, in pseudo-code:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;get current stack position; ensure at least two entries (else return)&lt;/li&gt;
&lt;li&gt;pop the operands off the stack&lt;/li&gt;
&lt;li&gt;apply the arithmetic operator to the operands&lt;/li&gt;
&lt;li&gt;put the result on the stack&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Implementing the four arithmetic operators is then as simple
as invoking&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; ...
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(def-arithmetic-op :mul mul)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(def-arithmetic-op :add add)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(def-arithmetic-op :sub sub)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(def-arithmetic-op :div div)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; ...&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
when generating the IR.&lt;/p&gt;
&lt;p&gt;
Aside from the general-purpose LLVM IR code (&lt;code class=&#34;verbatim&#34;&gt;llir.bb&lt;/code&gt;), the Forth
implementation is under two hundred lines.  It includes the invocation
to &lt;code class=&#34;verbatim&#34;&gt;clang&lt;/code&gt; to compile the temporary IR file to make the runnable
program.  Here&amp;#39;s an example compilation session:&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ cat example.fs
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;       \\ initial state          stack: []
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;3      \\ put 3 on stack.        stack: [3]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;99     \\ put 99 on stack.       stack: [3, 99]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;drop   \\ discard top item.      stack: [3]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;drop   \\ discard top item.      stack: []
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;2 2    \\ put 2 on stack, twice: stack: [2, 2]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;+      \\ 2 + 2 = 4.             stack: [4]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;5 *    \\ multiply 4 * 5.        stack: [20]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;2 /    \\ divide by 2.           stack: [10]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-1 +   \\ add -1                 stack: [9]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;8 -    \\ subtract 8 -&amp;gt; 1        stack: [1]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;.      \\ prints &amp;#39;1&amp;#39;             stack: [1]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;drop   \\ removes 1.             stack: []
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ ./forth.bb example.fs
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ ./example
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
The resulting program is fast, as expected…&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ time ./example
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;real	0m0.007s
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;user	0m0.002s
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sys	0m0.003s&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
… and small:&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ ls -l ./example
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-rwxr-xr-x  1 jacobsen  staff  8952 Aug 16 09:52 ./example&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
Let&amp;#39;s review what we&amp;#39;ve done: we have implemented a small subset of Forth,
writing a compiler front-end in Babashka/Clojure to translate source programs
into LLVM IR, and using &lt;code class=&#34;verbatim&#34;&gt;clang&lt;/code&gt; to turn the IR into compact binaries.  The
resulting programs are small and fast.&lt;/p&gt;
&lt;p&gt;
Sensible next steps would be to implement more of Forth&amp;#39;s stack
operators, and maybe start to implement the &lt;code class=&#34;verbatim&#34;&gt;:&lt;/code&gt; (colon) operator,
Forth&amp;#39;s mechanism for defining new symbols and functions.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&#34;outline-container-headline-6&#34; class=&#34;outline-2&#34;&gt;
&lt;h2 id=&#34;headline-6&#34;&gt;
Lisp
&lt;/h2&gt;
&lt;div id=&#34;outline-text-headline-6&#34; class=&#34;outline-text-2&#34;&gt;
&lt;p&gt;
Instead, let&amp;#39;s implement a different variant of our arithmetic
calculating language, using Lisp syntax (&lt;a href=&#34;https://en.wikipedia.org/wiki/S-expression&#34;&gt;S-expressions&lt;/a&gt;).  Consider our
first Forth example:&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;2 2 +
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;5 *
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;2 /
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-1 +
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;8 -
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
In Lisp, this looks like:&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ cat example.lisp
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(print (- (+ -1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;             (/ (* 5
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                   (+ 2 2))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                2))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;          8))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
Rather than coming last, as they did before (&amp;#34;postfix&amp;#34; notation), our
operators come first (&amp;#34;prefix&amp;#34; notation). The order of operations is
determined by parentheses, as opposed to using stack as we did for
our Forth implementation.&lt;/p&gt;
&lt;p&gt;
Here Babashka helps us tremendously because such parenthesized prefix
expressions are valid &lt;a href=&#34;https://github.com/edn-format/edn&#34;&gt;EDN&lt;/a&gt; data, which the Clojure function
&lt;code class=&#34;verbatim&#34;&gt;clojure.edn/read-string&lt;/code&gt; can parse for us. But we need to convert the
resulting nested list into the &amp;#34;SSA&amp;#34; (&lt;a href=&#34;https://en.wikipedia.org/wiki/Static_single-assignment_form&#34;&gt;single static assignment&lt;/a&gt;)
expressions LLVM understands. This is relatively straightforward with
a recursive function which expands leaves of the tree and stores the
results as intermediate values:&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(defn to-ssa [expr bindings]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  (if (not (coll? expr))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    expr
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    (let [[op &amp;amp; args] expr
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;          result (gensym &amp;#34;r&amp;#34;)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;          args (doall
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                (for [arg args]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                  (if-not (coll? arg)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                    arg
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                    (to-ssa arg bindings))))]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      (swap! bindings conj (concat [result op] args))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      result)))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(defn convert-to-ssa [expr]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  (let [bindings (atom [])]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    (to-ssa expr bindings)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    @bindings))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
We use &lt;code class=&#34;verbatim&#34;&gt;gensym&lt;/code&gt; here to get a unique variable name for each assignment,
and &lt;code class=&#34;verbatim&#34;&gt;doall&lt;/code&gt; to force the evaluation of the lazy for expansion of the
argument terms. The result:&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(-&amp;gt;&amp;gt; &amp;#34;example.lisp&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;     slurp
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;     (edn/read-string)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;     convert-to-ssa)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;;=&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;[(r623 + 2 2)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; (r622 * 5 r623)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; (r621 / r622 2)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; (r620 + -1 r621)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; (r619 - r620 8)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; (r618 print r619)]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
The next step will be to actually write out the corresponding LLVM
IR. The rest of &lt;code class=&#34;verbatim&#34;&gt;lisp.bb&lt;/code&gt; is satisfyingly compact.  Operators (we
have five, but more can easily be added), are just a map of symbols
to tiny bits of LLVM code:&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(def ops
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  {&amp;#39;* #(mul :i32 %1 %2)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   &amp;#39;+ #(add :i32 %1 %2)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   &amp;#39;/ #(div :i32 %1 %2)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   &amp;#39;- #(sub :i32 %1 %2)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   &amp;#39;print
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   #(call &amp;#34;i32 (i8*, ...)&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;          :printf
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;          [:i8* :as_ptr]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;          [:i32 (sigil %1)])})&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
Similar to our Forth implementation, but even more compact, the main Babashka function,
after a brief setup for &lt;code class=&#34;verbatim&#34;&gt;printf&lt;/code&gt;, generates a series of SSA instructions.&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(defn main [[path]]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  (when path
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    (let [assignments (-&amp;gt;&amp;gt; path
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                           slurp
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                           edn/read-string
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                           convert-to-ssa)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;          outfile (-&amp;gt;&amp;gt; path
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                       fs/file-name
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                       fs/split-ext
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                       first)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;          ir (module
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;              (external-fn :i32 :printf :i8*, :...)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;              (def-global-const-str :fmt_str &amp;#34;%d\n&amp;#34;)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;              (def-fn :i32 :main []
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                (assign :as_ptr
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                        (gep (fixedarray 4 :i8)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                             (star (fixedarray 4 :i8))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                             (sigil :fmt_str)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                             [:i64 0]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                             [:i64 0]))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                ;; Interpolate SSA instructions / operator invocations:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                (apply els
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                       (for [[reg op &amp;amp; args] assignments
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                             :let [op-fn (ops op)]]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                         (if-not op-fn
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                           (throw (ex-info &amp;#34;bad operator&amp;#34; {:op op}))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                           (assign reg (apply op-fn args)))))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                (ret :i32 0)))]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      (compile-to outfile ir))))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(main *command-line-args*)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
Putting these parts together (see &lt;a href=&#34;https://github.com/eigenhombre/llbb/blob/master/lisp.bb&#34;&gt;&lt;code class=&#34;verbatim&#34;&gt;lisp.bb&lt;/code&gt;&lt;/a&gt; on GitHub), we have:&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ ./lisp.bb example.lisp
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ ./example
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
It, too, is small and fast:&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ time ./example
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;real	0m0.006s
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;user	0m0.001s
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sys	0m0.003s
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ ls -al ./example
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-rwxr-xr-x  1 jacobsen  staff  33432 Aug 16 20:52 ./example&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
To say this is a &amp;#34;working Lisp compiler&amp;#34; at this point would be
grandiose (we still need functions, lists and other collection types,
eval, macros, …) but we have developed an excellent foundation
to build upon.&lt;/p&gt;
&lt;p&gt;
To summarize, the strategy we have taken is as follows:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Use a high level language (in our case, Babashka/Clojure) to parse
input and translate into LLVM IR;&lt;/li&gt;
&lt;li&gt;When needed, write and generate small C programs to understand the
equivalent IR to generate.&lt;/li&gt;
&lt;li&gt;Compile the IR to small, fast binaries using &lt;code class=&#34;verbatim&#34;&gt;clang&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&#34;outline-container-headline-7&#34; class=&#34;outline-2&#34;&gt;
&lt;h2 id=&#34;headline-7&#34;&gt;
Alternatives and Future Directions
&lt;/h2&gt;
&lt;div id=&#34;outline-text-headline-7&#34; class=&#34;outline-text-2&#34;&gt;
&lt;p&gt;
I should note that C itself has long been used as an intermediate
language, and we could have used it here instead of LLVM IR; I don&amp;#39;t
have a strong sense of the tradeoffs involved yet, but wanted to take
the opportunity to learn more about LLVM for this project.&lt;/p&gt;
&lt;p&gt;
LLVM is interesting to me because of the modularity of its toolchain;
it also provides a JIT compiler which allows one to build and execute
code at run-time.  We didn&amp;#39;t investigate tooling for that here (it
needs deeper LLVM language bindings than the homegrown Babashka code I
used), but it could provide a way to do run-time compilation similar
to what SBCL (a Common Lisp implementation which can compile functions
at run-time) does.&lt;/p&gt;
&lt;p&gt;
Here are some directions I&amp;#39;m considering going forward:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Try interfacing with external libraries, e.g. a &lt;a href=&#34;https://en.wikipedia.org/wiki/Arbitrary-precision_arithmetic&#34;&gt;bignum&lt;/a&gt; library;&lt;/li&gt;
&lt;li&gt;Implement more Forth functionality;&lt;/li&gt;
&lt;li&gt;Implement more Lisp, possibly including a significant subset of &lt;code class=&#34;verbatim&#34;&gt;l1&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;Try a JIT-based approach, possibly using Rust as the host language.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&#34;outline-container-headline-8&#34; class=&#34;outline-2&#34;&gt;
&lt;h2 id=&#34;headline-8&#34;&gt;
Conclusion
&lt;/h2&gt;
&lt;div id=&#34;outline-text-headline-8&#34; class=&#34;outline-text-2&#34;&gt;
&lt;p&gt;
Whenever possible, I want to make small, fast programs, and I like
playing with and creating small programming languages. LLVM provides a
fascinating set of tools and techniques for doing so, and using
Babashka to make small front-ends for IR generation turns out to be
surprisingly effective, at least for simple languages.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
</description>
    </item>
    
    <item>
      <title>Adding Tail Call Optimization to A Lisp Written in Go</title>
      <link>http://johnj.com/posts/tco/</link>
      <pubDate>Mon, 08 Aug 2022 00:00:00 +0000</pubDate>
      
      <guid>http://johnj.com/posts/tco/</guid>
      <description>
&lt;p&gt;





&lt;a href=&#34;http://johnj.com/swirl5.jpg&#34;&gt;&lt;img class=&#34;resize&#34; src=&#34;http://johnj.com/swirl5_hu_20fd4752b571d675.jpg&#34; style=&#34;width:300px; border:0px solid black;&#34;/&gt;&lt;/a&gt;

&lt;/p&gt;
&lt;p&gt;
The last few days have been devoted to improving &lt;a href=&#34;https://github.com/eigenhombre/l1/&#34;&gt;&lt;code class=&#34;verbatim&#34;&gt;l1&lt;/code&gt;&lt;/a&gt;, the homegrown lisp I
&lt;a href=&#34;http://johnj.com/posts/l1/&#34;&gt;wrote about&lt;/a&gt; earlier this year.  A number of changes have landed in the
last week:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Implemented &lt;a href=&#34;https://github.com/eigenhombre/l1/issues/36&#34;&gt;&lt;code class=&#34;verbatim&#34;&gt;let&lt;/code&gt;&lt;/a&gt;, &lt;a href=&#34;https://github.com/eigenhombre/l1/issues/42&#34;&gt;&lt;code class=&#34;verbatim&#34;&gt;defn&lt;/code&gt;&lt;/a&gt; and sugar for &lt;a href=&#34;https://github.com/eigenhombre/l1/issues/38&#34;&gt;quote&lt;/a&gt;;&lt;/li&gt;
&lt;li&gt;Figured out &lt;a href=&#34;https://github.com/eigenhombre/l1#emacs-integration&#34;&gt;basic REPL integration&lt;/a&gt; with Emacs;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/eigenhombre/l1/issues/27&#34;&gt;Added numeric comparison operators&lt;/a&gt;;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/eigenhombre/l1/issues/33&#34;&gt;Reviewed my Minimum Viable Repo&lt;/a&gt; checklist for this project;&lt;/li&gt;
&lt;li&gt;Fixed &lt;a href=&#34;https://github.com/eigenhombre/l1/issues?q=is%3Aissue+is%3Aclosed+sort%3Aupdated-desc+label%3Abug&#34;&gt;four bugs&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I also implemented the bulk of the automated tests &lt;a href=&#34;https://github.com/eigenhombre/l1/blob/master/tests.l1&#34;&gt;in the language
itself&lt;/a&gt;.  This was a decisive step forward in both ease of creating new
tests and confidence that the language was approaching something usable.&lt;/p&gt;
&lt;p&gt;
The work I&amp;#39;m happiest with, though, because it taught me the most, was implementing
&lt;a href=&#34;https://en.wikipedia.org/wiki/Tail_call&#34;&gt;tail call optimization&lt;/a&gt; (TCO) in the language, which the rest of this post will be about.&lt;/p&gt;
&lt;div id=&#34;outline-container-headline-1&#34; class=&#34;outline-2&#34;&gt;
&lt;h2 id=&#34;headline-1&#34;&gt;
Motivation
&lt;/h2&gt;
&lt;div id=&#34;outline-text-headline-1&#34; class=&#34;outline-text-2&#34;&gt;
&lt;p&gt;
The need for some form of TCO became clear as I started to write more small programs in &lt;code class=&#34;verbatim&#34;&gt;l1&lt;/code&gt;.
Perhaps the simplest example is one that sums all the natural numbers up to $n$:&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(defn sum-to-acc (n acc)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  (cond ((zero? n) acc)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        (t (sum-to-acc (- n 1) (+ n acc)))))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(defn sum-to (n)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  (sum-to-acc n 0))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
Calling &lt;code class=&#34;verbatim&#34;&gt;sum-to&lt;/code&gt; for small $n$ worked fine:&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(sum-to 100)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;;=&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;5050&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
However, larger $n$ blew up spectacularly:&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(sum-to (* 1000 1000))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;;=&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;runtime: goroutine stack exceeds 1000000000-byte limit
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;runtime: sp=0x14020500360 stack=[0x14020500000, 0x14040500000]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;fatal error: stack overflow
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;runtime stack:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;runtime.throw({0x10289aa2b?, 0x10294ddc0?})
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	/opt/homebrew/Cellar/go/1.18.3/libexec/src/runtime/panic.go:992 +0x50
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;runtime.newstack()
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	/opt/homebrew/Cellar/go/1.18.3/libexec/src/runtime/stack.go:1101 +0x46c
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;runtime.morestack()
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	/opt/homebrew/Cellar/go/1.18.3/libexec/src/runtime/asm_arm64.s:314 +0x70
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;goroutine 1 [running]:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;strings.(*Reader).ReadByte(0x1401c2820e0?)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	/opt/homebrew/Cellar/go/1.18.3/libexec/src/strings/reader.go:66 +0x98 fp=0x14020500360 sp=0x14020500360 pc=0x102883348
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;math/big.nat.scan({0x0, 0x1401c2820e0?, 0x0}, {0x1028dc7c8, 0x1401c2820e0}, 0xa, 0x0)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	/opt/homebrew/Cellar/go/1.18.3/libexec/src/math/big/natconv.go:126 +0x80 fp=0x14020500430 sp=0x14020500360 pc=0x10288b1e0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; ...&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
This happens, of course, because &lt;code class=&#34;verbatim&#34;&gt;sum-to-acc&lt;/code&gt; calls itself a million times,
each time storing a copy of its local bindings on the stack, which
eventually consumes all the space on the stack.&lt;/p&gt;
&lt;p&gt;
Getting simple recursive functions like this to work for large $n$ is
especially important because &lt;code class=&#34;verbatim&#34;&gt;l1&lt;/code&gt; doesn&amp;#39;t have loops (yet)!&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&#34;outline-container-headline-2&#34; class=&#34;outline-2&#34;&gt;
&lt;h2 id=&#34;headline-2&#34;&gt;
The Optimization
&lt;/h2&gt;
&lt;div id=&#34;outline-text-headline-2&#34; class=&#34;outline-text-2&#34;&gt;
&lt;p&gt;
The solution is hinted at already in my test case.  Note that I did
not write &lt;code class=&#34;verbatim&#34;&gt;sum-to&lt;/code&gt; as a single recursive function, as follows:&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(defn sum-to-notail (n)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  (cond ((zero? n) 0)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        (t (+ n (sum-to-notail (- n 1))))))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
While this function looks slightly simpler, it is harder for a
compiler or interpreter to optimize.  The difference is that, whereas
&lt;code class=&#34;verbatim&#34;&gt;sum-to-notail&lt;/code&gt; does some work after calling itself (by adding &lt;code class=&#34;verbatim&#34;&gt;n&lt;/code&gt; to
the result), &lt;code class=&#34;verbatim&#34;&gt;sum-to-acc&lt;/code&gt; calls itself from the &lt;em&gt;tail position&lt;/em&gt;; that is,
the function &lt;em&gt;returns immediately after calling itself&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;
People have &lt;a href=&#34;https://dspace.mit.edu/handle/1721.1/5753&#34;&gt;long realized&lt;/a&gt; that function calls from the tail position
can be replaced by updating the return address and then jumping
directly to the the new function without adding new information to the
stack.  This is something I had heard about for years and used in
various &amp;#34;functional&amp;#34; languages, without ever really implementing
myself (and therefore fully understanding).  It&amp;#39;s an easy thing to take for
granted without knowing anything about how it&amp;#39;s actually implemented
under the hood.  The failure of &lt;code class=&#34;verbatim&#34;&gt;sum-to-acc&lt;/code&gt; and similar recursive
functions, described above, meant I would have to learn.&lt;/p&gt;
&lt;p&gt;
Two very different blog posts were helpful to me in pointing the way
forward: &lt;a href=&#34;https://www.geoffreylitt.com/2018/01/15/adding-tail-calls-optimization-to-a-lisp-interpreter.html&#34;&gt;Adding tail call optimization to a Lisp interpreter in Ruby&lt;/a&gt;,
and &lt;a href=&#34;https://eklitzke.org/how-tail-call-optimization-works&#34;&gt;How Tail Call Optimization Works&lt;/a&gt;.  The posts focus on very
different languages (Ruby vs. C / assembler), but they each revolve
around what are effectively &lt;code class=&#34;verbatim&#34;&gt;GOTO&lt;/code&gt; statements.  I&amp;#39;m old enough to
remember BASIC and the pernicious &lt;code class=&#34;verbatim&#34;&gt;GOTO&lt;/code&gt; statement leading to
&amp;#34;spaghetti code.&amp;#34;  I doubt I&amp;#39;ve ever used a &lt;code class=&#34;verbatim&#34;&gt;GOTO&lt;/code&gt; statement in
production code, whose use in modern programming languages fell out of
favor in the aftermath of Dijkstra&amp;#39;s famous &lt;a href=&#34;https://homepages.cwi.nl/~storm/teaching/reader/Dijkstra68.pdf&#34;&gt;Go To Statement Considered
Harmful&lt;/a&gt; paper.  But the ability to transfer control to another part of
your program without invoking a function call is key to the
optimization.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&#34;outline-container-headline-3&#34; class=&#34;outline-2&#34;&gt;
&lt;h2 id=&#34;headline-3&#34;&gt;
The Approach
&lt;/h2&gt;
&lt;div id=&#34;outline-text-headline-3&#34; class=&#34;outline-text-2&#34;&gt;
&lt;p&gt;
Since the strategy is general, let&amp;#39;s lose all the parentheses for a
moment and rewrite &lt;code class=&#34;verbatim&#34;&gt;sum-to-acc&lt;/code&gt; in language-agnostic pseudo-code:&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;function sum-to-acc(n sum)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   if n == 0, then return sum
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   return sum-to-acc(n - 1, n + sum)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
In most languages (without TCO), when this function is called, the
values of &lt;code class=&#34;verbatim&#34;&gt;n&lt;/code&gt; and &lt;code class=&#34;verbatim&#34;&gt;sum&lt;/code&gt;, as well as the return address, will be put on
the stack, whose evolution looks something like the following.&lt;sup class=&#34;footnote-reference&#34;&gt;&lt;a id=&#34;footnote-reference-1&#34; href=&#34;#footnote-1&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;:&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; first invocation: [n=5, sum=0,  ret=sum-to:...]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;second invocation: [n=4, sum=5,  ret=sum-to-acc:...]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                   [n=5, sum=0,  ret=sum-to:...]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; third invocation: [n=3, sum=9,  ret=sum-to-acc:...]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                   [n=4, sum=5,  ret=sum-to-acc:...]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                   [n=5, sum=0,  ret=sum-to:...]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;fourth invocation: [n=2, sum=12, ret=sum-to-acc:...]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                   [n=3, sum=9,  ret=sum-to-acc:...]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                   [n=4, sum=5,  ret=sum-to-acc:...]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                   [n=5, sum=0,  ret=sum-to:...]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; fifth invocation: [n=1, sum=14, ret=sum-to-acc:...]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                   [n=2, sum=12, ret=sum-to-acc:...]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                   [n=3, sum=9,  ret=sum-to-acc:...]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                   [n=4, sum=5,  ret=sum-to-acc:...]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                   [n=5, sum=0,  ret=sum-to:...]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; sixth invocation: [n=0, sum=15, ret=sum-to-acc:...]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                   [n=1, sum=14, ret=sum-to-acc:...]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                   [n=2, sum=12, ret=sum-to-acc:...]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                   [n=3, sum=9,  ret=sum-to-acc:...]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                   [n=4, sum=5,  ret=sum-to-acc:...]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                   [n=5, sum=0,  ret=sum-to:...]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
At the sixth invocation, our terminating condition is reached, and 15
is returned, with all the pending stack frames popped off the stack.&lt;/p&gt;
&lt;p&gt;
With TCO, the implementation looks more like the following:&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;function sum-to-acc(n sum)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;TOP:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   if n == 0, then return sum
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   n = n - 1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   sum = sum + n
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   GOTO TOP&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
as a result, the evolution of the stack looks as follows:&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; first invocation: [n=5, sum=0, ret=sum-to:...]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;second invocation: [n=4, sum=5, ret=sum-to:...]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; third invocation: [n=3, sum=9, ret=sum-to:...]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;fourth invocation: [n=2, sum=12, ret=sum-to:...]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; fifth invocation: [n=1, sum=14, ret=sum-to:...]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; sixth invocation: [n=0, sum=15, ret=sum-to:...]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
All those extra stack frames are gone: recursion has turned into a form of iteration.&lt;/p&gt;
&lt;p&gt;
Implementing TCO, then, has two ingredients:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Replace the values of the current arguments with their new values directly.&lt;/li&gt;
&lt;li&gt;Jump straight to the next call of the function without adding to the stack;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This low-level, imperative optimization makes high-level,
functional, recursive implementations efficient.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&#34;outline-container-headline-4&#34; class=&#34;outline-2&#34;&gt;
&lt;h2 id=&#34;headline-4&#34;&gt;
Implementation
&lt;/h2&gt;
&lt;div id=&#34;outline-text-headline-4&#34; class=&#34;outline-text-2&#34;&gt;
&lt;p&gt;
In thinking about the implementation for &lt;code class=&#34;verbatim&#34;&gt;l1&lt;/code&gt;, I was pleased to learn
that Go actually has a &lt;code class=&#34;verbatim&#34;&gt;goto&lt;/code&gt; statement.  However, my implementation
was poorly set up to use it.&lt;/p&gt;
&lt;p&gt;
Early in the implementation of &lt;code class=&#34;verbatim&#34;&gt;l1&lt;/code&gt;, I noticed that each data type
(numbers, atoms, and lists) had its own evaluation rules, so it made
sense to make use of Go&amp;#39;s features supporting polymorphism, namely
interfaces and receivers.  I had a &lt;code class=&#34;verbatim&#34;&gt;Sexpr&lt;/code&gt; interface which looked like the following:&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;type Sexpr interface {
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	String() string
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	Eval(*env) (Sexpr, error)  // &amp;lt;--------
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	Equal(Sexpr) bool
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
Numbers and atoms, for example, had fairly simple &lt;code class=&#34;verbatim&#34;&gt;Eval&lt;/code&gt;
implementations.  For example,&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;func (a Atom) Eval(e *env) (Sexpr, error) {
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	if a.s == &amp;#34;t&amp;#34; {
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		return a, nil
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	ret, ok := e.Lookup(a.s)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	if ok {
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		return ret, nil
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	ret, ok = builtins[a.s]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	if ok {
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		return ret, nil
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	return nil, fmt.Errorf(&amp;#34;unknown symbol: %s&amp;#34;, a.s)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
And, of course, numbers eval to themselves:&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;func (n Number) Eval(e *env) (Sexpr, error) {
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	return n, nil
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
Lists, as you would expect, were more complicated – evaluating a list
expression needs to handle special forms&lt;sup class=&#34;footnote-reference&#34;&gt;&lt;a id=&#34;footnote-reference-2&#34; href=&#34;#footnote-2&#34;&gt;2&lt;/a&gt;&lt;/sup&gt;,
user-defined functions, and built-in functions.  Following the classic
&lt;a href=&#34;https://en.wikipedia.org/wiki/Structure_and_Interpretation_of_Computer_Programs&#34;&gt;Structure and Interpretation of Computer Programs&lt;/a&gt;, I separated the
core logic for function application into separate &lt;code class=&#34;verbatim&#34;&gt;Eval&lt;/code&gt; and &lt;code class=&#34;verbatim&#34;&gt;Apply&lt;/code&gt;
phases.  And to prevent the &lt;code class=&#34;verbatim&#34;&gt;Eval&lt;/code&gt; for lists from getting too large, I
broke out the evaluation rules for different cases (e.g. for &lt;code class=&#34;verbatim&#34;&gt;let&lt;/code&gt; and
&lt;code class=&#34;verbatim&#34;&gt;cond&lt;/code&gt; special forms and for function application) into their own
functions.&lt;/p&gt;
&lt;p&gt;
In other words, I had evaluation logic spread over ten functions in
five files.  Sadly, the need to jump back to the beginning of an
evaluation rather than recursively calling &lt;code class=&#34;verbatim&#34;&gt;Eval&lt;/code&gt; again meant that
several of those nicely broken out functions had to be brought
together into a single function, because &lt;code class=&#34;verbatim&#34;&gt;goto&lt;/code&gt; &lt;a href=&#34;https://go.dev/ref/spec#Goto_statements&#34;&gt;does not support
jumping from one function to another&lt;/a&gt;.  (C has &lt;code class=&#34;verbatim&#34;&gt;setjmp&lt;/code&gt; and &lt;code class=&#34;verbatim&#34;&gt;longjmp&lt;/code&gt;,
which effectively do this, but I would want to upgrade my IQ by a
few points before applying them in this situation.)&lt;/p&gt;
&lt;p&gt;
There were actually three cases where I was performing an evaluation
step right before returning, and the &lt;code class=&#34;verbatim&#34;&gt;goto&lt;/code&gt; pattern could be used:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;When evaluating code in the tail position of a user-defined function;&lt;/li&gt;
&lt;li&gt;When evaluating code in the last expression in a &lt;code class=&#34;verbatim&#34;&gt;let&lt;/code&gt; block;&lt;/li&gt;
&lt;li&gt;When evaluating code in the chosen branch of a &lt;code class=&#34;verbatim&#34;&gt;cond&lt;/code&gt; clause.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I wound up with code which with looks like the following.  Several
steps are indicated only with comments.  Note the tiny, easy-to-miss
&lt;strong&gt;&lt;code class=&#34;verbatim&#34;&gt;top:&lt;/code&gt;&lt;/strong&gt; label at the very beginning:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;// lisp.go
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;//
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;func eval(expr Sexpr, e *env) (Sexpr, error) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;strong&gt;top:&lt;/strong&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	switch t := expr.(type) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	case Atom:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		return evAtom(t, e)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	case Number:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		return expr, nil
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	// ...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	case *ConsCell:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		if t == Nil {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			return Nil, nil
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		// special forms:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		if carAtom, ok := t.car.(Atom); ok {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			switch {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			case carAtom.s == &amp;#34;quote&amp;#34;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;				return t.cdr.(*ConsCell).car, nil
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			case carAtom.s == &amp;#34;cond&amp;#34;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;				pairList := t.cdr.(*ConsCell)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;				if pairList == Nil {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;					return Nil, nil
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;				}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;				for {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;					if pairList == Nil {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;						return Nil, nil
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;					}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;					pair := pairList.car.(*ConsCell)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;					ev, err := eval(pair.car, e)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;					if err != nil {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;						return nil, err
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;					}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;					if ev == Nil {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;						pairList = pairList.cdr.(*ConsCell)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;						continue
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;					}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;					expr = pair.cdr.(*ConsCell).car
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;					&lt;strong&gt;goto top&lt;/strong&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;				}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			// ...&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
The code so far shows the evaluation for atoms, numbers, and &lt;code class=&#34;verbatim&#34;&gt;cond&lt;/code&gt;
statements.  &lt;code class=&#34;verbatim&#34;&gt;cond&lt;/code&gt; does not introduce any new bindings, but when the
first truthy condition is encountered, it evaluates the next argument
as its final act.  So the code above simply replaces the expression to
be evaluated, &lt;code class=&#34;verbatim&#34;&gt;expr&lt;/code&gt;, with the expression from the matching clause,
and then restarts the evaluation via &lt;code class=&#34;verbatim&#34;&gt;goto&lt;/code&gt;, without the overhead of a
separate function call.&lt;/p&gt;
&lt;p&gt;
The code for &lt;code class=&#34;verbatim&#34;&gt;let&lt;/code&gt; is somewhat similar:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			case carAtom.s == &amp;#34;let&amp;#34;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;				args := t.cdr.(*ConsCell)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;				if args == Nil {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;					return nil, fmt.Errorf(&amp;#34;let requires a binding list&amp;#34;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;				}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;				// ... code to set up let bindings ...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;				body := args.cdr.(*ConsCell)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;				var ret Sexpr = Nil
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;				for {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;					var err error
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;					if body == Nil {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;						return ret, nil
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;					}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;					// Implement TCO for `let`:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;					if body.cdr == Nil {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;						expr = body.car
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;						e = &amp;amp;newEnv
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;						&lt;strong&gt;goto top&lt;/strong&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;					}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;					ret, err = eval(body.car, &amp;amp;newEnv)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;					if err != nil {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;						return nil, err
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;					}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;					body = body.cdr.(*ConsCell)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;				}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;
The &lt;code class=&#34;verbatim&#34;&gt;for&lt;/code&gt; loop invokes a new &lt;code class=&#34;verbatim&#34;&gt;eval&lt;/code&gt; for each expression in the body of
the &lt;code class=&#34;verbatim&#34;&gt;let&lt;/code&gt;, &lt;em&gt;except&lt;/em&gt; for the last one: when the last expression is
reached, (the &lt;code class=&#34;verbatim&#34;&gt;cdr&lt;/code&gt; is &lt;code class=&#34;verbatim&#34;&gt;Nil&lt;/code&gt;), the last &lt;code class=&#34;verbatim&#34;&gt;eval&lt;/code&gt; is done by jumping to
the beginning of the function, once it has updated its environment to
point to include the new bindings.&lt;/p&gt;
&lt;p&gt;
The last use of this pattern is in function invocation proper, which looks similar:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			// (... code to set up new environment based on passed arguments ...)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			var ret Sexpr = Nil
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			for {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;				if lambda.body == Nil {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;					return ret, nil
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;				}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;				// TCO:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;				if lambda.body.cdr == Nil {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;					expr = lambda.body.car
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;					e = &amp;amp;newEnv
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;					&lt;strong&gt;goto top&lt;/strong&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;				}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;				ret, err = eval(lambda.body.car, &amp;amp;newEnv)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;				if err != nil {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;					return nil, err
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;				}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;				lambda.body = lambda.body.cdr.(*ConsCell)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;
I&amp;#39;ve skipped various parts of &lt;code class=&#34;verbatim&#34;&gt;eval&lt;/code&gt; that aren&amp;#39;t relevant for TCO
optimization – if you&amp;#39;re interested, you can &lt;a href=&#34;https://github.com/eigenhombre/l1/blob/5873705ab1badb16dd1f1586bb7cc13467287187/lisp.go#L126&#34;&gt;check out the code&lt;/a&gt;
yourself.&lt;/p&gt;
&lt;p&gt;
To be clear, what we are optimizing is all tail calls, not just
recursive ones – though the recursive ones were the primary objective
due to the stack overflows reported above.&lt;/p&gt;
&lt;p&gt;
The end result is that &lt;code class=&#34;verbatim&#34;&gt;sum-to&lt;/code&gt; now can complete for large values of
$n$:&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(sum-to (* 1000 1000))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;;=&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;500000500000&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
Incidentally, a variant of our test case failed before I added the TCO
optimization to &lt;code class=&#34;verbatim&#34;&gt;let&lt;/code&gt; shown above; this now works, as well:&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(defn sum-to-acc-with-let (n acc)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  (let ((_ 1))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    (cond ((zero? n) acc)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;          (t (sum-to-acc-with-let (- n 1) (+ n acc))))))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(defn sum-to-with-let (n) (sum-to-acc-with-let n 0))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(sum-to-with-let (* 1000 1000))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;;=&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;500000500000&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&#34;outline-container-headline-5&#34; class=&#34;outline-2&#34;&gt;
&lt;h2 id=&#34;headline-5&#34;&gt;
Conclusion
&lt;/h2&gt;
&lt;div id=&#34;outline-text-headline-5&#34; class=&#34;outline-text-2&#34;&gt;
&lt;p&gt;
Getting tail-call optimization to work was very satisfying… though
the &lt;code class=&#34;verbatim&#34;&gt;eval&lt;/code&gt; implementation is certainly more complex than before.  (Ah,
optimization!)&lt;/p&gt;
&lt;p&gt;
To ensure TCO continues to work, variants of &lt;code class=&#34;verbatim&#34;&gt;sum-to&lt;/code&gt; with and without &lt;code class=&#34;verbatim&#34;&gt;let&lt;/code&gt; are &lt;a href=&#34;https://github.com/eigenhombre/l1/blob/5873705ab1badb16dd1f1586bb7cc13467287187/Makefile#L17&#34;&gt;run
on every build&lt;/a&gt;, along with a few other short example programs.&lt;/p&gt;
&lt;p&gt;
After implementing TCO in my own code, I can appreciate and understand
the optimization better when I see it in the wild.  I fully expect to
use the pattern again when implementing future lisps (yes, I hope there
will be more).&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;footnotes&#34;&gt;
&lt;hr class=&#34;footnotes-separatator&#34;&gt;
&lt;div class=&#34;footnote-definitions&#34;&gt;
&lt;div class=&#34;footnote-definition&#34;&gt;
&lt;sup id=&#34;footnote-1&#34;&gt;&lt;a href=&#34;#footnote-reference-1&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;
&lt;div class=&#34;footnote-body&#34;&gt;
&lt;p&gt;Note that this is a somewhat abstract representation: the details are language-specific.  The &lt;code class=&#34;verbatim&#34;&gt;ret=sum-to:...&lt;/code&gt; notation means that when the function returns, control will pass back to where it left off inside the &lt;code class=&#34;verbatim&#34;&gt;sum-to&lt;/code&gt; function.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;footnote-definition&#34;&gt;
&lt;sup id=&#34;footnote-2&#34;&gt;&lt;a href=&#34;#footnote-reference-2&#34;&gt;2&lt;/a&gt;&lt;/sup&gt;
&lt;div class=&#34;footnote-body&#34;&gt;
&lt;p&gt;A special form is one that does not follow the normal evaluation rule for functions – it may evaluate its arguments once, many times, or not at all.  (I am glossing over macros for the time being; &lt;code class=&#34;verbatim&#34;&gt;l1&lt;/code&gt; does not have them yet.)&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
</description>
    </item>
    
    <item>
      <title>Tests by Example in Clojure and Common Lisp</title>
      <link>http://johnj.com/posts/tests-by-example/</link>
      <pubDate>Wed, 13 Jul 2022 00:00:00 +0000</pubDate>
      
      <guid>http://johnj.com/posts/tests-by-example/</guid>
      <description>&lt;figure&gt;





&lt;a href=&#34;http://johnj.com/cosb-crab-88.png&#34;&gt;&lt;img class=&#34;resize&#34; src=&#34;http://johnj.com/cosb-crab-88_hu_21d61e4557aed826.png&#34; style=&#34;width:400px; border:0px solid black;&#34;/&gt;&lt;/a&gt;


&lt;figcaption&gt;
Histogram made by a 1980&amp;#39;s version of the author.
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;
While playing around with some dice-rolling simulations recently in
Common Lisp (a topic for some future post, perhaps), I looked around
for a way of making histograms.  Finding none close to hand (it being
Common Lisp), it wasn&amp;#39;t too hard to &lt;a href=&#34;https://github.com/eigenhombre/hbook&#34;&gt;&amp;#34;roll my own&amp;#34; library&lt;/a&gt; (it
being… Common Lisp) to create text-based histograms in the tradition
of &lt;a href=&#34;https://cds.cern.ch/record/307945/files/&#34;&gt;libraries from CERN&lt;/a&gt; that I used as a fledgling physicist in the
late 1980s.&lt;/p&gt;
&lt;p&gt;
Since the project was just for fun, I drove most of the code forward
just by REPLing.  But I am trying to follow the same habits in my &amp;#34;for
fun&amp;#34; GitHub repositories as I would for paid work.  This means, among
other things, unit tests (in fact, for critical work I still prefer to
use &lt;a href=&#34;https://en.wikipedia.org/wiki/Test-driven_development&#34;&gt;TDD&lt;/a&gt; when I can).&lt;/p&gt;
&lt;p&gt;
So, in fleshing the tests out after the fact, I found myself
writing somewhat repetitive code that looked like this:&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(test hist-values-test
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  (let ((h (histogram &amp;#39;(1 2) 2)))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    (is (= 2 (hist-count h)))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    (is (= 1 (hist-min h)))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    (is (= 2 (hist-max h)))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    (is (equalp #(1 1) (hist-bin-heights h)))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    (is (equalp #(1 2) (hist-bin-xs h))))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  (let ((h (histogram &amp;#39;(1 2 1) 2)))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    (is (= 2 (hist-count h)))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    (is (= 1 (hist-min h)))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    (is (= 2 (hist-max h)))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    (is (equalp #(2 1) (hist-bin-heights h)))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    (is (equalp #(1 2) (hist-bin-xs h))))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  (let ((h (histogram &amp;#39;(1 2 2 3) 3)))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    (is (= 3 (hist-count h)))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    (is (= 1 (hist-min h)))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    (is (= 3 (hist-max h)))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    (is (equalp #(1 2 1) (hist-bin-heights h)))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    (is (equalp #(1 2 3) (hist-bin-xs h)))))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
This is using the minimalist &lt;a href=&#34;https://github.com/lmj/1am&#34;&gt;1AM&lt;/a&gt; testing library, which I like for its
simplicity.  It is also similar to the standard &lt;a href=&#34;https://clojure.github.io/clojure/clojure.test-api.html&#34;&gt;&lt;code class=&#34;verbatim&#34;&gt;clojure.test&lt;/code&gt;&lt;/a&gt; library
I&amp;#39;m used to in Clojure.  It lacks, however, one important feature of
&lt;code class=&#34;verbatim&#34;&gt;clojure.test&lt;/code&gt;, namely the &lt;code class=&#34;verbatim&#34;&gt;are&lt;/code&gt; macro.  The macro allows one to
represent tests as a table of examples:&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; Clojure code:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(deftest example
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  (are
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    [nums       prod]         ;; [1]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    (= prod (reduce * nums))  ;; [2]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    []          1             ;; [3]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    [1]         1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    [0]         0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    [0 1]       0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    [1 1]       1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    [2 2]       4
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    [2 3]       6
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    [-1 -1]     1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    [2 2 2]     8
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    [1000 1000] 1000000))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
An invocation of &lt;code class=&#34;verbatim&#34;&gt;are&lt;/code&gt; has three parts: a vector of symbols to be
bound to values from the examples to follow [1]; the expression to be
evaluated for each example [2]; and the actual examples [3], with one
example per line being the usual, but optional, convention.  (In the
code above I have added extra spaces to make clear that &lt;code class=&#34;verbatim&#34;&gt;nums&lt;/code&gt; goes
with the first column of data, and &lt;code class=&#34;verbatim&#34;&gt;prod&lt;/code&gt; goes with the second
column.)&lt;/p&gt;
&lt;p&gt;
If at first you didn&amp;#39;t understand that code being tested ([2]) was
related to multiplication, you&amp;#39;d probably be able to figure it out
just by looking at the examples.  This is the primary advantage of
&lt;code class=&#34;verbatim&#34;&gt;are&lt;/code&gt;, namely that examples often provide as good or better
documentation than a written description of functionality does.&lt;/p&gt;
&lt;p&gt;
Missing such a compact testing idiom for my unit tests, I found myself
wondering how hard it would be to port it to Common Lisp.  The answer,
as you might expect, was: Not that hard.  As is often the case, there
is &lt;a href=&#34;https://github.com/clojure/clojure/blob/master/src/clj/clojure/test.clj#L572&#34;&gt;not much actual Clojure code&lt;/a&gt; behind the function in question, and
the corresponding Common Lisp code is similarly compact, as we shall
see.&lt;/p&gt;
&lt;p&gt;
If you look at the actual function definition in &lt;code class=&#34;verbatim&#34;&gt;clojure.test&lt;/code&gt;, most
of the macro proper is error checking; the actual work is delegated to
a completely different namespace, &lt;code class=&#34;verbatim&#34;&gt;clojure.template&lt;/code&gt; (in what follows, I
will ignore the error checking):&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; Clojure code:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(defmacro are [argv expr &amp;amp; args]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  ;; ... error checking
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  `(clojure.template/do-template ~argv (is ~expr) ~@args)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  ;; ... error checking
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
A few macro expansions shows what&amp;#39;s happening:&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; Clojure code:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(macroexpand-1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &amp;#39;(are [nums prod]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    (= prod (reduce * nums))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    []      1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    [1]     1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    [2 2 2] 8))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;gives&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(clojure.template/do-template
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; [nums prod]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; (clojure.test/is (= prod (reduce * nums)))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; []      1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; [1]     1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; [2 2 2] 8)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
&lt;code class=&#34;verbatim&#34;&gt;do-template&lt;/code&gt; is also a macro.  Simply running &lt;code class=&#34;verbatim&#34;&gt;macroexpand-1&lt;/code&gt; again shows
what it does:&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; Clojure code:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(macroexpand-1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &amp;#39;(clojure.template/do-template
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   [nums prod]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   (clojure.test/is (= prod (reduce * nums)))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   []      1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   [1]     1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   [2 2 2] 8))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;gives&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(do (clojure.test/is (= 1 (reduce * [])))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    (clojure.test/is (= 1 (reduce * [1])))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    (clojure.test/is (= 8 (reduce * [2 2 2]))))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
The expanded code is exactly equivalent to what you would write if you
didn&amp;#39;t have the &lt;code class=&#34;verbatim&#34;&gt;are&lt;/code&gt; macro.  This is accomplished by simply repeating
the code being invoked, but substituting the actual example values for
&lt;code class=&#34;verbatim&#34;&gt;nums&lt;/code&gt; and &lt;code class=&#34;verbatim&#34;&gt;prod&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;
In order to do accomplish the same in Common Lisp, we take a bottom-up approach.
First, we need to split our test cases into groups corresponding to
the number of columns in our &lt;code class=&#34;verbatim&#34;&gt;argv&lt;/code&gt; vector (in this case, 2):&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(let ((cases &amp;#39;(#()      1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;               #(1)     1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;               #(2 2 2) 8)))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  (partition-n 2 2 cases))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;;=&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&amp;#39;((#()      1)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  (#(1)     1)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  (#(2 2 2) 8))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
The output looks very similar to &lt;code class=&#34;verbatim&#34;&gt;cases&lt;/code&gt;, but each pair has been
grouped into its own list.  Here I use &lt;code class=&#34;verbatim&#34;&gt;partition-n&lt;/code&gt; from &lt;a href=&#34;https://github.com/eigenhombre/cl-oju&#34;&gt;&lt;code class=&#34;verbatim&#34;&gt;cl-oju&lt;/code&gt;&lt;/a&gt;, a
Common Lisp library I wrote specifically to take advantage of sequence
idioms from the Clojure core library; &lt;code class=&#34;verbatim&#34;&gt;partition-n&lt;/code&gt; is a translation
of Clojure&amp;#39;s &lt;code class=&#34;verbatim&#34;&gt;partition&lt;/code&gt; function.  (&lt;a href=&#34;https://github.com/clojure/clojure/blob/master/src/clj/clojure/template.clj#L55&#34;&gt;The equivalent code&lt;/a&gt; in
&lt;code class=&#34;verbatim&#34;&gt;clojure.template&lt;/code&gt; also uses &lt;code class=&#34;verbatim&#34;&gt;partition&lt;/code&gt; for the same purpose.)&lt;/p&gt;
&lt;p&gt;
We now need to flesh out those cases by making use of each example in
the expression being tested, whose Common Lisp translation is&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(is (= prod (reduce #&amp;#39;* nums)))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
For example, if &lt;code class=&#34;verbatim&#34;&gt;nums&lt;/code&gt; is &lt;code class=&#34;verbatim&#34;&gt;#(2 2 2)&lt;/code&gt;, then &lt;code class=&#34;verbatim&#34;&gt;prod&lt;/code&gt; should be &lt;code class=&#34;verbatim&#34;&gt;8&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;
In other words, we want our test cases to be:&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(is (= 1 (reduce #&amp;#39;* #())))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(is (= 1 (reduce #&amp;#39;* #(1))))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(is (= 8 (reduce #&amp;#39;* #(2 2 2)))))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
The replacement of symbols with their actual values in the Clojure
code &lt;a href=&#34;eww:&#34;&gt;is accomplished&lt;/a&gt; with a tree-walking function called
&lt;code class=&#34;verbatim&#34;&gt;postwalk-replace&lt;/code&gt;.  We can do it in Common Lisp with the &lt;code class=&#34;verbatim&#34;&gt;subst&lt;/code&gt;
function, which works on linear or nested lists:&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(subst 3 &amp;#39;b &amp;#39;(* (+ b b) (/ b (- b b))))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;;=&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&amp;#39;(* (+ 3 3) (/ 3 (- 3 3)))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
But because we have multiple bindings or example arguments we have to
convert, we need to do it repeatedly:&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(defun apply-bindings (bindings case expr)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  (loop with ret = expr
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        for b in bindings
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        for c in case
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        do (setf ret (subst c b ret))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        finally (return ret)))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(apply-bindings &amp;#39;(x y) &amp;#39;(2 3) &amp;#39;(+ x y))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;;=&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&amp;#39;(+ 2 3)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
Now we have everything we need to expand our test cases:&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(let ((argv &amp;#39;(nums prod))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      (expr &amp;#39;(is (= prod (reduce #&amp;#39;* nums))))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      (c (length argv))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      (cases &amp;#39;(#()      1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;               #(1)     1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;               #(2 2 2) 8)))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  (loop for case in (partition-n c c cases)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        collect (apply-bindings argv case expr)))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;;=&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&amp;#39;((IS (= 1 (REDUCE #&amp;#39;* #())))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  (IS (= 1 (REDUCE #&amp;#39;* #(1))))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  (IS (= 8 (REDUCE #&amp;#39;* #(2 2 2)))))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
All the macro has to do is wrap this in a &lt;code class=&#34;verbatim&#34;&gt;progn&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(defmacro are (argv expr &amp;amp;rest cases)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  Analog of clojure.test/are.  Apply multiple assertions
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  based on some set up code and variations of one or more
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  variable bindings.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  (let ((c (length argv)))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    `(progn ,@(loop for case in (partition-n c c cases)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                    collect (apply-bindings argv case expr)))))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
giving, for our example:&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(macroexpand-1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &amp;#39;(are (nums prod)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   (is (= prod (reduce #&amp;#39;* nums)))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   #()      1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   #(1)     1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   #(2 2 2) 8))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;;=&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&amp;#39;(PROGN
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  (IS (= 1 (REDUCE #&amp;#39;* #())))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  (IS (= 1 (REDUCE #&amp;#39;* #(1))))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  (IS (= 8 (REDUCE #&amp;#39;* #(2 2 2)))))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
This is equivalent to the macroexpansion of Clojure&amp;#39;s &lt;code class=&#34;verbatim&#34;&gt;are&lt;/code&gt; that we
saw above.  I leave as an exercise for the reader a further
exploration of &lt;code class=&#34;verbatim&#34;&gt;clojure.template/apply-template&lt;/code&gt; and its use in the
&lt;code class=&#34;verbatim&#34;&gt;do-template&lt;/code&gt; macro; and the addition of error checking such as making
sure the number example values is a multiple of the number of binding
arguments.&lt;/p&gt;
&lt;p&gt;
One rough edge that I glossed over: in my first attempt, my macro couldn&amp;#39;t find
&lt;code class=&#34;verbatim&#34;&gt;apply-bindings&lt;/code&gt; at compile time until I wrapped that function&amp;#39;s definition as follows:&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(eval-when (:compile-toplevel :load-toplevel :execute)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  (defun apply-bindings (...) ...))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
This is apparently needed for functions used by macros defined in the
same file; it&amp;#39;s not an issue for functions defined in other
files. Since Clojure has a single-pass compiler, this sort of ceremony
is not needed for Clojure macros.&lt;/p&gt;
&lt;p&gt;
I expect to use this macro again, so will probably spin it out into a
small stand-alone library or incorporate it into a thin wrapper around
1AM.  Here it is in action in the &lt;code class=&#34;verbatim&#34;&gt;hbook&lt;/code&gt; library where our discussion started:&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(test hist-values-test
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  (are (h c mn mx heights xs)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;       (progn
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;         (is (= c (hist-count h)))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;         (is (= mn (hist-min h)))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;         (is (= mx (hist-max h)))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;         (is (equalp heights (hist-bin-heights h)))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;         (is (equalp xs (hist-bin-xs h))))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;       (histogram &amp;#39;(1 2)     2)   2 1 2 #(1 1)   #(1 2)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;       (histogram &amp;#39;(1 2 1)   2)   2 1 2 #(2 1)   #(1 2)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;       (histogram &amp;#39;(1 2 2 3) 3)   3 1 3 #(1 2 1) #(1 2 3)))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
The code which &lt;code class=&#34;verbatim&#34;&gt;are&lt;/code&gt; makes possible is usually denser and can be
harder to parse initially than more repetitive test code would, as is
clear from this example.  However, I find the brevity of &lt;code class=&#34;verbatim&#34;&gt;are&lt;/code&gt; tests
extremely helpful, especially when comparing the test examples to each
another.  Such examples are especially helpful when calling out edge
cases where behavior changes. I have given such tables to stakeholders
many times, in order to make sure we are aligned on what the behavior
should be. (Even if the stakeholder doesn&amp;#39;t care about the details of
your implementation or your test code &lt;em&gt;per se&lt;/em&gt;, they probably &lt;em&gt;will&lt;/em&gt;
care about the specific examples you provide).&lt;/p&gt;
&lt;p&gt;
Parenthetically, here is &lt;a href=&#34;https://github.com/eigenhombre/hbook&#34;&gt;the histogramming library&lt;/a&gt; in action, showing the
distribution of the sum of 1000 six-sided dice:&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(defun d () (1+ (random 6)))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(defun dn (n) (loop repeat n sum (d)))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(princ (hbook (loop repeat 100000 collect (dn 1000))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;              80
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;              30))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;;=&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      4962                                       X  X
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      4791                                       X  X
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      4620                                     X X  X X
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      4449                                     X X  X X
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      4278                                     X XXXXXX X
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      4106                                     X XXXXXX X
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      3935                                   X XXXXXXXXXX
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      3764                                   XXXXXXXXXXXX
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      3593                                   XXXXXXXXXXXX
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      3422                                   XXXXXXXXXXXX
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      3251                                   XXXXXXXXXXXXX X
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      3080                                  XXXXXXXXXXXXXXXX
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      2909                                X XXXXXXXXXXXXXXXX
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      2738                                XXXXXXXXXXXXXXXXXX
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      2566                                XXXXXXXXXXXXXXXXXX
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      2395                                XXXXXXXXXXXXXXXXXXXX
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      2224                               XXXXXXXXXXXXXXXXXXXXX
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      2053                              XXXXXXXXXXXXXXXXXXXXXX
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      1882                              XXXXXXXXXXXXXXXXXXXXXX
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      1711                              XXXXXXXXXXXXXXXXXXXXXXX
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      1540                             XXXXXXXXXXXXXXXXXXXXXXXXX
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      1369                             XXXXXXXXXXXXXXXXXXXXXXXXXX
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      1198                           XXXXXXXXXXXXXXXXXXXXXXXXXXXX
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      1027                           XXXXXXXXXXXXXXXXXXXXXXXXXXXXX
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;       856                         XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;       684                         XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;       513                       XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;       342                       XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;       171                    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;         0 X   XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX    X
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                                     111222233344544544443332211111
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                            11223568933623981977003313702313558540076333111
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                      11244625381526456400925471219232518023527888048930961854221 1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;           1   11235564827658185382948873231241519783970927498485883199710549330480234    1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;           33333333333333333333333333333333333333333333333333333333333333333333333333333333
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;           22222222233333333333333334444444444444445555555555555555666666666666666677777777
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;           45566788900122344556778990112334456678890011233455677899001223445667889901123345
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;           40639628518417306395285184073062952851740739629528417406396295184173063962851841
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;           ................................................................................
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;           04826059371504826159371604827159372604827159382604837159382604937159482604937150
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;           02457912468913578024579134680135780246791346802357902467913568023579124689135680&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
</description>
    </item>
    
    <item>
      <title>(Yet Another) Lisp In Go</title>
      <link>http://johnj.com/posts/l1/</link>
      <pubDate>Sun, 27 Mar 2022 00:00:00 +0000</pubDate>
      
      <guid>http://johnj.com/posts/l1/</guid>
      <description>
&lt;p&gt;





&lt;a href=&#34;http://johnj.com/l1.jpg&#34;&gt;&lt;img class=&#34;resize&#34; src=&#34;http://johnj.com/l1_hu_dae8791e33075232.jpg&#34; style=&#34;width:500px; border:0px solid black;&#34;/&gt;&lt;/a&gt;

&lt;/p&gt;
&lt;p&gt;
For the past month I&amp;#39;ve been spending some free time writing another
Lisp implementation, this time in Go.  &lt;a href=&#34;http://johnj.com/posts/scheme-in-python/&#34;&gt;My previous attempt&lt;/a&gt; was a
subset of Scheme made in preparation for a class on the classic
&lt;a href=&#34;https://mitpress.mit.edu/sites/default/files/sicp/index.html&#34;&gt;Structure and Interpretation of Computer Programs&lt;/a&gt;.  That project
was great fun and I learned a lot.&lt;/p&gt;
&lt;p&gt;
I started learning Go late last year and began thinking about writing
another Lisp.  Go has garbage collection, a feature that has long
been an essential part of most Lisps&lt;sup class=&#34;footnote-reference&#34;&gt;&lt;a id=&#34;footnote-reference-1&#34; href=&#34;#footnote-1&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;.
Getting GC essentially for free would save a lot of time and effort.&lt;/p&gt;
&lt;p&gt;
Go is also extremely fast. For applications where startup performance is
not an issue, I&amp;#39;m pretty happy with Clojure most of the time.  But
working with Common Lisp in recent years, and Go more recently, has
spoiled me and made me hungry for more performance, especially for
short-running command-line utilities.&lt;/p&gt;
&lt;p&gt;
There are obviously other Lisps written in Go already, including
&lt;a href=&#34;https://github.com/candid82/joker&#34;&gt;Joker&lt;/a&gt;, a Clojure interpreter and linter.  But I wasn&amp;#39;t particularly
interested with implementing a particular Lisp dialect; rather, I
wanted to try to implement a language core that one could extend in a
variety of different directions, including &lt;a href=&#34;http://www.paulgraham.com/rootsoflisp.html&#34;&gt;implementing the language
in itself&lt;/a&gt;.  Other possible directions include graphics programming,
text-based games, and scripting. The working name of this Lisp is &lt;code class=&#34;verbatim&#34;&gt;l1&lt;/code&gt;
(&amp;#34;el-one&amp;#34;), hinting at a possible series of small, experimental Lisps.&lt;/p&gt;
&lt;div id=&#34;outline-container-headline-1&#34; class=&#34;outline-2&#34;&gt;
&lt;h2 id=&#34;headline-1&#34;&gt;
Features
&lt;/h2&gt;
&lt;div id=&#34;outline-text-headline-1&#34; class=&#34;outline-text-2&#34;&gt;
&lt;p&gt;
Here is a summary of what&amp;#39;s implemented &amp;amp; planned:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;l1 has&lt;/th&gt;
&lt;th&gt;doesn&amp;#39;t have&lt;/th&gt;
&lt;th&gt;will have&lt;/th&gt;
&lt;th&gt;might get&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;integers (&lt;a href=&#34;https://stackoverflow.com/questions/17564335/golang-math-big-what-is-the-max-value-of-big-int&#34;&gt;essentially unlimited size&lt;/a&gt;)&lt;/td&gt;
&lt;td&gt;keywords&lt;/td&gt;
&lt;td&gt;macros&lt;/td&gt;
&lt;td&gt;curses&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;comments (&lt;code class=&#34;verbatim&#34;&gt;;; ....&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;maps&lt;/td&gt;
&lt;td&gt;syntax quote&lt;/td&gt;
&lt;td&gt;graphics&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;atoms&lt;/td&gt;
&lt;td&gt;strings&lt;/td&gt;
&lt;td&gt;reader macros (`, &amp;#39;, …)&lt;/td&gt;
&lt;td&gt;subprocess / shells&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;lists&lt;/td&gt;
&lt;td&gt;namespaces&lt;/td&gt;
&lt;td&gt;REPL / editor integration&lt;/td&gt;
&lt;td&gt;big floats&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4 special forms: &lt;code class=&#34;verbatim&#34;&gt;cond&lt;/code&gt;, &lt;code class=&#34;verbatim&#34;&gt;def&lt;/code&gt;, &lt;code class=&#34;verbatim&#34;&gt;lambda&lt;/code&gt;, &lt;code class=&#34;verbatim&#34;&gt;quote&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;exceptions&lt;/td&gt;
&lt;td&gt;&lt;code class=&#34;verbatim&#34;&gt;let&lt;/code&gt; (as a macro)&lt;/td&gt;
&lt;td&gt;&lt;code class=&#34;verbatim&#34;&gt;error&lt;/code&gt; equiv.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;16 built-in functions&lt;/td&gt;
&lt;td&gt;loops&lt;/td&gt;
&lt;td&gt;&lt;code class=&#34;verbatim&#34;&gt;defun&lt;/code&gt; / &lt;code class=&#34;verbatim&#34;&gt;defn&lt;/code&gt; (as a macro)&lt;/td&gt;
&lt;td&gt;tail call optimization&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;recursion&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;closures&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;byte code compilation/interpretation&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&#34;outline-container-headline-2&#34; class=&#34;outline-2&#34;&gt;
&lt;h2 id=&#34;headline-2&#34;&gt;
Performance
&lt;/h2&gt;
&lt;div id=&#34;outline-text-headline-2&#34; class=&#34;outline-text-2&#34;&gt;
&lt;p&gt;
The &lt;a href=&#34;https://github.com/eigenhombre/l1/&#34;&gt;current implementation is on GitHub&lt;/a&gt;.  Its speed surprises me a bit.&lt;/p&gt;
&lt;p&gt;
Consider the following program in &lt;code class=&#34;verbatim&#34;&gt;l1&lt;/code&gt;, which computes a factorial:&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; fact.l1: Return the factorial of `n`:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(def fact
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;     (lambda (n)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;       (cond ((eq 0 n) 1)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;             (t (* n (fact (- n 1)))))))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(print (fact 100))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;outputting&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;933262154439441526816992388562667004907159682643816214685929638
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;952175999932299156089414639761565182862536979208272237582511852
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;10916864000000000000000000000000&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
Its equivalent in Clojure (or its nimble alternative implementations,
Babashka or Joker) can be written as follows:&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; fact.clj: Return the factorial of `n`:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(def fact
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  (fn [n]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    (cond (= 0 n) 1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;          :else (*&amp;#39; n (fact (- n 1))))))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(println (fact 100))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;… and in my Python Scheme implementation as&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; fact.scm
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(define (fact n)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  (if (= n 1)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      (* n (fact (- n 1)))))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(display (fact 100))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
I also did the equivalent for Common Lisp.  I used &lt;a href=&#34;https://github.com/eigenhombre/oatmeal/&#34;&gt;Oatmeal&lt;/a&gt; to make a
skeleton Lisp project and used that to create an executable program
called &lt;code class=&#34;verbatim&#34;&gt;fact&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;
The execution times break down thusly:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Language&lt;/th&gt;
&lt;th&gt;Running It&lt;/th&gt;
&lt;th class=&#34;align-right&#34;&gt;Execution Time (ms)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Clojure&lt;/td&gt;
&lt;td&gt;&lt;code class=&#34;verbatim&#34;&gt;clojure -M fact.clj&lt;/code&gt;&lt;/td&gt;
&lt;td class=&#34;align-right&#34;&gt;1729&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Babashka&lt;/td&gt;
&lt;td&gt;&lt;code class=&#34;verbatim&#34;&gt;bb fact.clj&lt;/code&gt;&lt;/td&gt;
&lt;td class=&#34;align-right&#34;&gt;200&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&#34;verbatim&#34;&gt;smallscheme&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code class=&#34;verbatim&#34;&gt;scheme.py fact.scm&lt;/code&gt;&lt;/td&gt;
&lt;td class=&#34;align-right&#34;&gt;120&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Common Lisp&lt;/td&gt;
&lt;td&gt;&lt;code class=&#34;verbatim&#34;&gt;./fact&lt;/code&gt;&lt;/td&gt;
&lt;td class=&#34;align-right&#34;&gt;68&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Joker&lt;/td&gt;
&lt;td&gt;&lt;code class=&#34;verbatim&#34;&gt;joker fact.clj&lt;/code&gt;&lt;/td&gt;
&lt;td class=&#34;align-right&#34;&gt;59&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&#34;verbatim&#34;&gt;l1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code class=&#34;verbatim&#34;&gt;l1 fact.l1&lt;/code&gt;&lt;/td&gt;
&lt;td class=&#34;align-right&#34;&gt;8&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;
This is a very limited benchmark!  However, it does give a flavor for
start-up times.  Note that &lt;code class=&#34;verbatim&#34;&gt;l1&lt;/code&gt; is a tree-walking interpreter; I
wonder what speed might be possible if implemented with a byte code
interpreter.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&#34;outline-container-headline-3&#34; class=&#34;outline-2&#34;&gt;
&lt;h2 id=&#34;headline-3&#34;&gt;
Lexing
&lt;/h2&gt;
&lt;div id=&#34;outline-text-headline-3&#34; class=&#34;outline-text-2&#34;&gt;
&lt;p&gt;
I started the journey by writing the lexer.  A post on Hacker News led me
to &lt;a href=&#34;https://www.youtube.com/watch?v=HxaD_trXwRE&#34;&gt;this video&lt;/a&gt; where Rob Pike, of the core Go language team, describes
an elegant design for a lexer used in the Go templating library.  I
was able to extract the relevant bits into a fairly &lt;a href=&#34;https://github.com/eigenhombre/lexutil/&#34;&gt;general-purpose
library&lt;/a&gt; that I then used for this Lisp with &lt;a href=&#34;https://github.com/eigenhombre/l1/blob/master/lex.go&#34;&gt;relatively little code&lt;/a&gt; (of
course, one shouldn&amp;#39;t expect too much code when lexing a Lisp, since
there is not much syntax).&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&#34;outline-container-headline-4&#34; class=&#34;outline-2&#34;&gt;
&lt;h2 id=&#34;headline-4&#34;&gt;
Fun With Atoms and Lists
&lt;/h2&gt;
&lt;div id=&#34;outline-text-headline-4&#34; class=&#34;outline-text-2&#34;&gt;
&lt;p&gt;
You may have noticed the lack of character strings in the feature
table, above.  &lt;a href=&#34;https://github.com/norvig/paip-lisp&#34;&gt;Many interesting Lisp programs&lt;/a&gt; don&amp;#39;t use traditional
strings (arrays of characters encoded as bytes), and I am curious to
see what can be done strictly without them, though I could see adding
them at some point.&lt;/p&gt;
&lt;p&gt;
Without strings, one will probably want to manipulate atoms in various
ways.  As a start, &lt;code class=&#34;verbatim&#34;&gt;l1&lt;/code&gt; introduces the notion of &amp;#34;splitting&amp;#34; (creating
a list from an atom or number) and &amp;#34;fusing&amp;#34; (joining such a list back
together again):&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&amp;gt; (split (quote greenspun))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(g r e e n s p u n)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&amp;gt; (split 1395871)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(1 3 9 5 8 7 1)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&amp;gt; (fuse (quote (1 2 3 4 5)))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;12345
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&amp;gt; (randigits 10)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(6 1 5 4 4 8 8 3 0 1)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&amp;gt; (randigits 10)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(2 7 5 4 7 9 1 6 6 1)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&amp;gt; (fuse (randigits 1000))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;797522288353215977146173184650097900747324790200919947108552266
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;896559408664559755127840959435738695979408193086120089317097735
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;733247509700258597497415541421859295990446300938230591278544826
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;160148998280910399112793807480556810085222871423786728939605143
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;312291343715625109027024093962060686621901049553518883581864852
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;832439160531395519838325036388642484613231265974048363263732041
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;737675913066537856875008449087672272329301144164887429770199070
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;521721230755123684155760268379043481645391533460833091119801604
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;531684362848585264816725347753593965869286499060052823295397069
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;598147167103689429912992818647290966641807288375144076084638850
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;885562168375457674623070776900707693203757775691854059277861315
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;130019383408298242102129643369889134587749005021251080452606062
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;217504938911721968545635428643266561957454859338694605115003758
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;001930119736513921576952435852918640253473323143920762789645830
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;700672642264667728965761815048634636071828415705273836146286590
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;4892309215088593977646507232497245814663081971549675531
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&#34;outline-container-headline-5&#34; class=&#34;outline-2&#34;&gt;
&lt;h2 id=&#34;headline-5&#34;&gt;
Testing
&lt;/h2&gt;
&lt;div id=&#34;outline-text-headline-5&#34; class=&#34;outline-text-2&#34;&gt;
&lt;p&gt;
As with previous Lisps I&amp;#39;ve worked on, most of the tests were
represented in Go code as strings containing &lt;a href=&#34;https://github.com/eigenhombre/l1/blob/master/eval_test.go&#34;&gt;Lisp code and the
expressions they evaluate to&lt;/a&gt;.  Here are some examples, taken more or
less at random.&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        ...
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        // `split` function
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        {Cases(S(&amp;#34;(split)&amp;#34;, &amp;#34;&amp;#34;, &amp;#34;expects a single argument&amp;#34;))},
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        {Cases(S(&amp;#34;(split 1)&amp;#34;, &amp;#34;(1)&amp;#34;, OK))},
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        {Cases(S(&amp;#34;(split -1)&amp;#34;, &amp;#34;(-1)&amp;#34;, OK))},
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        {Cases(S(&amp;#34;(split -321)&amp;#34;, &amp;#34;(-3 2 1)&amp;#34;, OK))},
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        {Cases(S(&amp;#34;(split (quote a))&amp;#34;, &amp;#34;(a)&amp;#34;, OK))},
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        {Cases(S(&amp;#34;(split (quote (a b c)))&amp;#34;, &amp;#34;&amp;#34;, &amp;#34;expects an atom or a number&amp;#34;))},
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        {ECases(S(&amp;#34;(split (quote greenspun))&amp;#34;, &amp;#34;(g r e e n s p u n)&amp;#34;, OK))},
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        {ECases(S(&amp;#34;(split (* 12345 67890))&amp;#34;, &amp;#34;(8 3 8 1 0 2 0 5 0)&amp;#34;, OK))},
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        {ECases(S(&amp;#34;(len (split (* 99999 99999 99999)))&amp;#34;, &amp;#34;15&amp;#34;, OK))},
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        {ECases(S(&amp;#34;(split (quote greenspun))&amp;#34;, &amp;#34;(g r e e n s p u n)&amp;#34;, OK))},
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        {ECases(S(&amp;#34;(split (* 12345 67890))&amp;#34;, &amp;#34;(8 3 8 1 0 2 0 5 0)&amp;#34;, OK))},
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        {Cases(S(&amp;#34;(fuse (quote (1 2)))&amp;#34;, &amp;#34;12&amp;#34;, OK))},
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        {ECases(S(&amp;#34;(+ 2 (fuse (quote (1 2 3))))&amp;#34;, &amp;#34;125&amp;#34;, OK))},
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        {ECases(S(&amp;#34;(fuse (split 1295807125987))&amp;#34;, &amp;#34;1295807125987&amp;#34;, OK))},
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        {ECases(S(&amp;#34;(len (randigits 10))&amp;#34;, &amp;#34;10&amp;#34;, OK))},
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        {ECases(S(&amp;#34;((lambda (x) (+ 1 x)) 1)&amp;#34;, &amp;#34;2&amp;#34;, OK))},
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        {ECases(
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                S(&amp;#34;(def incrementer (lambda (n) (lambda (x) (+ x n))))&amp;#34;, &amp;#34;&amp;lt;lambda(n)&amp;gt;&amp;#34;, OK),
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                S(&amp;#34;(def inc (incrementer 1))&amp;#34;, &amp;#34;&amp;lt;lambda(x)&amp;gt;&amp;#34;, OK),
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                S(&amp;#34;(inc 5)&amp;#34;, &amp;#34;6&amp;#34;, OK),
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                S(&amp;#34;(def add2 (incrementer 2))&amp;#34;, &amp;#34;&amp;lt;lambda(x)&amp;gt;&amp;#34;, OK),
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                S(&amp;#34;(add2 5)&amp;#34;, &amp;#34;7&amp;#34;, OK),
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        )},
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        ...&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
Here &lt;code class=&#34;verbatim&#34;&gt;Cases&lt;/code&gt; is a utility function that create a local environment (a
possibly nested set of variable bindings) and evaluates one or more
expressions in that environment; &lt;code class=&#34;verbatim&#34;&gt;ECases&lt;/code&gt; (&lt;code class=&#34;verbatim&#34;&gt;E&lt;/code&gt; for Exemplary) is the
same, but saves its test cases in an &lt;a href=&#34;https://github.com/eigenhombre/l1/blob/master/examples.txt&#34;&gt;&lt;code class=&#34;verbatim&#34;&gt;examples.txt&lt;/code&gt;&lt;/a&gt; file which stores
a reduced set of illustrative cases, e.g. for adding to the README.
&lt;code class=&#34;verbatim&#34;&gt;S&lt;/code&gt; is a function which takes an expression to evaluate, the result
that should obtain, or an error message fragment which is expected if
the expression should fail.&lt;/p&gt;
&lt;p&gt;
This seems to be a good way to test a new language
implementation, though I plan to implement some generative / &amp;#34;fuzzing&amp;#34;
tests as well, since I doubt all the bugs have been found yet.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&#34;outline-container-headline-6&#34; class=&#34;outline-2&#34;&gt;
&lt;h2 id=&#34;headline-6&#34;&gt;
Further Work
&lt;/h2&gt;
&lt;div id=&#34;outline-text-headline-6&#34; class=&#34;outline-text-2&#34;&gt;
&lt;p&gt;
Macros are next.  I&amp;#39;m pretty sure I know how I want to do them, and
for me the power of macros is the whole point of Lisp, or at least a
big part of the point.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&#34;outline-container-headline-7&#34; class=&#34;outline-2&#34;&gt;
&lt;h2 id=&#34;headline-7&#34;&gt;
A Final Note on Performance, and Conclusion
&lt;/h2&gt;
&lt;div id=&#34;outline-text-headline-7&#34; class=&#34;outline-text-2&#34;&gt;
&lt;p&gt;
To return to the performance discussion, above: a reasonable person
might object that &lt;code class=&#34;verbatim&#34;&gt;l1&lt;/code&gt; is so lean on features, that it&amp;#39;s not at all
surprising that it starts fast.  Clojure, on the other hand, leverages
the JVM, which has been tuned for decades for speed in long-running
processes, and also provides a thoughtful and comprehensive language
design that does many things no hobby language could easily support.&lt;/p&gt;
&lt;p&gt;
That being said, one thing I am excited about with this project is
this: pretty much anything I can do in Go (which is very many things)
can be added to my Lisp without &lt;em&gt;too&lt;/em&gt; much effort.  Conversely, to add
features to a Common Lisp or Clojure implementation would be very
difficult indeed.  Building a small language core that you can extend
in a variety of directions is a fun, if not necessarily entirely
practical, way to go.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;footnotes&#34;&gt;
&lt;hr class=&#34;footnotes-separatator&#34;&gt;
&lt;div class=&#34;footnote-definitions&#34;&gt;
&lt;div class=&#34;footnote-definition&#34;&gt;
&lt;sup id=&#34;footnote-1&#34;&gt;&lt;a href=&#34;#footnote-reference-1&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;
&lt;div class=&#34;footnote-body&#34;&gt;
&lt;p&gt;I met a speaker at LambdaJam 2015 who used his own Lisp for music performance. It was not garbage-collected, for real-time performance.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
</description>
    </item>
    
    <item>
      <title>From Elegance to Speed</title>
      <link>http://johnj.com/posts/from-elegance-to-speed/</link>
      <pubDate>Wed, 25 Sep 2019 00:00:00 +0000</pubDate>
      
      <guid>http://johnj.com/posts/from-elegance-to-speed/</guid>
      <description>
&lt;div id=&#34;outline-container-headline-1&#34; class=&#34;outline-2&#34;&gt;
&lt;h2 id=&#34;headline-1&#34;&gt;
Making Things Fast
&lt;/h2&gt;
&lt;div id=&#34;outline-text-headline-1&#34; class=&#34;outline-text-2&#34;&gt;
&lt;p&gt;





&lt;a href=&#34;http://johnj.com/plane.jpg&#34;&gt;&lt;img class=&#34;resize&#34; src=&#34;http://johnj.com/plane_hu_a29fb6edbf8b159e.jpg&#34; style=&#34;width:700px; border:0px solid black;&#34;/&gt;&lt;/a&gt;

&lt;/p&gt;
&lt;p&gt;
A while back, we used &lt;a href=&#34;http://johnj.com/posts/lazy-physics/&#34;&gt;a toy particle physics trigger&lt;/a&gt; to explore
concepts in lazy evaluation and functional programming in Clojure. We
came up with the following function which selected groups of eight
events clustered close together in time:&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(defn smt-8 [times]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  (-&amp;gt;&amp;gt; times
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;       (partition 8 1)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;       (map (juxt identity
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                  (comp (partial apply -)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                        (juxt last first))))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;       (filter (comp (partial &amp;gt; 1000) second))))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
Though elegant, this function processed events at a rate of 250 kHz,
which I found slightly disappointing, performance-wise.&lt;/p&gt;
&lt;p&gt;
I have been interested in writing faster programs lately, which is one
of the reasons I&amp;#39;ve been &lt;a href=&#34;http://johnj.com/posts/lisp-projects/&#34;&gt;learning Common Lisp&lt;/a&gt;. Common Lisp lets you
create extremely high-level programming constructs, but also lets you
get closer to the metal when you need to. In this post we&amp;#39;ll look at
some ways for improving performance and compare our results to the
original 250 kHz event rate.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&#34;outline-container-headline-2&#34; class=&#34;outline-2&#34;&gt;
&lt;h2 id=&#34;headline-2&#34;&gt;
First Steps
&lt;/h2&gt;
&lt;div id=&#34;outline-text-headline-2&#34; class=&#34;outline-text-2&#34;&gt;
&lt;p&gt;
The first step is to translate our code as is to Common Lisp. We&amp;#39;re
going to punt entirely on the question of laziness for this post,
though we might take it up in the future.&lt;/p&gt;
&lt;p&gt;
Here&amp;#39;s my first attempt. We have to start with our source of random
times. In Clojure, we had:&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(def times (iterate #(+ % (rand-int 1000)) 0))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
Since I&amp;#39;m going to benchmark performance, we&amp;#39;ll need to set a limit to the number of events (times) we&amp;#39;ll process. So, in Common Lisp:&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(defun time-sequence (n)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  (loop repeat n
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;     for y = 0 then (+ y (random 1000))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;     collect y))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
where &lt;code class=&#34;verbatim&#34;&gt;n&lt;/code&gt; is the number of event times to process.  Here and
throughout what follows, I&amp;#39;m using the &lt;code class=&#34;verbatim&#34;&gt;loop&lt;/code&gt; macro, which is a Swiss
army knife for iteration with a somewhat strange, non-Lispy, but
readable syntax.&lt;/p&gt;
&lt;p&gt;
We also want to set our random state so as to guarantee different
results each time we execute our simulation:&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(setf *random-state* (make-random-state t))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
My first attempt in Common Lisp looked like this benchmarking snippet:&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(timing
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  (length
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    (-&amp;gt;&amp;gt; 1000000
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;         time-sequence
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;         (partition-n 8 1)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;         (mapcar (juxt #&amp;#39;car (compose #&amp;#39;car #&amp;#39;last) #&amp;#39;identity))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;         (mapcar #&amp;#39;(lambda (l) `(,(- (cadr l) (car l)) ,(caddr l))))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;         (remove-if-not #&amp;#39;(lambda (l) (&amp;lt; (car l) 1000))))))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
This is less lovely than the Clojure, partly because of all the
hash-quoting of functions (Common Lisp is a &lt;a href=&#34;https://stackoverflow.com/questions/4578574/what-is-the-difference-between-lisp-1-and-lisp-2&#34;&gt;Lisp-2&lt;/a&gt;, and Clojure is a
Lisp 1). &lt;code class=&#34;verbatim&#34;&gt;-&amp;gt;&amp;gt;&lt;/code&gt; is from the &lt;code class=&#34;verbatim&#34;&gt;arrow-macros&lt;/code&gt; library, and &lt;code class=&#34;verbatim&#34;&gt;compose&lt;/code&gt; is
from the &lt;code class=&#34;verbatim&#34;&gt;cl-utilities&lt;/code&gt; library.  The other Clojure-ish functions,
&lt;code class=&#34;verbatim&#34;&gt;partition-n&lt;/code&gt; (a replacement for Clojure&amp;#39;s &lt;code class=&#34;verbatim&#34;&gt;partition&lt;/code&gt;, whose name
collides with an entirely different function in Common Lisp) and
&lt;code class=&#34;verbatim&#34;&gt;juxt&lt;/code&gt; are from &lt;a href=&#34;https://github.com/eigenhombre/cl-oju&#34;&gt;&lt;code class=&#34;verbatim&#34;&gt;cl-oju&lt;/code&gt;&lt;/a&gt;, &lt;a href=&#34;https://github.com/eigenhombre/cl-oju&#34;&gt;a small library&lt;/a&gt; I&amp;#39;ve been writing for those
still-frequent times when I want a Clojure function or idiom in Common
Lisp. (The library ignores laziness for now, since I haven&amp;#39;t needed it
yet.)&lt;/p&gt;
&lt;p&gt;
&lt;code class=&#34;verbatim&#34;&gt;timing&lt;/code&gt; is a macro I adapted from &lt;a href=&#34;https://lispcookbook.github.io/cl-cookbook/dates_and_times.html&#34;&gt;the Common Lisp Cookbook&lt;/a&gt;, which
captures both the results of a computation and the elapsed CPU time
used (not wall clock time) in msec:&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(defmacro timing (&amp;amp;body forms)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  (let ((run1 (gensym))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	(run2 (gensym))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	(result (gensym)))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    `(let ((,run1 (get-internal-run-time))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	   (,result (progn ,@forms))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	   (,run2 (get-internal-run-time)))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;       `(duration ,(- ,run2 ,run1) msec... result ,,result))))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
For now, &lt;code class=&#34;verbatim&#34;&gt;result&lt;/code&gt; is simply the number of eight-fold time clusters
occuring within 1000 units of time. The execution time was roughly a
second for the first few times I ran this:&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &amp;#39;(DURATION 1045 MSEC... RESULT 235)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &amp;#39;(DURATION 1554 MSEC... RESULT 201)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &amp;#39;(DURATION 827 MSEC... RESULT 164)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
This already processed events at 1 MHz, roughly 4x faster than the
Clojure speed of 250kHz.&lt;/p&gt;
&lt;p&gt;
Later, however, when I revisited the code, I noticed it ran significantly
faster:&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &amp;#39;(DURATION 435 MSEC... RESULT 193)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &amp;#39;(DURATION 279 MSEC... RESULT 189)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &amp;#39;(DURATION 205 MSEC... RESULT 177)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &amp;#39;(DURATION 601 MSEC... RESULT 180)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
This is 2.6 Mhz, &lt;strong&gt;10x the Clojure code speed&lt;/strong&gt;.  It took me a while to
figure out that I had changed the SBCL heap size in order to handle
larger arrays for testing (this is one area where laziness would
help!). The larger heap size was making the code run faster.&lt;/p&gt;
&lt;p&gt;
It should be said at this point that I made no attempt in my original
blog post to optimize the Clojure code for performance. Nevertheless,
I think it&amp;#39;s interesting that my first attempt to write the same
algorithm in Common Lisp, using roughly the same idioms, performed so
much faster.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&#34;outline-container-headline-3&#34; class=&#34;outline-2&#34;&gt;
&lt;h2 id=&#34;headline-3&#34;&gt;
Interlude
&lt;/h2&gt;
&lt;div id=&#34;outline-text-headline-3&#34; class=&#34;outline-text-2&#34;&gt;
&lt;p&gt;
Looking back over my career, it seems I have been moving gradually
from fast, lower-level languages to slower, more expressive,
high-level languages: &lt;code class=&#34;verbatim&#34;&gt;FORTRAN&lt;/code&gt; and C, to Perl and Python, then to
Clojure (which is faster than Python for most long-running programs,
while being arguably more expressive&lt;sup class=&#34;footnote-reference&#34;&gt;&lt;a id=&#34;footnote-reference-1&#34; href=&#34;#footnote-1&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;). I&amp;#39;ve enjoyed this
trajectory, because higher level languages let you implement so much, so
quickly.&lt;/p&gt;
&lt;p&gt;
My feelings on this are shifting, however. I wrote some code a decade
ago for &lt;a href=&#34;https://arxiv.org/abs/0810.4930&#34;&gt;a system&lt;/a&gt; that has been running constantly for a decade on
thousands of devices. My code is not particularly CPU efficient and,
therefore, not as energy-efficient as it could be. As the planet
warms, I think it&amp;#39;s important to try and find small efficiencies where
we can… not necessarily under the assumption that it will make a
massive difference, but because it&amp;#39;s just the right thing to do as
conscientious professionals. (The fact that the sins of my past are
executing on processors running on top of and within Antarctic ice
adds an extra bit of irony here).&lt;/p&gt;
&lt;p&gt;
Common Lisp is particularly interesting to me of late because, having
been designed largely for &lt;a href=&#34;https://en.wikipedia.org/wiki/Symbolic_artificial_intelligence&#34;&gt;Good Old-Fashioned AI&lt;/a&gt;, it allows you to work
at a very high level (you can, for example, add Prolog-like
functionality to a Lisp in a few hundred lines of code &lt;sup class=&#34;footnote-reference&#34;&gt;&lt;a id=&#34;footnote-reference-2&#34; href=&#34;#footnote-2&#34;&gt;2&lt;/a&gt;&lt;/sup&gt; – but, you can generate very fast (i.e.,
more energy efficient) code as well, as we shall see shortly.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&#34;outline-container-headline-4&#34; class=&#34;outline-2&#34;&gt;
&lt;h2 id=&#34;headline-4&#34;&gt;
Improvements
&lt;/h2&gt;
&lt;div id=&#34;outline-text-headline-4&#34; class=&#34;outline-text-2&#34;&gt;
&lt;p&gt;
The next thing I tried was to separate the event generation from the trigger calculation and to use a vector for the input times, instead of a list:&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(defun time-sequence-vec (n)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  (make-array `(,n)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;              :initial-contents
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;              (loop repeat n
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                 for y = 0 then (+ y (random 1000))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                 collect y)))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(defparameter array-size (* 100 1000 1000))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(defparameter *s* (time-sequence-vec array-size))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
I also make the test sample much larger to improve the run durations and statistics.&lt;/p&gt;
&lt;p&gt;
Both Graham&lt;sup class=&#34;footnote-reference&#34;&gt;&lt;a id=&#34;footnote-reference-3&#34; href=&#34;#footnote-3&#34;&gt;3&lt;/a&gt;&lt;/sup&gt; and Norvig&lt;sup class=&#34;footnote-reference&#34;&gt;&lt;a id=&#34;footnote-reference-4&#34; href=&#34;#footnote-4&#34;&gt;4&lt;/a&gt;&lt;/sup&gt; emphasize tuning your algorithm first before turning
to other optimizations. In our case the problem is O(&lt;em&gt;n&lt;/em&gt;), which is
the best time complexity we can hope for, but our use of function
composition, while elegant, could be turned into something more
efficient. To improve the algorithm proper, I perform the entire
computation in a single &lt;code class=&#34;verbatim&#34;&gt;loop&lt;/code&gt; statement. I also change the output
slightly to show the index for matching 8-fold events, start and end
time, and event duration:&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(defun second-try ()
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  (loop for x below (- array-size 8)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;     if (&amp;lt; (- (elt *s* (+ x 8))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;              (elt *s* x))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;           1000)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;     collect `(index ,x
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                     startval ,(elt *s* x)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                     endval   ,(elt *s* (+ x 8))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                     diff     ,(- (elt *s* (+ x 8))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                                  (elt *s* x)))))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(take 4 (second-try))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;;=&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&amp;#39;((INDEX 69087 STARTVAL 34504666 ENDVAL 34505615 DIFF 949)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  (INDEX 153990 STARTVAL 76991815 ENDVAL 76992630 DIFF 815)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  (INDEX 237070 STARTVAL 118617491 ENDVAL 118618358 DIFF 867)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  (INDEX 294951 STARTVAL 147513479 ENDVAL 147514346 DIFF 867))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; Time it, a few times:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(timing (length (second-try)))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;;=&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&amp;#39;(DURATION 2158 MSEC... RESULT 2427)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;;=&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&amp;#39;(DURATION 2167 MSEC... RESULT 2427)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;;=&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&amp;#39;(DURATION 2162 MSEC... RESULT 2427)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;;=&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
Note that the starting and ending time values increase monotonically,
and the reported time differences (&lt;code class=&#34;verbatim&#34;&gt;DIFF&lt;/code&gt;) are under 1000, as desired&lt;sup class=&#34;footnote-reference&#34;&gt;&lt;a id=&#34;footnote-reference-5&#34; href=&#34;#footnote-5&#34;&gt;5&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;
The new trigger function improves the processing rate to 46.2 MHz. At
this point I&amp;#39;m starting to wonder what the assembly language looks
like:&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(disassemble &amp;#39;second-try)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;;=&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;; disassembly for SECOND-TRY
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;; Size: 1061 bytes. Origin: #x228FE0B0                        ; SECOND-TRY
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;; 0B0:       498B7510         MOV RSI, [R13+16]               ; thread.binding-stack-pointer
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;; 0B4:       488975F8         MOV [RBP-8], RSI
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;; 0B8:       488B3591FFFFFF   MOV RSI, [RIP-111]              ; &amp;#39;ARRAY-SIZE
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;; 0BF:       8B56F5           MOV EDX, [RSI-11]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;; 0C2:       4A8B142A         MOV RDX, [RDX+R13]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;; 0C6:       83FA61           CMP EDX, 97
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;; 0C9:       480F4456F9       CMOVEQ RDX, [RSI-7]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;; 0CE:       83FA51           CMP EDX, 81
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;; 0D1:       0F84BF030000     JEQ L17
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;; 0D7:       BF10000000       MOV EDI, 16
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;; 0DC:       FF1425B000B021   CALL QWORD PTR [#x21B000B0]     ; GENERIC--
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; .................. many lines omitted ................
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;; 4B6: L24:  CC18             BREAK 24                        ; UNBOUND-SYMBOL-ERROR
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;; 4B8:       27               BYTE #X27                       ; &amp;#39;*S*
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;; 4B9: L25:  6880000000       PUSH 128
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;; 4BE:       FF14252800B021   CALL QWORD PTR [#x21B00028]     ; ALLOC-TRAMP-R11
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;; 4C5:       E9FFFEFFFF       JMP L12
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;; 4CA: L26:  6A10             PUSH 16
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;; 4CC:       FF14252800B021   CALL QWORD PTR [#x21B00028]     ; ALLOC-TRAMP-R11
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;; 4D3:       EB94             JMP L14&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
(258 lines in total.)&lt;/p&gt;
&lt;p&gt;
My assembler-fu is not strong, but I notice the &lt;code class=&#34;verbatim&#34;&gt;GENERIC--&lt;/code&gt; and we do
not need generic functions: there are many opportunities here to
introduce type declarations.&lt;/p&gt;
&lt;p&gt;
After declaring to the compiler we want more speed and less
type-checking (&lt;code class=&#34;verbatim&#34;&gt;(declaim (optimize (speed 3) (debug 0) (safety 0)))&lt;/code&gt;),
let&amp;#39;s declare our array to be type &lt;code class=&#34;verbatim&#34;&gt;fixnum&lt;/code&gt; (which on SBCL is an
integer from -4611686018427387904 to 4611686018427387903).&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(defparameter *s* (make-array array-size
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                              :element-type &amp;#39;fixnum))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; Initialize array:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(loop
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   for y = 0 then (+ y (random 1000))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   for i below array-size
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   do (setf (elt *s* i) y))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(timing
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  (length
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   (loop for x below (- array-size 8)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      if (&amp;lt; (- (elt *s* (+ x 8))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;               (elt *s* x))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            1000)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      collect `(index ,x
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                      startval ,(elt *s* x)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                      endval   ,(elt *s* (+ x 8))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                      diff     ,(- (elt *s* (+ x 8))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                                   (elt *s* x))))))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;;=&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&amp;#39;(DURATION 1964 MSEC... RESULT 2435)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;;=&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&amp;#39;(DURATION 1939 MSEC... RESULT 2435)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;;=&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&amp;#39;(DURATION 2010 MSEC... RESULT 2435)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
… maybe a slight improvement. Let&amp;#39;s now type-hint where we can throughout the tight loop:&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(timing
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  (length
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   (loop for x below (- array-size 8)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      if (&amp;lt; (- (the fixnum (elt *s* (the fixnum (+ x 8))))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;               (the fixnum (elt *s* (the fixnum x))))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            1000)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      collect `(index ,x
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                      startval ,(elt *s* x)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                      endval   ,(elt *s* (+ x 8))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                      diff     ,(- (elt *s* (+ x 8))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                                   (elt *s* x))))))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;;=&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&amp;#39;(DURATION 1740 MSEC... RESULT 2435)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;;=&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&amp;#39;(DURATION 1738 MSEC... RESULT 2435)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;;=&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&amp;#39;(DURATION 1753 MSEC... RESULT 2435)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
A 10% or so improvement… not too bad.&lt;/p&gt;
&lt;p&gt;
At this point I&amp;#39;m tempted to look at the macroexpansion of my &lt;code class=&#34;verbatim&#34;&gt;loop&lt;/code&gt;
expression and see what it&amp;#39;s doing. For simplicity, I &lt;code class=&#34;verbatim&#34;&gt;collect&lt;/code&gt; just
the starting time index for times satisfying the trigger:&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(macroexpand-1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &amp;#39;(loop for x below (- array-size 8)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;     if (&amp;lt; (- (the fixnum (elt *s* (the fixnum (+ x 8))))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            (the fixnum (elt *s* (the fixnum x))))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;         1000)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;     collect x))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;;=&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&amp;#39;(block nil
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  (let ((#:loop-limit-711 (- array-size 8)) (x 0))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    (declare (type (and number real) x)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;             (type (and number real) #:loop-limit-711))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    (sb-loop::with-loop-list-collection-head (#:loop-list-head-712
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                                              #:loop-list-tail-713)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      (tagbody
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;       sb-loop::next-loop
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;         (when (&amp;gt;= x #:loop-limit-711) (go sb-loop::end-loop))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;         (if (&amp;lt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;              (- (the fixnum (elt *s* (the fixnum (+ x 8))))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                 (the fixnum (elt *s* (the fixnum x))))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;              1000)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;             (sb-loop::loop-collect-rplacd
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;              (#:loop-list-head-712 #:loop-list-tail-713) (list x)))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;         (sb-loop::loop-desetq x (1+ x))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;         (go sb-loop::next-loop)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;       sb-loop::end-loop
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;         (return-from nil
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;           (sb-loop::loop-collect-answer #:loop-list-head-712))))))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
I notice that &lt;code class=&#34;verbatim&#34;&gt;x&lt;/code&gt; and &lt;code class=&#34;verbatim&#34;&gt;:loop-limit-711&lt;/code&gt; have an overly-general type declaration. I&amp;#39;m not sure how to type-hint &lt;code class=&#34;verbatim&#34;&gt;x&lt;/code&gt;, but I can type-hint the upper bound:&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(timing
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  (length
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   (loop for x below (- (the fixnum array-size) 8)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      if (&amp;lt; (- (the fixnum (elt *s* (+ (the fixnum x) 8)))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;               (the fixnum (elt *s* (the fixnum x))))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            1000)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      collect `(index ,x
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                      startval ,(elt *s* x)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                      endval   ,(elt *s* (+ x 8))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                      diff     ,(- (elt *s* (+ x 8))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                                   (elt *s* x))))))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;;=&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&amp;#39;(DURATION 1460 MSEC... RESULT 2513)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;;=&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&amp;#39;(DURATION 1455 MSEC... RESULT 2513)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;;=&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&amp;#39;(DURATION 1486 MSEC... RESULT 2513)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
Another modest but significant improvement.&lt;/p&gt;
&lt;p&gt;
At this point I reached for the SBCL profiler to see what I could
learn from it. Most of the processing time is spent in array
lookups, which I don&amp;#39;t think we can avoid.&lt;/p&gt;
&lt;p&gt;
Let&amp;#39;s look at the assembler again. Since our trigger matches are rare,
most of our time is going to be spent in finding the events, rather
than in collecting the detailed results for the matches. If we switch
back to using &lt;code class=&#34;verbatim&#34;&gt;collect x&lt;/code&gt; to avoid the extra assembly associated with
building &lt;code class=&#34;verbatim&#34;&gt;`(index ,x startval ...)&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(defun trigger ()
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(loop for x below (- (the fixnum array-size) 8)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;     if (&amp;lt; (- (the fixnum (elt *s* (+ (the fixnum x) 8)))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;              (the fixnum (elt *s* (the fixnum x))))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;           1000)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;     collect x))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(disassemble &amp;#39;trigger)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;;=&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; disassembly for TRIGGER
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; Size: 448 bytes. Origin: #x22610EA0                         ; TRIGGER
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 0EA0:       498B4510         MOV RAX, [R13+16]              ; thread.binding-stack-pointer
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 0EA4:       488945F8         MOV [RBP-8], RAX
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 0EA8:       488B05B1FFFFFF   MOV RAX, [RIP-79]              ; &amp;#39;ARRAY-SIZE
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 0EAF:       8B70F5           MOV ESI, [RAX-11]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 0EB2:       4A8B342E         MOV RSI, [RSI+R13]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 0EB6:       83FE61           CMP ESI, 97
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 0EB9:       480F4470F9       CMOVEQ RSI, [RAX-7]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 0EBE:       83FE51           CMP ESI, 81
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 0EC1:       0F8477010000     JEQ L11
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 0EC7:       40F6C601         TEST SIL, 1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 0ECB:       0F8568010000     JNE L10
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 0ED1:       48D1FE           SAR RSI, 1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 0ED4:       4883EE08         SUB RSI, 8
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 0ED8:       488975F0         MOV [RBP-16], RSI
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 0EDC:       31F6             XOR ESI, ESI
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 0EDE:       49896D28         MOV [R13+40], RBP              ; thread.pseudo-atomic-bits
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 0EE2:       4D8B5D68         MOV R11, [R13+104]             ; thread.alloc-region
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 0EE6:       498D4310         LEA RAX, [R11+16]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 0EEA:       493B4570         CMP RAX, [R13+112]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 0EEE:       0F874D010000     JNBE L12
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 0EF4:       49894568         MOV [R13+104], RAX             ; thread.alloc-region
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 0EF8: L0:   498D4307         LEA RAX, [R11+7]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 0EFC:       49316D28         XOR [R13+40], RBP              ; thread.pseudo-atomic-bits
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 0F00:       7402             JEQ L1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 0F02:       CC09             BREAK 9                        ; pending interrupt trap
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 0F04: L1:   C740F917001020   MOV DWORD PTR [RAX-7], #x20100017  ; NIL
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 0F0B:       C7400117001020   MOV DWORD PTR [RAX+1], #x20100017  ; NIL
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 0F12:       488945E8         MOV [RBP-24], RAX
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 0F16:       488945E0         MOV [RBP-32], RAX
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 0F1A:       E9BB000000       JMP L4
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 0F1F:       90               NOP
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 0F20: L2:   8B142524144A20   MOV EDX, [#x204A1424]          ; tls_index: *S*
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 0F27:       4A8B142A         MOV RDX, [RDX+R13]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 0F2B:       83FA61           CMP EDX, 97
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 0F2E:       480F44142528144A20 CMOVEQ RDX, [#x204A1428]     ; *S*
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 0F37:       83FA51           CMP EDX, 81
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 0F3A:       0F840F010000     JEQ L13
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 0F40:       488D7E10         LEA RDI, [RSI+16]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 0F44:       4883EC10         SUB RSP, 16
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 0F48:       488975D8         MOV [RBP-40], RSI
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 0F4C:       B904000000       MOV ECX, 4
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 0F51:       48892C24         MOV [RSP], RBP
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 0F55:       488BEC           MOV RBP, RSP
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 0F58:       B862934F22       MOV EAX, #x224F9362            ; #&amp;lt;FDEFN ELT&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 0F5D:       FFD0             CALL RAX
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 0F5F:       488B75D8         MOV RSI, [RBP-40]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 0F63:       F6C201           TEST DL, 1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 0F66:       0F85CA000000     JNE L9
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 0F6C:       4C8BC2           MOV R8, RDX
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 0F6F:       49D1F8           SAR R8, 1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 0F72:       4C8945D0         MOV [RBP-48], R8
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 0F76:       8B142524144A20   MOV EDX, [#x204A1424]          ; tls_index: *S*
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 0F7D:       4A8B142A         MOV RDX, [RDX+R13]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 0F81:       83FA61           CMP EDX, 97
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 0F84:       480F44142528144A20 CMOVEQ RDX, [#x204A1428]     ; *S*
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 0F8D:       83FA51           CMP EDX, 81
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 0F90:       0F84BC000000     JEQ L14
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 0F96:       488BFE           MOV RDI, RSI
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 0F99:       4883EC10         SUB RSP, 16
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 0F9D:       488975D8         MOV [RBP-40], RSI
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 0FA1:       B904000000       MOV ECX, 4
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 0FA6:       48892C24         MOV [RSP], RBP
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 0FAA:       488BEC           MOV RBP, RSP
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 0FAD:       B862934F22       MOV EAX, #x224F9362            ; #&amp;lt;FDEFN ELT&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 0FB2:       FFD0             CALL RAX
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 0FB4:       4C8B45D0         MOV R8, [RBP-48]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 0FB8:       488B75D8         MOV RSI, [RBP-40]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 0FBC:       F6C201           TEST DL, 1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 0FBF:       7572             JNE L8
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 0FC1:       488BC2           MOV RAX, RDX
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 0FC4:       48D1F8           SAR RAX, 1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 0FC7:       498BD0           MOV RDX, R8
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 0FCA:       4829C2           SUB RDX, RAX
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 0FCD:       4881FAE8030000   CMP RDX, 1000
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 0FD4:       7C22             JL L5
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 0FD6: L3:   4883C602         ADD RSI, 2
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 0FDA: L4:   488BC6           MOV RAX, RSI
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 0FDD:       48D1F8           SAR RAX, 1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 0FE0:       483B45F0         CMP RAX, [RBP-16]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 0FE4:       0F8C36FFFFFF     JL L2
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 0FEA:       488B45E8         MOV RAX, [RBP-24]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 0FEE:       488B5001         MOV RDX, [RAX+1]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 0FF2:       488BE5           MOV RSP, RBP
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 0FF5:       F8               CLC
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 0FF6:       5D               POP RBP
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 0FF7:       C3               RET
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 0FF8: L5:   4C8B45E0         MOV R8, [RBP-32]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 0FFC:       49896D28         MOV [R13+40], RBP              ; thread.pseudo-atomic-bits
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 1000:       4D8B5D68         MOV R11, [R13+104]             ; thread.alloc-region
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 1004:       498D4310         LEA RAX, [R11+16]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 1008:       493B4570         CMP RAX, [R13+112]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 100C:       7747             JNBE L15
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 100E:       49894568         MOV [R13+104], RAX             ; thread.alloc-region
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 1012: L6:   498D4307         LEA RAX, [R11+7]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 1016:       49316D28         XOR [R13+40], RBP              ; thread.pseudo-atomic-bits
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 101A:       7402             JEQ L7
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 101C:       CC09             BREAK 9                        ; pending interrupt trap
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 101E: L7:   488970F9         MOV [RAX-7], RSI
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 1022:       C7400117001020   MOV DWORD PTR [RAX+1], #x20100017  ; NIL
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 1029:       488945E0         MOV [RBP-32], RAX
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 102D:       49894001         MOV [R8+1], RAX
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 1031:       EBA3             JMP L3
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 1033: L8:   CC48             BREAK 72                       ; OBJECT-NOT-FIXNUM-ERROR
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 1035:       08               BYTE #X08                      ; RDX
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 1036: L9:   CC48             BREAK 72                       ; OBJECT-NOT-FIXNUM-ERROR
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 1038:       08               BYTE #X08                      ; RDX
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 1039: L10:  CC48             BREAK 72                       ; OBJECT-NOT-FIXNUM-ERROR
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 103B:       18               BYTE #X18                      ; RSI
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 103C:       CC10             BREAK 16                       ; Invalid argument count trap
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 103E: L11:  CC18             BREAK 24                       ; UNBOUND-SYMBOL-ERROR
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 1040:       00               BYTE #X00                      ; RAX
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 1041: L12:  6A10             PUSH 16
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 1043:       FF14252800B021   CALL QWORD PTR [#x21B00028]    ; ALLOC-TRAMP-R11
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 104A:       E9A9FEFFFF       JMP L0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 104F: L13:  CC18             BREAK 24                       ; UNBOUND-SYMBOL-ERROR
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 1051:       27               BYTE #X27                      ; &amp;#39;*S*
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 1052: L14:  CC18             BREAK 24                       ; UNBOUND-SYMBOL-ERROR
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 1054:       27               BYTE #X27                      ; &amp;#39;*S*
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 1055: L15:  6A10             PUSH 16
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 1057:       FF14252800B021   CALL QWORD PTR [#x21B00028]    ; ALLOC-TRAMP-R11
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;; 105E:       EBB2             JMP L6&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
… this is almost a manageable amount of assembler, though I don&amp;#39;t
claim to understand all of it. If I needed more speed, though, I could
dig into the assembler as a way to try and ferret out even more
efficiency.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&#34;outline-container-headline-5&#34; class=&#34;outline-2&#34;&gt;
&lt;h2 id=&#34;headline-5&#34;&gt;
Summary
&lt;/h2&gt;
&lt;div id=&#34;outline-text-headline-5&#34; class=&#34;outline-text-2&#34;&gt;
&lt;p&gt;
We went from our initial POC in very functional-looking Clojure,
running at 250 kHz, to optimized Common Lisp running at 100,000,000 /
1467 msec = 68.2 MHz, which is nearly 300x faster.&lt;/p&gt;
&lt;p&gt;
Checking our intuition about how fast this really is: my processor is
2.7 GHz, and our processing rate is 68.2 MHz, meaning we&amp;#39;re spending
about 40 clock ticks per event, which doesn&amp;#39;t strike me as too bad.&lt;/p&gt;
&lt;p&gt;
In the end, we made the following changes to our initial attempt:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Separated out the initial event time-sequence generation as a
separate step;&lt;/li&gt;
&lt;li&gt;Rewrote the algorithm as a single loop;&lt;/li&gt;
&lt;li&gt;&lt;code class=&#34;verbatim&#34;&gt;declaim&lt;/code&gt;&amp;#39;ed optimizations to the compiler;&lt;/li&gt;
&lt;li&gt;Type-hinted the input array, the variables used in the time
difference calculation, and the loop upper bound.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We also touched on profiling (which didn&amp;#39;t provide much benefit this
time, but can be very useful generally), and showed how to inspect the
generated assembler code.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&#34;outline-container-headline-6&#34; class=&#34;outline-2&#34;&gt;
&lt;h2 id=&#34;headline-6&#34;&gt;
Conclusion
&lt;/h2&gt;
&lt;div id=&#34;outline-text-headline-6&#34; class=&#34;outline-text-2&#34;&gt;
&lt;p&gt;
Common Lisp can be made pretty fast!  I should write a C-language
version of this toy problem to compare.  The final code is not nearly
as beautiful as the original, but without too much effort we got much
faster code.  I&amp;#39;ll conclude with this line from ANSI Common Lisp:
&amp;#34;Lisp is really two languages: a language for writing fast programs
and a language for writing programs fast.&amp;#34; It seems quite powerful to
me to have both of these on hand.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;footnotes&#34;&gt;
&lt;hr class=&#34;footnotes-separatator&#34;&gt;
&lt;div class=&#34;footnote-definitions&#34;&gt;
&lt;div class=&#34;footnote-definition&#34;&gt;
&lt;sup id=&#34;footnote-1&#34;&gt;&lt;a href=&#34;#footnote-reference-1&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;
&lt;div class=&#34;footnote-body&#34;&gt;
&lt;p&gt;Reasonable people can disagree on the relative expressiveness of languages; for me, Lisps win on expressiveness because I can bend the language to my will using macros in a way that I cannot with non-Lisps.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;footnote-definition&#34;&gt;
&lt;sup id=&#34;footnote-2&#34;&gt;&lt;a href=&#34;#footnote-reference-2&#34;&gt;2&lt;/a&gt;&lt;/sup&gt;
&lt;div class=&#34;footnote-body&#34;&gt;
&lt;p&gt;See Paul Graham, &lt;em&gt;On Lisp&lt;/em&gt; p. vii&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;footnote-definition&#34;&gt;
&lt;sup id=&#34;footnote-3&#34;&gt;&lt;a href=&#34;#footnote-reference-3&#34;&gt;3&lt;/a&gt;&lt;/sup&gt;
&lt;div class=&#34;footnote-body&#34;&gt;
&lt;p&gt;Paul Graham, ANSI Common Lisp&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;footnote-definition&#34;&gt;
&lt;sup id=&#34;footnote-4&#34;&gt;&lt;a href=&#34;#footnote-reference-4&#34;&gt;4&lt;/a&gt;&lt;/sup&gt;
&lt;div class=&#34;footnote-body&#34;&gt;
&lt;p&gt;Peter Norvig, Paradigms of Artificial Intelligence Programming: Case Studies in Common Lisp&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;footnote-definition&#34;&gt;
&lt;sup id=&#34;footnote-5&#34;&gt;&lt;a href=&#34;#footnote-reference-5&#34;&gt;5&lt;/a&gt;&lt;/sup&gt;
&lt;div class=&#34;footnote-body&#34;&gt;
&lt;p&gt;The original Clojure code reported the entire sequence of eight times for each triggered event, but we omit that level of detail for clarity. Since the triggered clusters are rare, this doesn&amp;#39;t significantly impact the timing measurements.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
</description>
    </item>
    
    <item>
      <title>Common Lisp How-Tos</title>
      <link>http://johnj.com/posts/lisp-projects/</link>
      <pubDate>Sun, 15 Sep 2019 00:00:00 +0000</pubDate>
      
      <guid>http://johnj.com/posts/lisp-projects/</guid>
      <description>
&lt;div id=&#34;outline-container-headline-1&#34; class=&#34;outline-2&#34;&gt;
&lt;h2 id=&#34;headline-1&#34;&gt;
Intro
&lt;/h2&gt;
&lt;div id=&#34;outline-text-headline-1&#34; class=&#34;outline-text-2&#34;&gt;
&lt;p&gt;





&lt;a href=&#34;http://johnj.com/lisp-sticks.jpeg&#34;&gt;&lt;img class=&#34;resize&#34; src=&#34;http://johnj.com/lisp-sticks_hu_118f89e1fb0202d5.jpeg&#34; style=&#34;width:700px; border:0px solid black;&#34;/&gt;&lt;/a&gt;

&lt;/p&gt;
&lt;p&gt;
&lt;em&gt;I&amp;#39;ve been writing this post as I go, and you may still see changes if you check back from time to time.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;
This post is for writing about things I&amp;#39;m figuring out, and for
keeping notes on what I want to figure out next, as I get ramped up on
Common Lisp. When I&amp;#39;m done there will hopefully be stuff here other
people can use.&lt;/p&gt;
&lt;p&gt;
There&amp;#39;s a lot to love and admire about Common Lisp, but the language
has some pointy bits that can at times make Clojure look friendly.
With so many things to sort out I&amp;#39;m going to try to keep a few notes
going forward just to keep it all organized.  Caveat emptor, YMMV, USE
AT YOUR OWN RISK, etc., etc.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&#34;outline-container-headline-2&#34; class=&#34;outline-2&#34;&gt;
&lt;h2 id=&#34;headline-2&#34;&gt;
Lessons Learned So Far
&lt;/h2&gt;
&lt;div id=&#34;outline-text-headline-2&#34; class=&#34;outline-text-2&#34;&gt;
&lt;div id=&#34;outline-container-headline-3&#34; class=&#34;outline-3&#34;&gt;
&lt;h3 id=&#34;headline-3&#34;&gt;
How Do I Set Up Common Lisp on a Mac?
&lt;/h3&gt;
&lt;div id=&#34;outline-text-headline-3&#34; class=&#34;outline-text-3&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/eigenhombre/mac-sbcl-quicklisp-install&#34;&gt;I made a repo&lt;/a&gt; to automate how I set up a fresh SBCL install on a Mac,
including Quicklisp. This gets me from zero to a working Emacs REPL
system fairly quickly.&lt;/p&gt;
&lt;p&gt;
Note that I also set a &lt;code class=&#34;verbatim&#34;&gt;LISP_HOME&lt;/code&gt; environment variable in my
&lt;code class=&#34;verbatim&#34;&gt;.bash_profile&lt;/code&gt; which I use in the examples which follow.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&#34;outline-container-headline-4&#34; class=&#34;outline-3&#34;&gt;
&lt;h3 id=&#34;headline-4&#34;&gt;
How Do I Get Environment Variables from Lisp?
&lt;/h3&gt;
&lt;div id=&#34;outline-text-headline-4&#34; class=&#34;outline-text-3&#34;&gt;
&lt;p&gt;
From the &lt;a href=&#34;https://lispcookbook.github.io/cl-cookbook/os.html&#34;&gt;Common Lisp Cookbook&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(uiop:getenv &amp;#34;HOME&amp;#34;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&#34;outline-container-headline-5&#34; class=&#34;outline-3&#34;&gt;
&lt;h3 id=&#34;headline-5&#34;&gt;
How Do I Quickly Create a New Project?
&lt;/h3&gt;
&lt;div id=&#34;outline-text-headline-5&#34; class=&#34;outline-text-3&#34;&gt;
&lt;p&gt;
(There is &lt;a href=&#34;https://lispmethods.com/libraries.html&#34;&gt;a nice writeup&lt;/a&gt; on how Lisp projects are organized.)&lt;/p&gt;
&lt;p&gt;
First, it seems it&amp;#39;s best to pick a standard place to put your Lisp
projects. I have a deep directory tree on my filesystem so would
prefer to set that path as an environment variable; this makes the
setup easy to port to another computer.&lt;/p&gt;
&lt;p&gt;
I made this &lt;code class=&#34;verbatim&#34;&gt;bash&lt;/code&gt; script, &lt;code class=&#34;verbatim&#34;&gt;lisplib&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;#!/bin/bash
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;projname=${1?}
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sbcl --non-interactive  \
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;     --disable-debugger \
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;     --eval &amp;#39;(ql:quickload &amp;#34;cl-project&amp;#34;)&amp;#39; \
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;     --eval &amp;#39;(ql:quickload &amp;#34;cl-utilities&amp;#34;)&amp;#39; \
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;     --eval &amp;#39;(let* ((projname &amp;#34;&amp;#39;$projname&amp;#39;&amp;#34;)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                    (home (sb-unix::posix-getenv &amp;#34;LISP_HOME&amp;#34;))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                    (projpath (concatenate &amp;#39;&amp;#34;&amp;#39;&amp;#34;&amp;#39;string home &amp;#34;/&amp;#34; projname)))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;               (cl-project:make-project (pathname projpath)))&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;open -a /Applications/Emacs.app $LISP_HOME/$projname/src/main.lisp&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;(Omit the newlines inside the last single-quoted expression.)&lt;/p&gt;
&lt;p&gt;
When I, say, &lt;code class=&#34;verbatim&#34;&gt;lisplib foo&lt;/code&gt;, it creates the project using &lt;code class=&#34;verbatim&#34;&gt;make-project&lt;/code&gt;
and opens the editor on the main source file.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&#34;outline-container-headline-6&#34; class=&#34;outline-3&#34;&gt;
&lt;h3 id=&#34;headline-6&#34;&gt;
How Do I Add Dependencies to One Of My Projects?
&lt;/h3&gt;
&lt;div id=&#34;outline-text-headline-6&#34; class=&#34;outline-text-3&#34;&gt;
&lt;p&gt;Add it to the &lt;code class=&#34;verbatim&#34;&gt;.asd&lt;/code&gt; file in the &lt;code class=&#34;verbatim&#34;&gt;:depends-on&lt;/code&gt; list.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&#34;outline-container-headline-7&#34; class=&#34;outline-3&#34;&gt;
&lt;h3 id=&#34;headline-7&#34;&gt;
How Do I Get My Local Projects Loadable By Other Projects?
&lt;/h3&gt;
&lt;div id=&#34;outline-text-headline-7&#34; class=&#34;outline-text-3&#34;&gt;
&lt;p&gt;I did this once:&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ cd ~/quicklisp
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ mv local-projects /tmp  # Mine was basically empty...
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ ln -s $LISP_HOME local-projects&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&#34;outline-container-headline-8&#34; class=&#34;outline-3&#34;&gt;
&lt;h3 id=&#34;headline-8&#34;&gt;
How Do I Get Dependencies Loaded
&lt;/h3&gt;
&lt;div id=&#34;outline-text-headline-8&#34; class=&#34;outline-text-3&#34;&gt;
&lt;ol&gt;
&lt;li&gt;put your project in the directory symlinked above;&lt;/li&gt;
&lt;li&gt;jack into your REPL;&lt;/li&gt;
&lt;li&gt;update &lt;code class=&#34;verbatim&#34;&gt;depends-on&lt;/code&gt; in the project&amp;#39;s &lt;code class=&#34;verbatim&#34;&gt;.asd&lt;/code&gt; file as you add dependencies;&lt;/li&gt;
&lt;li&gt;&lt;code class=&#34;verbatim&#34;&gt;(ql:quickload &amp;lt;current-package&amp;gt;)&lt;/code&gt; to pick up its dependencies.&lt;/li&gt;
&lt;li&gt;Optionally, to get the correct namespacing for the package you&amp;#39;re
working on, use &lt;code class=&#34;verbatim&#34;&gt;slime-repl-set-package&lt;/code&gt; (&lt;code class=&#34;verbatim&#34;&gt;C-c M-p&lt;/code&gt;) to set the
default package to the one you&amp;#39;re working on (not 100% sure what
effect this has yet)&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&#34;outline-container-headline-9&#34; class=&#34;outline-3&#34;&gt;
&lt;h3 id=&#34;headline-9&#34;&gt;
How Do I Build Binaries?
&lt;/h3&gt;
&lt;div id=&#34;outline-text-headline-9&#34; class=&#34;outline-text-3&#34;&gt;
&lt;p&gt;I use to Xach Beane&amp;#39;s &lt;a href=&#34;https://www.xach.com/lisp/buildapp/&#34;&gt;&lt;code class=&#34;verbatim&#34;&gt;buildapp&lt;/code&gt;&lt;/a&gt;, built like so:&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;git clone git@github.com:xach/buildapp.git
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;cd buildapp
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;make
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;make install&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;A small working build script using &lt;code class=&#34;verbatim&#34;&gt;buildapp&lt;/code&gt; can be found &lt;a href=&#34;https://github.com/eigenhombre/loam/blob/master/build.sh&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&#34;outline-container-headline-10&#34; class=&#34;outline-3&#34;&gt;
&lt;h3 id=&#34;headline-10&#34;&gt;
How Do I Get My Project Into &lt;a href=&#34;https://www.quicklisp.org/beta/&#34;&gt;Quicklisp&lt;/a&gt;?
&lt;/h3&gt;
&lt;div id=&#34;outline-text-headline-10&#34; class=&#34;outline-text-3&#34;&gt;
&lt;p&gt;Make a pull request with Xach Beane &lt;a href=&#34;https://github.com/quicklisp/quicklisp-projects/issues&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&#34;outline-container-headline-11&#34; class=&#34;outline-3&#34;&gt;
&lt;h3 id=&#34;headline-11&#34;&gt;
How Do I Use &lt;code class=&#34;verbatim&#34;&gt;Curses&lt;/code&gt; (or equivalent)?
&lt;/h3&gt;
&lt;div id=&#34;outline-text-headline-11&#34; class=&#34;outline-text-3&#34;&gt;
&lt;p&gt;After some research I decided to follow in &lt;a href=&#34;http://stevelosh.com/blog/2016/08/lisp-jam-postmortem/&#34;&gt;Steve Losh&amp;#39;s footsteps&lt;/a&gt; and
use &lt;code class=&#34;verbatim&#34;&gt;cl-charms&lt;/code&gt; (tutorial &lt;a href=&#34;http://turtleware.eu/posts/cl-charms-crash-course.html&#34;&gt;here&lt;/a&gt;). This &lt;a href=&#34;https://stackoverflow.com/questions/57906498/package-lock-error-while-installing-sbcl-cffi-package-on-mac-via-quicklisp&#34;&gt;cost me multiple days&lt;/a&gt; due to some outdated
Homebrew packages, but worked out in the end after updating those and
reinstalling my Lisp setup.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&#34;outline-container-headline-12&#34; class=&#34;outline-3&#34;&gt;
&lt;h3 id=&#34;headline-12&#34;&gt;
How Do I Get Help?
&lt;/h3&gt;
&lt;div id=&#34;outline-text-headline-12&#34; class=&#34;outline-text-3&#34;&gt;
&lt;p&gt;Aside from Stack Overflow, &lt;a href=&#34;https://www.irccloud.com/irc/freenode/channel/lisp&#34;&gt;the &lt;code class=&#34;verbatim&#34;&gt;#lisp&lt;/code&gt; channel on IRC&lt;/a&gt; was helpful to
me for the above issue.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&#34;outline-container-headline-13&#34; class=&#34;outline-2&#34;&gt;
&lt;h2 id=&#34;headline-13&#34;&gt;
Future Projects
&lt;/h2&gt;
&lt;div id=&#34;outline-text-headline-13&#34; class=&#34;outline-text-2&#34;&gt;
&lt;ul&gt;
&lt;li&gt;Finish &lt;a href=&#34;https://github.com/eigenhombre/weeds&#34;&gt;Weeds&lt;/a&gt; (redo of my blog software in CL)&lt;/li&gt;
&lt;li&gt;Port &lt;a href=&#34;https://github.com/eigenhombre/namejen&#34;&gt;namejen&lt;/a&gt; to CL&lt;/li&gt;
&lt;li&gt;Write a Roguelike&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
</description>
    </item>
    
    <item>
      <title>Implementing Scheme in Python</title>
      <link>http://johnj.com/posts/scheme-in-python/</link>
      <pubDate>Wed, 28 Aug 2019 00:00:00 +0000</pubDate>
      
      <guid>http://johnj.com/posts/scheme-in-python/</guid>
      <description>
&lt;p&gt;





&lt;a href=&#34;http://johnj.com/oewy.jpg&#34;&gt;&lt;img class=&#34;resize&#34; src=&#34;http://johnj.com/oewy_hu_ab424748ab8b3940.jpg&#34; style=&#34;width:700px; border:0px solid black;&#34;/&gt;&lt;/a&gt;

&lt;/p&gt;
&lt;div id=&#34;outline-container-headline-1&#34; class=&#34;outline-2&#34;&gt;
&lt;h2 id=&#34;headline-1&#34;&gt;
Background
&lt;/h2&gt;
&lt;div id=&#34;outline-text-headline-1&#34; class=&#34;outline-text-2&#34;&gt;
&lt;p&gt;
Lately I&amp;#39;ve been a bit of a Lisp kick again, reading &lt;em&gt;&lt;a href=&#34;http://www.paulgraham.com/onlisp.html&#34;&gt;On Lisp&lt;/a&gt;&lt;/em&gt; and
&lt;em&gt;&lt;a href=&#34;http://www.gigamonkeys.com/book/&#34;&gt;Practical Common Lisp&lt;/a&gt;&lt;/em&gt;, working &lt;a href=&#34;https://github.com/eigenhombre/99lisp/&#34;&gt;problems&lt;/a&gt; and &lt;a href=&#34;https://github.com/eigenhombre/weeds&#34;&gt;re-casting&lt;/a&gt; my
&lt;a href=&#34;https://github.com/eigenhombre/organa&#34;&gt;Clojure-based blog software&lt;/a&gt; into Common Lisp to see how that goes. The
urge to do these things caught me somewhat by surprise: in the past
few years I haven&amp;#39;t done much programming outside of my day job
because I&amp;#39;ve been focused more on painting and drawing. It seems,
though, that these things are cyclical and right now I&amp;#39;m in the grips
of Lisp mania again.&lt;/p&gt;
&lt;p&gt;
This cycle goes back to the mid-1980s when I was a college student
studying physics and learning how to program. It&amp;#39;s hard to say how I
got the Lisp bug initially. I remember reading &lt;a href=&#34;https://en.wikipedia.org/wiki/Metamagical_Themas&#34;&gt;Douglas Hofstadter&lt;/a&gt;&amp;#39;s
explanation of recursive Lisp functions; hanging out near the AI
workstations in the basement of the Madison Academic Computing Center
where I worked (the sans-serif Lisp program printouts looked way
better than anybody else&amp;#39;s output); and reading about AI and Lisp on
Usenet.  At any rate, I managed to pick up a copy of PC-Lisp, a port
of &lt;a href=&#34;https://en.wikipedia.org/wiki/Franz_Lisp&#34;&gt;Franz Lisp&lt;/a&gt; to IBM PCs which apparently &lt;a href=&#34;https://github.com/blakemcbride/PC-LISP&#34;&gt;is still a thing&lt;/a&gt; after all
these years. Somewhat astonishingly, the interpreter ran on my
underpowered &lt;a href=&#34;https://en.wikipedia.org/wiki/IBM_PCjr&#34;&gt;IBM PCjr&lt;/a&gt;, loading from floppy disk in half a minute or
so. I remember how even fairly small programs would pause for several
seconds while the garbage collector did its thing. This interpreter,
along with a Lisp textbook I picked up somewhere, was enough to get me
started learning about atoms, lists, &lt;code class=&#34;verbatim&#34;&gt;quote&lt;/code&gt;, &lt;code class=&#34;verbatim&#34;&gt;car&lt;/code&gt; and &lt;code class=&#34;verbatim&#34;&gt;cdr&lt;/code&gt;,
symbolic computing, and simple recursive algorithms.&lt;/p&gt;
&lt;p&gt;
I also wrote a small s-expression parser in &lt;a href=&#34;https://en.wikipedia.org/wiki/Turbo_Pascal&#34;&gt;Turbo Pascal&lt;/a&gt; on the same
PCjr as a way of graphing arbitrary math functions of two variables. I
had no compiler class but my roommate taught me enough about finite
state machines, lexers, parsers, etc. to be dangerous… enough
knowledge to get my grapher up and running. (I wish I still had some
of these old programs, but they vanished when I &amp;#34;lent&amp;#34; the computer
and all my diskettes to a friend; they are probably landfill
somewhere.)&lt;/p&gt;
&lt;p&gt;
This all subsided for several years while I got sucked into physics,
then painting, then capoeira, then physics, then painting, then
software engineering in C, Perl, and Python. In the early aughts I got
interested in Paul Graham&amp;#39;s &lt;a href=&#34;http://www.paulgraham.com/articles.html&#34;&gt;writing&lt;/a&gt;, which led to a few skirmishes
with Common Lisp every couple of years, and ultimately to me getting
totally hooked on Clojure starting in 2011.&lt;/p&gt;
&lt;p&gt;
I intend to write more about what makes Lisps in general compelling
for me&lt;sup class=&#34;footnote-reference&#34;&gt;&lt;a id=&#34;footnote-reference-1&#34; href=&#34;#footnote-1&#34;&gt;1&lt;/a&gt;&lt;/sup&gt; and why I&amp;#39;ve returned to it over and over throughout my
career. In the mean time….&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&#34;outline-container-headline-2&#34; class=&#34;outline-2&#34;&gt;
&lt;h2 id=&#34;headline-2&#34;&gt;
Scheming in Python
&lt;/h2&gt;
&lt;div id=&#34;outline-text-headline-2&#34; class=&#34;outline-text-2&#34;&gt;
&lt;p&gt;
Happily, my Lisp mania has crested coincidentally with Chicago Python
teacher David Beazley announcing another &lt;a href=&#34;https://www.dabeaz.com/sicp.html&#34;&gt;class&lt;/a&gt; on &lt;a href=&#34;https://en.wikipedia.org/wiki/Structure_and_Interpretation_of_Computer_Programs&#34;&gt;The Structure and
Interpretation of Computer Programs&lt;/a&gt;, a classic MIT computing text
based on a dialect of Lisp called Scheme, and I managed to get on the
list before it filled up. Since it&amp;#39;s been awhile since I&amp;#39;ve written
much Python, I thought I&amp;#39;d warm up for the class by trying to write &lt;a href=&#34;https://github.com/eigenhombre/smallscheme&#34;&gt;a
small Scheme implementation&lt;/a&gt; in Python. My hope was to refresh my
memory of the basics of Scheme, improve my slightly-dusty Python, and
have fun.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&#34;outline-container-headline-3&#34; class=&#34;outline-2&#34;&gt;
&lt;h2 id=&#34;headline-3&#34;&gt;
Prior Art
&lt;/h2&gt;
&lt;div id=&#34;outline-text-headline-3&#34; class=&#34;outline-text-2&#34;&gt;
&lt;p&gt;
Researching this post (after most of the code was done), I noticed
that there are a &lt;a href=&#34;https://www.biostat.wisc.edu/~annis/creations/PyLisp/&#34;&gt;ton&lt;/a&gt; &lt;a href=&#34;https://github.com/fogus/lithp&#34;&gt;of&lt;/a&gt; &lt;a href=&#34;http://petraszd-smallscheme.appspot.com/&#34;&gt;small&lt;/a&gt; &lt;a href=&#34;https://github.com/juliusf/schemePy&#34;&gt;Lisps&lt;/a&gt; &lt;a href=&#34;https://github.com/xielingwang/pyScheme&#34;&gt;written&lt;/a&gt; in Python (&lt;a href=&#34;https://github.com/eigenhombre/PyClojure&#34;&gt;including&lt;/a&gt; &lt;a href=&#34;https://github.com/drewr/clojure-py&#34;&gt;two&lt;/a&gt; I
worked on the better part of a decade ago). One that stuck out in my
memory was Peter Norvig&amp;#39;s hundred-odd-line &lt;a href=&#34;https://norvig.com/lispy.html&#34;&gt;Lispy&lt;/a&gt;, which is
particularly striking in its elegance (in style, it reminds me of the
Lisp programs in &lt;a href=&#34;https://github.com/norvig/paip-lisp&#34;&gt;PAIP&lt;/a&gt;).&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&#34;outline-container-headline-4&#34; class=&#34;outline-2&#34;&gt;
&lt;h2 id=&#34;headline-4&#34;&gt;
The Stages
&lt;/h2&gt;
&lt;div id=&#34;outline-text-headline-4&#34; class=&#34;outline-text-2&#34;&gt;
&lt;p&gt;My plan for writing the interpreter was to follow the actual REPL
stages: Read, Eval, and Print. &lt;em&gt;Read&lt;/em&gt; would involve parsing input
expressions and turning them into data structures to be evaluated;
&lt;em&gt;Eval&lt;/em&gt; would be a (presumably recursive) step whereby, for function
calls, arguments would be &lt;em&gt;Eval&lt;/em&gt;&amp;#39;ed first, with the results handed to
the appropriate code implementing the actual function, implemented
either in Python (for a few primitive functions) or, eventually,
through user-defined functions. An exception to the argument
evaluation rule would have to be made for a few &lt;em&gt;special forms&lt;/em&gt;, which
would have to be handled on a case-by-case basis.&lt;/p&gt;
&lt;div id=&#34;outline-container-headline-5&#34; class=&#34;outline-3&#34;&gt;
&lt;h3 id=&#34;headline-5&#34;&gt;
Parsing
&lt;/h3&gt;
&lt;div id=&#34;outline-text-headline-5&#34; class=&#34;outline-text-3&#34;&gt;
&lt;p&gt;My first approach for the parser was to use &lt;a href=&#34;https://www.dabeaz.com/ply/&#34;&gt;PLY&lt;/a&gt;, which I&amp;#39;ve used
before. Having been spoiled by the excellent &lt;a href=&#34;https://github.com/Engelberg/instaparse&#34;&gt;Instaparse&lt;/a&gt; library for
Clojure, upon returning to PLY I found the library&amp;#39;s interface
relatively clumsy and abstruse.&lt;/p&gt;
&lt;p&gt;
Then I thought I&amp;#39;d try a regex to parse everything, since Scheme&amp;#39;s
base syntax and grammar are so simple. The following regex actually
worked well for awhile:&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;pat = &amp;#34;&amp;#34;&amp;#34;^\s*\((?P&amp;lt;list&amp;gt;.*)\)$   # Something beginning/ending with parens, or
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;         |
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;         (?P&amp;lt;bool&amp;gt;(\#t|\#f))\s*  # A boolean true/false value, or
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;         |                       # An atom starting w/ a letter or arithmetic op:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;         (?P&amp;lt;atom&amp;gt;[a-zA-Z\+\-\*\/]+[a-zA-Z0-9\+\-\*\/]*)\s*
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;         |
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;         (?P&amp;lt;num&amp;gt;[0-9]+)\s*&amp;#34;&amp;#34;&amp;#34;   # Or, a positive natural number.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
(I had not gotten to negative or floating point numbers at this stage
of the project.)&lt;/p&gt;
&lt;p&gt;
Expressions of the form &lt;code class=&#34;verbatim&#34;&gt;(+ 1 2 (+ 1 1 1))&lt;/code&gt;, for example, parsed
correctly.  However, the regex didn&amp;#39;t handle lists that nested in
other than the last position, for example, &lt;code class=&#34;verbatim&#34;&gt;(+ (* 2 3) 4)&lt;/code&gt;. It might
be possible to do the whole problem with regular expressions, but at
this point I decided to look for a nice modern parser library that let
me write down the grammer in EBNF notation and simply returned a parse
tree when given a valid expression. I found &lt;a href=&#34;https://github.com/lark-parser/lark&#34;&gt;Lark&lt;/a&gt;, which is roughly as
featureful as Instaparse and worked well. Here&amp;#39;s the Lark grammar as
it currently stands:&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;start  : _exprs
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;_exprs : _e* _e
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;_e     : ATOM
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;       | _num
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;       | BOOL
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;       | list
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;TRUE   : &amp;#34;#t&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;FALSE  : &amp;#34;#f&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;BOOL   : TRUE | FALSE
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;list   : &amp;#34;(&amp;#34; _exprs? &amp;#34;)&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;INT    : /[-+]?[0-9]+/
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ATOM   : /[a-zA-Z]+[a-zA-Z0-9\-\?]*/
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;       | /[\*\/\=\&amp;gt;\&amp;lt;]/
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;       | /[\-\+](?![0-9])/
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;FLOAT  : /[-+]?[0-9]+\.[0-9]*/
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;_num   : INT | FLOAT
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;%import common.WS
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;%ignore WS&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Note that while libraries like Lark and Instaparse are a nice
way to turn out a powerful parser quickly, Norvig&amp;#39;s &lt;code class=&#34;verbatim&#34;&gt;lis.py&lt;/code&gt; just
splits the inputs on open/close parens and uses them to
increase/decrease nesting level as they appear. The approach to
parsing numbers is also elegant: try to parse it as an integer; if
that fails, as a float; otherwise, it&amp;#39;s a symbol (what my grammar
calls &lt;code class=&#34;verbatim&#34;&gt;ATOM&lt;/code&gt;). I suspect that using a &amp;#34;real&amp;#34; parser makes it easier to add more syntax to your language if needed, though.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&#34;outline-container-headline-6&#34; class=&#34;outline-3&#34;&gt;
&lt;h3 id=&#34;headline-6&#34;&gt;
Data Model
&lt;/h3&gt;
&lt;div id=&#34;outline-text-headline-6&#34; class=&#34;outline-text-3&#34;&gt;
&lt;p&gt;Once Lark parses an expression, I convert to my own internal
representation before evaluation (function &lt;a href=&#34;https://github.com/eigenhombre/smallscheme/blob/master/smallscheme/scheme.py#L52&#34;&gt;&lt;code class=&#34;verbatim&#34;&gt;convert_ast&lt;/code&gt;&lt;/a&gt;). I did not
use objects to represent lists, atoms, etc., but just simple tuples
and lists:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Data Type&lt;/th&gt;
&lt;th&gt;Example&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Atom&lt;/td&gt;
&lt;td&gt;&lt;code class=&#34;verbatim&#34;&gt;(&amp;#39;atom&amp;#39;, &amp;#39;foo&amp;#39;)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Boolean&lt;/td&gt;
&lt;td&gt;&lt;code class=&#34;verbatim&#34;&gt;(&amp;#39;bool&amp;#39;, True)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Int&lt;/td&gt;
&lt;td&gt;&lt;code class=&#34;verbatim&#34;&gt;(&amp;#39;int&amp;#39;, 123)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Float&lt;/td&gt;
&lt;td&gt;&lt;code class=&#34;verbatim&#34;&gt;(&amp;#39;float&amp;#39;, 3.14)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;List&lt;/td&gt;
&lt;td&gt;&lt;code class=&#34;verbatim&#34;&gt;(&amp;#39;list&amp;#39;, [(&amp;#39;atom&amp;#39;, &amp;#39;define&amp;#39;), (&amp;#39;atom&amp;#39;, &amp;#39;x&amp;#39;), (&amp;#39;int&amp;#39;, 3)])&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;It might be more idiomatic Python to use objects, but I&amp;#39;m more used to
thinking in terms of nested structures of base data types (lists,
tuples, dictionaries), which have the advantage of being easily
printable while debugging.&lt;/p&gt;
&lt;p&gt;
Here&amp;#39;s an example expression, parsed with Lark and then converted into
my internal representation:&lt;/p&gt;
&lt;div id=&#34;outline-container-headline-7&#34; class=&#34;outline-4&#34;&gt;
&lt;h4 id=&#34;headline-7&#34;&gt;
Scheme raw source
&lt;/h4&gt;
&lt;div id=&#34;outline-text-headline-7&#34; class=&#34;outline-text-4&#34;&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(define (abs x)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  (if (&amp;lt; x 0)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      (- x)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      x))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&#34;outline-container-headline-8&#34; class=&#34;outline-4&#34;&gt;
&lt;h4 id=&#34;headline-8&#34;&gt;
Lark output
&lt;/h4&gt;
&lt;div id=&#34;outline-text-headline-8&#34; class=&#34;outline-text-4&#34;&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Tree(start,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;     [Tree(list,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;           [Token(ATOM, &amp;#39;define&amp;#39;),
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            Tree(list,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                 [Token(ATOM, &amp;#39;abs&amp;#39;),
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                  Token(ATOM, &amp;#39;x&amp;#39;)]),
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            Tree(list, [Token(ATOM, &amp;#39;if&amp;#39;),
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                        Tree(list,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                             [Token(ATOM, &amp;#39;&amp;lt;&amp;#39;),
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                              Token(ATOM, &amp;#39;x&amp;#39;),
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                              Token(INT, &amp;#39;0&amp;#39;)]),
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                        Tree(list,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                             [Token(ATOM, &amp;#39;-&amp;#39;),
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                              Token(ATOM, &amp;#39;x&amp;#39;)]),
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                        Token(ATOM, &amp;#39;x&amp;#39;)])])])&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&#34;outline-container-headline-9&#34; class=&#34;outline-4&#34;&gt;
&lt;h4 id=&#34;headline-9&#34;&gt;
Internal representation used in the interpreter
&lt;/h4&gt;
&lt;div id=&#34;outline-text-headline-9&#34; class=&#34;outline-text-4&#34;&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;[(&amp;#39;list&amp;#39;, [(&amp;#39;atom&amp;#39;, &amp;#39;define&amp;#39;),
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;           (&amp;#39;list&amp;#39;, [(&amp;#39;atom&amp;#39;, &amp;#39;abs&amp;#39;),
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                     (&amp;#39;atom&amp;#39;, &amp;#39;x&amp;#39;)]),
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;           (&amp;#39;list&amp;#39;, [(&amp;#39;atom&amp;#39;, &amp;#39;if&amp;#39;),
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                     (&amp;#39;list&amp;#39;, [(&amp;#39;atom&amp;#39;, &amp;#39;&amp;lt;&amp;#39;),
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                               (&amp;#39;atom&amp;#39;, &amp;#39;x&amp;#39;),
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                               (&amp;#39;int&amp;#39;, 0)]),
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                     (&amp;#39;list&amp;#39;, [(&amp;#39;atom&amp;#39;, &amp;#39;-&amp;#39;),
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                               (&amp;#39;atom&amp;#39;, &amp;#39;x&amp;#39;)]),
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                     (&amp;#39;atom&amp;#39;, &amp;#39;x&amp;#39;)])])]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&#34;outline-container-headline-10&#34; class=&#34;outline-3&#34;&gt;
&lt;h3 id=&#34;headline-10&#34;&gt;
Evaluation
&lt;/h3&gt;
&lt;div id=&#34;outline-text-headline-10&#34; class=&#34;outline-text-3&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/eigenhombre/smallscheme/blob/master/smallscheme/scheme.py#L299&#34;&gt;Evaluation&lt;/a&gt; turned out, not surprisingly, to be where most of the work is; specifically, the individual cases for special forms. These were:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&#34;verbatim&#34;&gt;quote&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code class=&#34;verbatim&#34;&gt;cond&lt;/code&gt; / &lt;code class=&#34;verbatim&#34;&gt;if&lt;/code&gt; (I implemented these separately but, had I implemented
macros, I might implement one in terms of the other)&lt;/li&gt;
&lt;li&gt;&lt;code class=&#34;verbatim&#34;&gt;define&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code class=&#34;verbatim&#34;&gt;lambda&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code class=&#34;verbatim&#34;&gt;or&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code class=&#34;verbatim&#34;&gt;and&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Aside from these, there was code for normal function application rules, with a slight variance between internally-defined functions and functioned defined by the user with &lt;code class=&#34;verbatim&#34;&gt;define&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;
I did not, &lt;a href=&#34;http://www.paulgraham.com/rootsoflisp.html&#34;&gt;as Paul Graham did&lt;/a&gt;, attempt to find the minimal subset of language elements needed to bootstrap a complete Lisp, though that is certainly an interesting exercise. My goal was to get my tests green in a straightforward way, as described below.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&#34;outline-container-headline-11&#34; class=&#34;outline-3&#34;&gt;
&lt;h3 id=&#34;headline-11&#34;&gt;
Printing
&lt;/h3&gt;
&lt;div id=&#34;outline-text-headline-11&#34; class=&#34;outline-text-3&#34;&gt;
&lt;p&gt;
The &lt;em&gt;Print&lt;/em&gt; stage needed to convert the internal representation of the
evaluated result to a string, both for a user running a REPL, and for
my unit tests. This turned out to be simple enough that I can put the
entire function here:&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;def printable_value(ast):
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    k, v = ast
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    if k == &amp;#39;int&amp;#39; or k == &amp;#39;float&amp;#39;:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        return str(v)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    if k == &amp;#39;bool&amp;#39;:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        return {True: &amp;#34;#t&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                False: &amp;#34;#f&amp;#34;}.get(v)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    if k == &amp;#39;intproc&amp;#39;:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        return &amp;#34;Internal procedure &amp;#39;%s&amp;#39;&amp;#34; % v
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    if k == &amp;#39;atom&amp;#39;:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        return v
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    if k == &amp;#39;list&amp;#39;:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        return &amp;#39;(&amp;#39; + &amp;#39; &amp;#39;.join([printable_value(x)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                               for x in v]) + &amp;#39;)&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    if k == &amp;#39;nop&amp;#39;:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        return &amp;#39;&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    if k == &amp;#39;fn&amp;#39;:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        (fn_name, _, _) = v
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        if fn_name == &amp;#39;lambda&amp;#39;:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            return &amp;#34;Anonymous-function&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        return &amp;#34;Function-&amp;#39;%s&amp;#39;&amp;#34; % str(fn_name)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    raise Exception(&amp;#39;Unprintable ast &amp;#34;%s&amp;#34;&amp;#39; % str(ast))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
The primitive data types (&lt;code class=&#34;verbatim&#34;&gt;int&lt;/code&gt;, &lt;code class=&#34;verbatim&#34;&gt;float&lt;/code&gt;, &lt;code class=&#34;verbatim&#34;&gt;bool&lt;/code&gt; and &lt;code class=&#34;verbatim&#34;&gt;atom&lt;/code&gt;) are
obvious enough; &lt;code class=&#34;verbatim&#34;&gt;intproc&lt;/code&gt; and &lt;code class=&#34;verbatim&#34;&gt;fn&lt;/code&gt; are for internally-defined and
user-defined functions, respectively; finally, &lt;code class=&#34;verbatim&#34;&gt;nop&lt;/code&gt; is for when you
don&amp;#39;t want any value shown to the user (i.e., after one enters a
&lt;code class=&#34;verbatim&#34;&gt;define&lt;/code&gt; expression, there is no output printed before the next
prompt):&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;scheme&amp;gt; (define a 3)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;scheme&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&#34;outline-container-headline-12&#34; class=&#34;outline-3&#34;&gt;
&lt;h3 id=&#34;headline-12&#34;&gt;
Testing Approach
&lt;/h3&gt;
&lt;div id=&#34;outline-text-headline-12&#34; class=&#34;outline-text-3&#34;&gt;
&lt;p&gt;I used a fairly strict test-driven development workflow for this
project: write just enough new test code to fail; write just enough
production code to get the test to pass; then refactor. This workflow
generally serves me well for harder problems where I&amp;#39;m unlikely to see
the best way to do things from the outset and I expect to make many
improvements: I know the tests will have my back when I make
changes. This turned out to be the right approach, since I had to
pivot several times.&lt;/p&gt;
&lt;p&gt;
I didn&amp;#39;t just use tests drive the code forward, but let SICP drive the
&lt;em&gt;tests&lt;/em&gt; forward as well. When I needed the next thing to work on, all
I had to do was turn forward a few pages in the book, and the page
count gave me a measure of my progress.&lt;/p&gt;
&lt;p&gt;
A few of the tests, with the corresponding page numbers:&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    # Adapted from SICP p. 8:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    t(&amp;#34;(define pi 3.14159)&amp;#34;)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    t(&amp;#34;(define radius 10)&amp;#34;)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    t(&amp;#34;(* pi (* radius radius))&amp;#34;, &amp;#34;314.159&amp;#34;)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    ...
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    # p. 19:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    t(&amp;#34;(define x 7)&amp;#34;)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    t(&amp;#34;(and (&amp;gt; x 5) (&amp;lt; x 10))&amp;#34;, &amp;#34;#t&amp;#34;)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    ...
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    # p. 37
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    t(&amp;#34;&amp;#34;&amp;#34;(define (fib n)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;           (cond ((= n 0) 0)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                 ((= n 1) 1)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                 (else (+ (fib (- n 1))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                          (fib (- n 2))))))&amp;#34;&amp;#34;&amp;#34;)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    t(&amp;#34;(fib 5)&amp;#34;, &amp;#34;5&amp;#34;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
Here &lt;code class=&#34;verbatim&#34;&gt;t&lt;/code&gt; (a very short function name since it&amp;#39;s used so many times) is
a testing function which evaluates the code supplied in the first
argument, using the current &amp;#34;environment&amp;#34; (scope). If a second argument
(a string) is supplied, it also asserts that the code in the first
argument evaluates to the second.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&#34;outline-container-headline-13&#34; class=&#34;outline-3&#34;&gt;
&lt;h3 id=&#34;headline-13&#34;&gt;
The Code Comes To Life
&lt;/h3&gt;
&lt;div id=&#34;outline-text-headline-13&#34; class=&#34;outline-text-3&#34;&gt;
&lt;p&gt;One of my favorite things about this project was when I started
writing nontrivial tests which &lt;em&gt;already passed&lt;/em&gt;, because enough of the
language had been implemented already. This happened more often as the
project progressed, and it made me feel like I&amp;#39;d implemented a &amp;#34;real&amp;#34;
language, an oddly compelling feeling.&lt;/p&gt;
&lt;p&gt;
The code, in its entirety, can be found &lt;a href=&#34;https://github.com/eigenhombre/smallscheme&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&#34;outline-container-headline-14&#34; class=&#34;outline-2&#34;&gt;
&lt;h2 id=&#34;headline-14&#34;&gt;
Next Steps
&lt;/h2&gt;
&lt;div id=&#34;outline-text-headline-14&#34; class=&#34;outline-text-2&#34;&gt;
&lt;p&gt;Though I have already gone far past my goals for the project, there are a few directions which I could take this.&lt;/p&gt;
&lt;div id=&#34;outline-container-headline-15&#34; class=&#34;outline-3&#34;&gt;
&lt;h3 id=&#34;headline-15&#34;&gt;
Implement more of Scheme
&lt;/h3&gt;
&lt;div id=&#34;outline-text-headline-15&#34; class=&#34;outline-text-3&#34;&gt;
&lt;p&gt;For example, I don&amp;#39;t have strings yet in my implementation!&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&#34;outline-container-headline-16&#34; class=&#34;outline-3&#34;&gt;
&lt;h3 id=&#34;headline-16&#34;&gt;
Extend it Further
&lt;/h3&gt;
&lt;div id=&#34;outline-text-headline-16&#34; class=&#34;outline-text-3&#34;&gt;
&lt;p&gt;Implement Python interop and shell features. This could be genuinely
fun and useful, but there&amp;#39;s already &lt;a href=&#34;https://github.com/hylang/hy&#34;&gt;a fairly full-featured Lisp skin
for Python called Hy&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&#34;outline-container-headline-17&#34; class=&#34;outline-3&#34;&gt;
&lt;h3 id=&#34;headline-17&#34;&gt;
Go Low Level
&lt;/h3&gt;
&lt;div id=&#34;outline-text-headline-17&#34; class=&#34;outline-text-3&#34;&gt;
&lt;p&gt;Do it again, but in a faster, lower-level language. Python is
relatively slow compared to Clojure for long-running programs, and
slower than Common Lisp or C for program startup. I&amp;#39;ve been wanting to
dust off my C chops, and this would be an excuse to do so, though C is
a bit primitive compared to, say, Rust. (Go is not to my taste so I
wouldn&amp;#39;t pick it for a fun project like this one.) So, either an
excuse to learn Rust or to improve my C chops. Which leads me to the
final question: would I rather implement Lisps, or program in them? Up
until now it has been the latter, but after the past few weeks I can
definitely taste the appeal of the former.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&#34;outline-container-headline-18&#34; class=&#34;outline-2&#34;&gt;
&lt;h2 id=&#34;headline-18&#34;&gt;
Thoughts Upon Revisiting Python
&lt;/h2&gt;
&lt;div id=&#34;outline-text-headline-18&#34; class=&#34;outline-text-2&#34;&gt;
&lt;p&gt;This was the biggest Python project I&amp;#39;ve done in five years, so it was
interesting to check my experience of the language after some time
away in Clojure-land. I was a big Python fan for many years but my
enthusiasm for the language has definitely cooled. This is partly due to the performance comparison I just mentioned, but the two other things I really missed were REPL integration and structural editing.&lt;/p&gt;
&lt;p&gt;
In Lisps such as Clojure and Common Lisp I can send expressions to the
REPL directly from Emacs and see the results instantly. It&amp;#39;s difficult
to describe how helpful this short feedback cycle is until you&amp;#39;ve
experienced it. Writing the interpreter, I got sort of close by using
&lt;a href=&#34;https://github.com/eigenhombre/continuous-testing-helper&#34;&gt;&lt;code class=&#34;verbatim&#34;&gt;conttest&lt;/code&gt;&lt;/a&gt; plus &lt;code class=&#34;verbatim&#34;&gt;nosetests&lt;/code&gt;: my unit tests ran every time I saved
a source file, and if I wanted to inspect some object I could add a
&lt;code class=&#34;verbatim&#34;&gt;print&lt;/code&gt; or two temporarily to the code I was working on. But this is
definitely more clumsy than a Lisp REPL directly integrated with my editor.&lt;/p&gt;
&lt;p&gt;
Structural editing (via &lt;a href=&#34;http://danmidwood.com/content/2014/11/21/animated-paredit.html&#34;&gt;Paredit&lt;/a&gt;) is another thing that is hard to
explain the utility of but which is hard to live without once you&amp;#39;re
used to it.  The basic idea is that you are no longer editing strings
of text, but the actual tree of nested lists comprising your code -
killing, splitting, joining, absorbing (&amp;#34;slurping&amp;#34;) into and expelling
(&amp;#34;barfing&amp;#34;) from those lists.  Working with the code at the tree level
is a powerful way to edit your code, and &lt;a href=&#34;https://www.youtube.com/watch?v=D6h5dFyyUX0&#34;&gt;watching this video might
help&lt;/a&gt; may give a hint of it. Once you&amp;#39;re used to the affordances of
Paredit or its cousins, it feels clunky and primitive to go back to
editing plain old text.&lt;/p&gt;
&lt;p&gt;
Other value propositions of Clojure, such as macros, immutable
data structures and concurrency, weren&amp;#39;t really an issue for this
project, though I would certainly miss them for bigger projects.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&#34;outline-container-headline-19&#34; class=&#34;outline-2&#34;&gt;
&lt;h2 id=&#34;headline-19&#34;&gt;
Conclusion
&lt;/h2&gt;
&lt;div id=&#34;outline-text-headline-19&#34; class=&#34;outline-text-2&#34;&gt;
&lt;p&gt;
Implementing your own Lisp is surprisingly do-able (and fun!). Python
is certainly a fine tool for the job (though if you want to skip straight to programming in a modern Lisp for your day job, please &lt;a href=&#34;http://johnj.com/contact.html&#34;&gt;contact me&lt;/a&gt;).&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&#34;outline-container-headline-20&#34; class=&#34;outline-2&#34;&gt;
&lt;h2 id=&#34;headline-20&#34;&gt;
Postscript
&lt;/h2&gt;
&lt;div id=&#34;outline-text-headline-20&#34; class=&#34;outline-text-2&#34;&gt;
&lt;p&gt;
While digging through my digital and mental archives for Lisp things I remembered something I hadn&amp;#39;t seen in a long time: the use of closing square brackets to terminate a deeply-nested collection of s-expressions (i.e. &lt;code class=&#34;verbatim&#34;&gt;]&lt;/code&gt; instead of &lt;code class=&#34;verbatim&#34;&gt;)))))))&lt;/code&gt;). Did I imagine it? While not necessarily a good idea, it&amp;#39;s an interesting one. Then, while reading through Gabriel and Steele&amp;#39;s &lt;a href=&#34;https://dl.acm.org/citation.cfm?id=155373&#34;&gt;Evolution of Lisp&lt;/a&gt; this morning, I came across the following snippet:&lt;/p&gt;
&lt;p&gt;
&amp;#34;One of the minor, but interesting, syntactic extensions that
Interlisp made was the introduction of the superparenthesis, or
superbracket. If a right square bracket &lt;code class=&#34;verbatim&#34;&gt;]&lt;/code&gt; is encountered during a
read operation, it balances all outstanding open left parentheses, or
back to the last outstanding left square bracket &lt;code class=&#34;verbatim&#34;&gt;[&lt;/code&gt;.&amp;#34;&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;DEFINEQ((FACTORIAL
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  (LAMBDA (N)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   (COND [(ZEROP N) 1]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;         (T (TIMES N (FACTORIAL (SUB1 N]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
Bingo! I wasn&amp;#39;t imagining it.  This suggests those workstations in the
basement of MACC at UW-Madison were probably running Interlisp.&lt;/p&gt;
&lt;p&gt;





&lt;a href=&#34;http://johnj.com/for-the-trees.png&#34;&gt;&lt;img class=&#34;resize&#34; src=&#34;http://johnj.com/for-the-trees_hu_895555d88ddbe0d5.png&#34; style=&#34;width:700px; border:0px solid black;&#34;/&gt;&lt;/a&gt;

&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;footnotes&#34;&gt;
&lt;hr class=&#34;footnotes-separatator&#34;&gt;
&lt;div class=&#34;footnote-definitions&#34;&gt;
&lt;div class=&#34;footnote-definition&#34;&gt;
&lt;sup id=&#34;footnote-1&#34;&gt;&lt;a href=&#34;#footnote-reference-1&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;
&lt;div class=&#34;footnote-body&#34;&gt;
&lt;p&gt;So compelling that I left &lt;a href=&#34;https://icecube.wisc.edu&#34;&gt;an exciting science project&lt;/a&gt;
partly in order to do Lisp (Clojure) programming full time.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
</description>
    </item>
    
    <item>
      <title>Code and Data</title>
      <link>http://johnj.com/posts/code-and-data/</link>
      <pubDate>Mon, 04 Jun 2018 00:00:00 +0000</pubDate>
      
      <guid>http://johnj.com/posts/code-and-data/</guid>
      <description>
&lt;p&gt;





&lt;a href=&#34;http://johnj.com/thin-ice.png&#34;&gt;&lt;img class=&#34;resize&#34; src=&#34;http://johnj.com/thin-ice_hu_2c5da9487f484be.png&#34; style=&#34;width:700px; border:0px solid black;&#34;/&gt;&lt;/a&gt;

&lt;/p&gt;
&lt;div id=&#34;outline-container-headline-1&#34; class=&#34;outline-2&#34;&gt;
&lt;h2 id=&#34;headline-1&#34;&gt;
Introduction
&lt;/h2&gt;
&lt;div id=&#34;outline-text-headline-1&#34; class=&#34;outline-text-2&#34;&gt;
&lt;p&gt;
&lt;em&gt;This article was adapted from discussions we had at the weekly
Clojure study group at OpinionLab, in June, 2018.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;
Clojure is a Lisp.  Code is data in Lisp, and data can also be
code. Lisp code consists of lists of symbols (or atoms, as they are
called in other Lisps), other data primitives such as numbers and
keywords, or (nested) lists of the same.&lt;sup class=&#34;footnote-reference&#34;&gt;&lt;a id=&#34;footnote-reference-1&#34; href=&#34;#footnote-1&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;
The first item in an expression (list) is the name of an operation,
usually a function; the rest of the items are the arguments. When
lists are nested, the inner expressions are evaluated first: in &lt;code class=&#34;verbatim&#34;&gt;(+ 1
(* 2 3))&lt;/code&gt;, the multiplication happens before the addition.&lt;/p&gt;
&lt;p&gt;
Somewhat less commonly, instead of function names, the first item in
the list may be the name of a macro or so-called &amp;#34;special form.&amp;#34;  In
these cases, the exact method of evaluation depends on the
implementation of the macro or form. For example, in &lt;code class=&#34;verbatim&#34;&gt;(dotimes [_ 10]
(println &amp;#39;hi))&lt;/code&gt;, the &lt;code class=&#34;verbatim&#34;&gt;println&lt;/code&gt; is evaluated 10 times; if &lt;code class=&#34;verbatim&#34;&gt;dotimes&lt;/code&gt;
were a function, &lt;code class=&#34;verbatim&#34;&gt;println&lt;/code&gt; would be evaluated exactly once.&lt;/p&gt;
&lt;p&gt;
To prevent evaluation of an expression, one can &lt;code class=&#34;verbatim&#34;&gt;quote&lt;/code&gt; it:&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(quote (+ 1 (* 2 3)))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;;=&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(+ 1 (* 2 3))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
The single quote (&amp;#39;) character is an abbreviation for &lt;code class=&#34;verbatim&#34;&gt;quote&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&amp;#39;(+ 1 (* 2 3))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;;=&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(+ 1 (* 2 3))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
The REPL will evaluate expressions unless you quote them; if you
decide later you want to evaluate an expression, you can use &lt;code class=&#34;verbatim&#34;&gt;eval&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(def expr &amp;#39;(+ 1 (* 2 3)))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(eval expr)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;;=&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;7&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
Quoting and evaluation are inverse operations:&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(eval (eval (eval (eval &amp;#39;&amp;#39;&amp;#39;&amp;#39;(+ 1 (* 2 3))))))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;;=&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;7&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
Here are some examples you should try at the REPL, to help build an
understanding of these two operations:&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(+ 1 1)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&amp;#39;+
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;+
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&amp;#39;(+ 1 1)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(cons &amp;#39;+ &amp;#39;(1 1))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(eval (cons &amp;#39;+ &amp;#39;(1 1)))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(first &amp;#39;(+ - * /))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(cons (first &amp;#39;(+ - * /)) &amp;#39;(1 1))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(eval (cons (first &amp;#39;(+ - * /)) (rest &amp;#39;(not-a-number 1 1))))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(-&amp;gt;&amp;gt; &amp;#39;(not-a-number 1 1)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;     rest
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;     (cons (first &amp;#39;(+ - * /)))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;     eval)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
Try to understand each of these as best you can, and try some
variations.  The last expression is the same as the one prior to it,
just rewritten using the thread-last (&lt;code class=&#34;verbatim&#34;&gt;-&amp;gt;&amp;gt;&lt;/code&gt;) macro.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&#34;outline-container-headline-2&#34; class=&#34;outline-2&#34;&gt;
&lt;h2 id=&#34;headline-2&#34;&gt;
Arithmetic of the Fittest
&lt;/h2&gt;
&lt;div id=&#34;outline-text-headline-2&#34; class=&#34;outline-text-2&#34;&gt;
&lt;p&gt;
The close relationship of code and data suggests making new code on
the fly to solve problems, which is a concept used in
&lt;a href=&#34;https://en.wikipedia.org/wiki/Genetic_algorithm&#34;&gt;genetic algorithms&lt;/a&gt;.  Here is an example inspired by GAs.  Let&amp;#39;s write
a function which &lt;em&gt;finds expressions involving the four arithmetic
operators that return the number 2.&lt;/em&gt; Examples:&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(+ 1 1)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(- 4 2)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(* 1 2)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(/ 2 1)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
First, let&amp;#39;s make our expression generator (type or copy-paste into your REPL):&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(defn oper [] (rand-nth &amp;#39;(* / - +)))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(defn digit [] (rand-int 10))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(defn numlist []
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  (let [numnums (rand-int 10)]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    (repeatedly numnums digit)))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(defn expr-fn []
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  (cons (oper) (numlist)))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
Trying these out:&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(oper)    ;;=&amp;gt; *
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(oper)    ;;=&amp;gt; /
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(numlist) ;;=&amp;gt; (6)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(numlist) ;;=&amp;gt; (6 9 3 4 4 2 4 3 2)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(expr-fn) ;;=&amp;gt; (/ 6 1 3 7 0 3 0 9)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(expr-fn) ;;=&amp;gt; (- 5 7 2)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
Our expression generator selects an arithmetic operator at random, and
tacks it on to the beginning of a random list of 0-9 digits.&lt;/p&gt;
&lt;p&gt;
Evaluating some example functions:&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(eval (expr-fn)) ;;=&amp;gt; 0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(eval (expr-fn)) ;;=&amp;gt; 41
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(eval (expr-fn)) ;;=&amp;gt; 7/1152
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(eval (expr-fn)) ;;=&amp;gt; java.lang.ArithmeticException stacktrace!?!?!&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
This last one shows a problem: some of our expressions will not be
valid mathematically (for example, &lt;code class=&#34;verbatim&#34;&gt;(/ 1 0)&lt;/code&gt;). Let&amp;#39;s catch any exceptions:&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(defn eval-with-catch-exception [expr]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  (try
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    (eval expr)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    (catch Throwable t
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      (-&amp;gt; t .getClass .getSimpleName symbol))))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
This function attempts to evaluate &lt;code class=&#34;verbatim&#34;&gt;expr&lt;/code&gt; and, if the code throws an
exception, simply returns the exception name as a symbol.&lt;/p&gt;
&lt;p&gt;
We are now in a position to try our code generator out:&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(dotimes [_ 10]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  (let [e (expr-fn)]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    (println e (eval-with-catch-exception e))))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
which gives&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(/ 9 8 7 0 0 7 2 2 6) ArithmeticException
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(+ 1 3 3 0 7 7 6) 27
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(+ 4 2) 6
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(- 4 1 2 1 0 0 0) 0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(/ 5 7 0 7) ArithmeticException
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(* 0 4 6) 0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(* 8 6 7 2 4 1) 2688
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(* 7 4 6 9 8 6) 72576
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(*) 1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(- 7) -7&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
(&lt;code class=&#34;verbatim&#34;&gt;*&lt;/code&gt; called with no arguments returns 1; &lt;code class=&#34;verbatim&#34;&gt;+&lt;/code&gt; with no arguments returns 0. This may or
may not make intuitive sense to you, depending on how much math you&amp;#39;ve had in
school.)&lt;/p&gt;
&lt;p&gt;
Let&amp;#39;s generate some that return the desired result, 2:&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(distinct
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; (for [_ (range 1000)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;       :let [f (expr-fn)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;             result (eval-with-catch-exception f)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;             fitness-fn #(= result 2)]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;       :when (fitness-fn)]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   f))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;;=&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;((+ 2)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; (- 9 1 1 1 4)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; (- 2 0)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; (/ 4 2)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; (/ 2 1)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; (* 2))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
(Note that &lt;code class=&#34;verbatim&#34;&gt;(+ n)&lt;/code&gt; and &lt;code class=&#34;verbatim&#34;&gt;(* n)&lt;/code&gt; both just return &lt;code class=&#34;verbatim&#34;&gt;n&lt;/code&gt;.)&lt;/p&gt;
&lt;div id=&#34;outline-container-headline-3&#34; class=&#34;outline-3&#34;&gt;
&lt;h3 id=&#34;headline-3&#34;&gt;
Macros
&lt;/h3&gt;
&lt;div id=&#34;outline-text-headline-3&#34; class=&#34;outline-text-3&#34;&gt;
&lt;p&gt;
Macros are an advanced topic, but they are relevant because they allow
(among other things) selective evaluation of arguments. Arguments to a
macro can be evaluated zero, one, or many times; this makes macros
especially helpful for implementing control flow: &lt;code class=&#34;verbatim&#34;&gt;loop&lt;/code&gt;, &lt;code class=&#34;verbatim&#34;&gt;for&lt;/code&gt;,
&lt;code class=&#34;verbatim&#34;&gt;while&lt;/code&gt; etc. are all macros.&lt;/p&gt;
&lt;p&gt;
Macros rely on code-as-data: they essentially functions which generate
code, which is then evaluated. Most or all modern Lisps have macros,
the equivalent of which are very rare in non-Lisps. These macros play
a large role in making Lisp so expressive.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&#34;outline-container-headline-4&#34; class=&#34;outline-3&#34;&gt;
&lt;h3 id=&#34;headline-4&#34;&gt;
Exercises
&lt;/h3&gt;
&lt;div id=&#34;outline-text-headline-4&#34; class=&#34;outline-text-3&#34;&gt;
&lt;p&gt;
&lt;strong&gt;Exercise 1&lt;/strong&gt;: Creating and evaluating code on the fly in this manner
is not unique to Lisp, but Lisp provides a very natural way to do
so. Consider how to do the above examples in JavaScript, Ruby, or
other mainstream languages. What, if any, are the differences between
Clojure/Lisp and those languages?&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;Exercise 2&lt;/strong&gt;: Set a different arithmetic goal (other than &lt;code class=&#34;verbatim&#34;&gt;2&lt;/code&gt;) and
generate expressions which satisfy it.&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;Exercise 3&lt;/strong&gt;: Adapt your code generator to include nested expressions,
so that some of the numbers are generated expressions in their own
right.  Example: &lt;code class=&#34;verbatim&#34;&gt;(+ 1 4) -&amp;gt; (+ 1 (* 2 2))&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;Exercise 4&lt;/strong&gt;: Instead of generating expressions, adapt &lt;code class=&#34;verbatim&#34;&gt;expr-fn&lt;/code&gt; to
return &lt;em&gt;functions&lt;/em&gt; of no arguments, and adapt the rest of the code to
call and evaluate those functions.  I.e., &lt;code class=&#34;verbatim&#34;&gt;(+ 1 2 3)&lt;/code&gt; becomes &lt;code class=&#34;verbatim&#34;&gt;(fn []
(+ 1 2 3))&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;Exercise 5 (advanced)&lt;/strong&gt;: Both the generated functions and the &amp;#34;fitness function&amp;#34;
&lt;code class=&#34;verbatim&#34;&gt;fitness-fn&lt;/code&gt; can be made more complex; for example, in addition to the
operators &lt;code class=&#34;verbatim&#34;&gt;+ - * /&lt;/code&gt; and the numbers 0-9, you could add an &amp;#34;argument&amp;#34;
variable &lt;code class=&#34;verbatim&#34;&gt;x&lt;/code&gt; and change the fitness function to expect expressions
that return the square of &lt;code class=&#34;verbatim&#34;&gt;x&lt;/code&gt;; some acceptable outputs would
then be &lt;code class=&#34;verbatim&#34;&gt;(* x x)&lt;/code&gt; and &lt;code class=&#34;verbatim&#34;&gt;(* 1 x x 1)&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;
Change your expression generator and fitness functions to implement
the squaring function.&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;Exercise 6 (advanced)&lt;/strong&gt;: try adding other Clojure core functions and
data types to the list of possible operators and arguments; try other
fitness functions as well.&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;Exercise 7 (more advanced)&lt;/strong&gt;: develop a way of combining expressions
and evaluating the fitness of the resulting expression. To build on
our previous example, if you have the two lists &lt;code class=&#34;verbatim&#34;&gt;(+ 1 1)&lt;/code&gt; and &lt;code class=&#34;verbatim&#34;&gt;(* 2
3)&lt;/code&gt;, you could choose terms at random from each list, e.g. &lt;code class=&#34;verbatim&#34;&gt;(* 1 3)&lt;/code&gt;;
you must decide how to handle lists with different lengths.  The
fitness function could just be &lt;code class=&#34;verbatim&#34;&gt;fitness-fn&lt;/code&gt; from our example, or a
more ambitious one&lt;sup class=&#34;footnote-reference&#34;&gt;&lt;a id=&#34;footnote-reference-2&#34; href=&#34;#footnote-2&#34;&gt;2&lt;/a&gt;&lt;/sup&gt;. If you want to include nested
expressions, then you have to decide how to combine those.&lt;/p&gt;
&lt;p&gt;
Rather than success or failure, the fitness function could return a
number which reflects how well or poorly the expression performed. A
strategy from genetic algorithms is to generate many expressions,
evaluate these, take the best performers, and then generate new
expressions by combining these. Implement this.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&#34;outline-container-headline-5&#34; class=&#34;outline-3&#34;&gt;
&lt;h3 id=&#34;headline-5&#34;&gt;
See Also
&lt;/h3&gt;
&lt;div id=&#34;outline-text-headline-5&#34; class=&#34;outline-text-3&#34;&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.youtube.com/watch?reload%3D9&amp;amp;v%3Der_lLvkklsk&#34;&gt;This freaking amazing
talk&lt;/a&gt;&lt;sup class=&#34;footnote-reference&#34;&gt;&lt;a id=&#34;footnote-reference-3&#34; href=&#34;#footnote-3&#34;&gt;3&lt;/a&gt;&lt;/sup&gt; given
by William Byrd and Greg Rosenblatt on program synthesis, given at
Clojure/conj 2016.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://en.wikipedia.org/wiki/Genetic_algorithm&#34;&gt;Genetic Algorithms&lt;/a&gt; on Wikipedia&lt;sup class=&#34;footnote-reference&#34;&gt;&lt;a id=&#34;footnote-reference-4&#34; href=&#34;#footnote-4&#34;&gt;4&lt;/a&gt;&lt;/sup&gt;.&lt;/li&gt;
&lt;li&gt;Colin Jones&amp;#39;s excellent &lt;a href=&#34;https://pragprog.com/book/cjclojure/mastering-clojure-macros&#34;&gt;book on macros&lt;/a&gt;&lt;sup class=&#34;footnote-reference&#34;&gt;&lt;a id=&#34;footnote-reference-5&#34; href=&#34;#footnote-5&#34;&gt;5&lt;/a&gt;&lt;/sup&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;footnotes&#34;&gt;
&lt;hr class=&#34;footnotes-separatator&#34;&gt;
&lt;div class=&#34;footnote-definitions&#34;&gt;
&lt;div class=&#34;footnote-definition&#34;&gt;
&lt;sup id=&#34;footnote-1&#34;&gt;&lt;a href=&#34;#footnote-reference-1&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;
&lt;div class=&#34;footnote-body&#34;&gt;
&lt;p&gt;Other collection types in Clojure are ignored in this post.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;footnote-definition&#34;&gt;
&lt;sup id=&#34;footnote-2&#34;&gt;&lt;a href=&#34;#footnote-reference-2&#34;&gt;2&lt;/a&gt;&lt;/sup&gt;
&lt;div class=&#34;footnote-body&#34;&gt;
&lt;p&gt;like, say, returning a list of the first million or so prime numbers&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;footnote-definition&#34;&gt;
&lt;sup id=&#34;footnote-3&#34;&gt;&lt;a href=&#34;#footnote-reference-3&#34;&gt;3&lt;/a&gt;&lt;/sup&gt;
&lt;div class=&#34;footnote-body&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://www.youtube.com/watch?reload=9&amp;amp;v=er_lLvkklsk&#34;&gt;https://www.youtube.com/watch?reload=9&amp;amp;v=er_lLvkklsk&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;footnote-definition&#34;&gt;
&lt;sup id=&#34;footnote-4&#34;&gt;&lt;a href=&#34;#footnote-reference-4&#34;&gt;4&lt;/a&gt;&lt;/sup&gt;
&lt;div class=&#34;footnote-body&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://en.wikipedia.org/wiki/Genetic_algorithm&#34;&gt;https://en.wikipedia.org/wiki/Genetic_algorithm&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;footnote-definition&#34;&gt;
&lt;sup id=&#34;footnote-5&#34;&gt;&lt;a href=&#34;#footnote-reference-5&#34;&gt;5&lt;/a&gt;&lt;/sup&gt;
&lt;div class=&#34;footnote-body&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://pragprog.com/book/cjclojure/mastering-clojure-macros&#34;&gt;https://pragprog.com/book/cjclojure/mastering-clojure-macros&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
</description>
    </item>
    
    <item>
      <title>(oodles of delicious atoms)</title>
      <link>http://johnj.com/posts/oodles/</link>
      <pubDate>Wed, 30 May 2018 00:00:00 +0000</pubDate>
      
      <guid>http://johnj.com/posts/oodles/</guid>
      <description>
&lt;div id=&#34;outline-container-headline-1&#34; class=&#34;outline-2&#34;&gt;
&lt;h2 id=&#34;headline-1&#34;&gt;
A Recursive Feast
&lt;/h2&gt;
&lt;div id=&#34;outline-text-headline-1&#34; class=&#34;outline-text-2&#34;&gt;
&lt;p&gt;
In 1983, Douglas R. Hofstadter, author of &amp;#34;Gödel, Escher, Bach: An
Eternal Golden Braid&amp;#34; wrote a series of articles on Lisp in Scientific
American (later republished in the book &lt;a href=&#34;https://en.wikipedia.org/wiki/Metamagical_Themas&#34;&gt;Metamagical Themas&lt;/a&gt;, which is
where I encountered them for the first time).  While much of the
writing focused on the nature of recursion in programming, the third
and last article in the series provided an entertaining example of
blurring the line between code and data, which is typical for Lisp
(though somewhat less common in Clojure, except for the occasional
macro).&lt;/p&gt;
&lt;p&gt;
In the example, a set of acronyms are presented; each acronym can be
&amp;#34;expanded&amp;#34; into a phrase which itself may contain other acronyms.
The program generates random expansions of these acronyms, &amp;#34;bottoming
out&amp;#34; (hitting the base case) at random, though with increasing
probability of termination for more deeply-nested expressions.&lt;/p&gt;
&lt;p&gt;
What follows is my translation of the Lisp code in his articles into
Clojure, with a few extra details and explanations.  A few interesting
edge cases have to be accounted for to accommodate the differences
between the languages.&lt;/p&gt;
&lt;p&gt;
If you&amp;#39;re interested in running the code, it&amp;#39;s &lt;a href=&#34;https://github.com/eigenhombre/oodles&#34;&gt;on GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&#34;outline-container-headline-2&#34; class=&#34;outline-2&#34;&gt;
&lt;h2 id=&#34;headline-2&#34;&gt;
Cooking It Up
&lt;/h2&gt;
&lt;div id=&#34;outline-text-headline-2&#34; class=&#34;outline-text-2&#34;&gt;
&lt;p&gt;
First, a small macro helps us keep things tidy: &lt;code class=&#34;verbatim&#34;&gt;defpasta&lt;/code&gt; makes a
function that simply returns the list supplied as its argument,
avoiding the need for the argument vector or the quote.  Note that
just one small macro provides enough &amp;#34;syntactic sugar&amp;#34; to make the
examples more readable.  We also attach metadata for convenience in
testing (see below).&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(defmacro defpasta [name_ &amp;amp; expr]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  `(defn ~(with-meta name_ {:pasta true}) []
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;     &amp;#39;~@expr))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
Next are the actual acronym definitions. These are the definitions
Hofstadter uses, with commas treated differently.  The commas are
important in his output, but commas are whitespace in Clojure… so
where the symbols are used with commas in compound statements, we
append &lt;code class=&#34;verbatim&#34;&gt;_CO&lt;/code&gt; to tell the program to supply a comma in the output.
(Example: &lt;code class=&#34;verbatim&#34;&gt;SAUCE,&lt;/code&gt; becomes &lt;code class=&#34;verbatim&#34;&gt;SAUCE_CO&lt;/code&gt;.)&lt;/p&gt;
&lt;p&gt;
We cannot, unfortunately, add commas after lists in this way, but
his example is inconsistent in this regard (three examples have
commas after lists, but the example expansion later in the article
does not).&lt;/p&gt;
&lt;p&gt;
Hostadter presents the acronyms in capital letters, though
Common Lisp atoms (analogous to Clojure symbols) are
case-insensitive; we follow that convention here and use it to
indicate terms which may be expanded… that is to say, the
&lt;code class=&#34;verbatim&#34;&gt;COFFEE&lt;/code&gt; in the expansion of &lt;code class=&#34;verbatim&#34;&gt;SAUCE&lt;/code&gt; can itself be expanded to a
phrase which includes &lt;code class=&#34;verbatim&#34;&gt;ESPRESSO&lt;/code&gt;, and so on.&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(defpasta TOMATOES (TOMATOES on MACARONI (and TOMATOES only)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                             exquisitely SPICED))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(defpasta MACARONI (MACARONI and CHEESE (a REPAST of Naples_CO Italy)))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(defpasta REPAST (rather extraordinary PASTA and SAUCE_CO typical))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(defpasta CHEESE (cheddar_CO havarti_CO, emmentaler
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                                (especially SHARP emmenthaler)))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(defpasta SHARP (strong_CO hearty_CO and rather pungent))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(defpasta SPICED (sweetly pickled in CHEESE ENDIVE dressing))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(defpasta ENDIVE (egg NOODLES_CO dipped in vinegar eggnog))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(defpasta NOODLES (NOODLES (oodles of delicious LINGUINI) elegantly served))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(defpasta LINGUINI (LAMBCHOPS (including NOODLES)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                                  gotten usually in Northern Italy))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(defpasta PASTA (PASTA and SAUCE (that&amp;#39;s ALL!)))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(defpasta ALL! (a lucious lunch))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(defpasta SAUCE (SHAD and unusual COFFEE (excellente!)))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(defpasta SHAD (SPAGHETTI_CO heated al dente))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(defpasta SPAGHETTI (standard PASTA_CO always good_CO hot particularly
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                              (twist_CO then ingest)))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(defpasta COFFEE (choice of fine flavors, particularly ESPRESSO))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(defpasta ESPRESSO (excellent_CO strong_CO powerful_CO rich ESPRESSO_CO
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                                 suppressing sleep outrageously))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(defpasta BASTA! (belly all stuffed (tummy ache!)))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(defpasta LAMBCHOPS (LASAGNE and meatballs_CO casually heaped onto PASTA SAUCE))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(defpasta LASAGNE (LINGUINI and SAUCE and GARLIC (NOODLES everywhere!)))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(defpasta RHUBARB (RAVIOLI_CO heated under butter and RHUBARB (BASTA!)))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(defpasta RAVIOLI (RIGATONI and vongole in oil_CO lavishly introduced))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(defpasta RIGATONI (rich Italian GNOCCHI and TOMATOES (or NOODLES instead)))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(defpasta GNOCCHI (GARLIC NOODLES over crisp CHEESE_CO heated immediately))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(defpasta GARLIC (green and red LASAGNE in CHEESE))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
Hofstadter leaves the implementation of &lt;code class=&#34;verbatim&#34;&gt;acronym?&lt;/code&gt; undefined,
since it is so implementation-specific.  In our case, something is
an acronym if it&amp;#39;s a symbol and its name is equal to an
upper case version of itself.&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(defn acronym? [x]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  (and (symbol? x)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;       (= (name x) (.toUpperCase (name x)))))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
We also want to be able to remove commas from a symbol and evaluate
the result as a function. This is also very implementation-specific;
in our case, it relies on Clojure&amp;#39;s machinery for converting symbols
to strings and vice-versa, and on the subtle differences between
symbols, vars, and functions:&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(defn strip-comma-and-eval [sym]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  (let [base-symbol-name (-&amp;gt; sym
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                             name
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                             (clojure.string/replace #&amp;#34;_CO$&amp;#34; &amp;#34;&amp;#34;)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                             symbol)]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    ((-&amp;gt; *ns*
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;          ns-map
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;          (get (symbol base-symbol-name))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;          var-get))))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(strip-comma-and-eval &amp;#39;RHUBARB)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;;=&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(RAVIOLI_CO heated under butter and RHUBARB (BASTA!))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
&lt;code class=&#34;verbatim&#34;&gt;lower&lt;/code&gt; reduces the probability by some amount to encourage our
recursion to bottom out (and thereby avoid stack overflows).
Hofstadter multiplies probabilities by 0.8, but I simply square the
probability so that higher probabilities decrease more slowly than
lower ones as the recursion progresses:&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(defn lower [x] (* x x))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
A significant portion of Hofstadter&amp;#39;s article relates to the
recursive &lt;code class=&#34;verbatim&#34;&gt;expand&lt;/code&gt; function, so I won&amp;#39;t go into details here.  This
version is similar to his; it adds a bottoming-out clause to
accommodate the base case of an empty phrase (since &lt;code class=&#34;verbatim&#34;&gt;()&lt;/code&gt; and &lt;code class=&#34;verbatim&#34;&gt;nil&lt;/code&gt;
are not the same in Clojure, as they are in Common Lisp).  Also we
use &lt;code class=&#34;verbatim&#34;&gt;strip-comma-and-eval&lt;/code&gt; instead of plain &lt;code class=&#34;verbatim&#34;&gt;eval&lt;/code&gt; to handle the
comma-ed symbols.&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(defn expand [phrase probability]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  (cond
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    (symbol? phrase) phrase
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    (empty? phrase) phrase
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    (acronym? (first phrase))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    (if (&amp;lt; (rand) probability)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      (concat
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;       (expand (strip-comma-and-eval (first phrase)) (lower probability))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;       (expand (rest phrase) probability))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      (cons (first phrase) (expand (rest phrase) probability)))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    :else (cons (expand (first phrase) (lower probability))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                (expand (rest phrase) (lower probability)))))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
Ultimately we want to make the output similar to what Hofstadter shows in
the book.  The &lt;code class=&#34;verbatim&#34;&gt;normalize&lt;/code&gt; function does this, relying on two helper
functions, whose names are self-explanatory:&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(defn lower-case-symbol [x]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  (if-not (symbol? x)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    x
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    (-&amp;gt; x name .toLowerCase symbol)))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(defn get-commas-back [x]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  (if-not (symbol? x)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    x
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    (-&amp;gt; x
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        name
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        (clojure.string/replace #&amp;#34;_CO$&amp;#34; &amp;#34;,&amp;#34;)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        symbol)))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
When we&amp;#39;re done expanding our lists of food (and our bellies), we
prepare our data for output to the user: turn &lt;code class=&#34;verbatim&#34;&gt;_CO&lt;/code&gt; suffixes into
actual commas (using the fact that &lt;code class=&#34;verbatim&#34;&gt;(symbol &amp;#34;x,&amp;#34;)&lt;/code&gt; yields a valid
symbol, if one that would be hard to read back at the REPL); and,
lower-case all symbols to adhere to the style of the output shown in
&lt;em&gt;Metamagical Themas:&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(defn normalize [expr]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  (-&amp;gt;&amp;gt; expr
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;       (clojure.walk/postwalk get-commas-back)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;       (clojure.walk/postwalk lower-case-symbol)))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&#34;outline-container-headline-3&#34; class=&#34;outline-2&#34;&gt;
&lt;h2 id=&#34;headline-3&#34;&gt;
Dinner Is Served
&lt;/h2&gt;
&lt;div id=&#34;outline-text-headline-3&#34; class=&#34;outline-text-2&#34;&gt;
&lt;p&gt;
Now for the actual function we&amp;#39;ll use to generate our expansions.
Setting a large probability will ensure longer examples:&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(defn dinner [expr]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  (normalize (expand expr 0.9999)))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
We should test our code to make sure it doesn&amp;#39;t bomb out on any of our
acronyms.  Here we find all the acronyms based on the metadata added
by the &lt;code class=&#34;verbatim&#34;&gt;defpasta&lt;/code&gt; macro, ensuring each runs to completion:&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(let [nsm (ns-map *ns*)]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  (doseq [[k v] nsm :when (:pasta (meta v))]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    (dotimes [_ 10]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      (dinner (list k)))))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
If, like me, you use Emacs and CIDER and want long REPL examples,
you have to set `*print-length*` to something bigger than its
default:&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(set! *print-length* 1000)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
Now to run it!  Are you hungry yet?&lt;/p&gt;
&lt;div class=&#34;src src-text&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(dinner &amp;#39;(LINGUINI))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;;;=&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(lasagne and meatballs, casually heaped onto pasta sauce (including
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;noodles) gotten usually in northern italy and standard pasta, always
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;good, hot particularly (twist, then ingest) heated al dente and
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;unusual coffee (excellente!) and green and red lasagne in cheese
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(noodles (oodles of delicious linguini) elegantly served (oodles of
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;delicious linguini) elegantly served everywhere!) and meatballs,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;casually heaped onto pasta shad and unusual coffee (excellente!)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(including noodles (oodles of delicious linguini) elegantly served
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(oodles of delicious linguini) elegantly served (oodles of delicious
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;linguini) elegantly served (oodles of delicious linguini) elegantly
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;served (oodles of delicious lasagne and meatballs, casually heaped
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;onto pasta sauce (including noodles) gotten usually in northern italy)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;elegantly served) gotten usually in northern italy and standard pasta
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;and shad and unusual coffee (excellente!) (that&amp;#39;s all!) and shad and
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;unusual coffee (excellente!) (that&amp;#39;s all!) always good, hot
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;particularly (twist, then ingest) heated al dente and unusual choice
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;of fine flavors particularly espresso (excellente!) and green and red
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;lasagne in cheese (noodles (oodles of delicious linguini) elegantly
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;served (oodles of delicious linguini) elegantly served (oodles of
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;delicious linguini) elegantly served (oodles of delicious linguini)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;elegantly served everywhere!) and meatballs, casually heaped onto
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;pasta and sauce (that&amp;#39;s all!) and sauce (that&amp;#39;s all!) and shad and
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;unusual coffee (excellente!) (that&amp;#39;s all!) sauce (including noodles
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(oodles of delicious linguini) elegantly served (oodles of delicious
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;lambchops (including noodles) gotten usually in northern italy)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;elegantly served (oodles of delicious lambchops (including noodles)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;gotten usually in northern italy) elegantly served) gotten usually in
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;northern italy and standard pasta and shad and unusual coffee
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(excellente!) (that&amp;#39;s all!) and standard pasta, always good, hot
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;particularly (twist, then ingest) heated al dente and unusual coffee
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(excellente!) (that&amp;#39;s all!) and spaghetti, heated al dente and unusual
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;coffee (excellente!) (that&amp;#39;s a lucious lunch) and standard pasta,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;always good, hot particularly (twist, then ingest) heated al dente and
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;unusual coffee (excellente!) (that&amp;#39;s a lucious lunch) always good, hot
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;particularly (twist, then ingest) heated al dente and unusual choice
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;of fine flavors particularly espresso (excellente!) and green and red
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;linguini and sauce and garlic (noodles everywhere!) and meatballs,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;casually heaped onto pasta sauce (including noodles) gotten usually in
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;northern italy and spaghetti, heated al dente and unusual coffee
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(excellente!) and green and red lasagne in cheese (noodles (oodles of
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;delicious linguini) elegantly served everywhere!) in cheese (noodles
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(oodles of delicious linguini) elegantly served (oodles of delicious
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;linguini) elegantly served (oodles of delicious linguini) elegantly
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;served (oodles of delicious linguini) elegantly served (oodles of
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;delicious linguini) elegantly served (oodles of delicious lambchops
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(including noodles) gotten usually in northern italy) elegantly served
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(oodles of delicious linguini) elegantly served (oodles of delicious
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;linguini) elegantly served everywhere!) and meatballs, casually heaped
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;onto pasta and shad and unusual coffee (excellente!) (that&amp;#39;s a lucious
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;lunch) and sauce (that&amp;#39;s all!) and spaghetti, heated al dente and
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;unusual coffee (excellente!) (that&amp;#39;s a lucious lunch) and standard
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;pasta and sauce (that&amp;#39;s all!) always good, hot particularly (twist,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;then ingest) heated al dente and unusual coffee (excellente!) (that&amp;#39;s
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;a lucious lunch) shad and unusual choice of fine flavors particularly
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;espresso (excellente!) (including noodles (oodles of delicious
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;linguini) elegantly served (oodles of delicious linguini) elegantly
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;served (oodles of delicious linguini) elegantly served (oodles of
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;delicious linguini) elegantly served (oodles of delicious lasagne and
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;meatballs, casually heaped onto pasta sauce (including noodles) gotten
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;usually in northern italy) elegantly served (oodles of delicious
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;lambchops (including noodles) gotten usually in northern italy)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;elegantly served (oodles of delicious linguini and sauce and garlic
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(noodles everywhere!) and meatballs, casually heaped onto pasta sauce
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(including noodles (oodles of delicious linguini) elegantly served)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;gotten usually in northern italy) elegantly served (oodles of
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;delicious lambchops (including noodles (oodles of delicious linguini)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;elegantly served) gotten usually in northern italy) elegantly served
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(oodles of delicious lasagne and meatballs, casually heaped onto pasta
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sauce (including noodles) gotten usually in northern italy and shad
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;and unusual coffee (excellente!) and garlic (noodles everywhere!) and
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;meatballs, casually heaped onto pasta sauce (including noodles (oodles
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;of delicious linguini) elegantly served (oodles of delicious linguini)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;elegantly served) gotten usually in northern italy) elegantly served
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(oodles of delicious linguini and sauce and garlic (noodles
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;everywhere!) and meatballs, casually heaped onto pasta sauce
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(including noodles) gotten usually in northern italy and spaghetti,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;heated al dente and unusual coffee (excellente!) and garlic (noodles
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(oodles of delicious linguini) elegantly served everywhere!) and
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;meatballs, casually heaped onto pasta sauce (including noodles (oodles
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;of delicious linguini) elegantly served (oodles of delicious linguini)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;elegantly served) gotten usually in northern italy) elegantly served)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;gotten usually in northern italy)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
Man, I&amp;#39;m stuffed!&lt;/p&gt;
&lt;p&gt;
&lt;em&gt;A talk based on this code was given as in instructional&lt;/em&gt;
/
&lt;em&gt;fun exercise at Clojurepalooza at OpinionLab in May of 2018.&lt;/em&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
</description>
    </item>
    
  </channel>
</rss>
