<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="assets/xml/rss.xsl" media="all"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Simon Dobson</title><link>https://simondobson.org/</link><description>Aut tace aut loquere meliora silentio</description><atom:link href="https://simondobson.org/rss.xml" rel="self" type="application/rss+xml"></atom:link><language>en</language><copyright>Contents © 2026 &lt;a href="mailto:simoninireland@gmail.com"&gt;Simon Dobson&lt;/a&gt; </copyright><lastBuildDate>Fri, 07 Aug 2026 10:45:18 GMT</lastBuildDate><generator>Nikola (getnikola.com)</generator><docs>http://blogs.law.harvard.edu/tech/rss</docs><item><title>Unexpected (to me) behaviour in Lisp sub-typing</title><link>https://simondobson.org/2026/08/07/strange-behaviour-in-lisp-sub-typing/</link><dc:creator>Simon Dobson</dc:creator><description>&lt;div id="outline-container-org34c1854" class="outline-2"&gt;
&lt;h2 id="org34c1854"&gt;Unexpected (to me) behaviour in Lisp sub-typing&lt;/h2&gt;
&lt;div class="outline-text-2" id="text-org34c1854"&gt;
&lt;p&gt;
I just encountered some unexpected behaviour in how Common Lisp (or
at least &lt;a href="https://sbcl.org"&gt;SBCL&lt;/a&gt;) handles array sub-typing.
&lt;/p&gt;

&lt;p&gt;
Suppose you have a structure declaration like this:
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;defstruct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;A&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Other"&gt;#1A&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;:type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;simple-array&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;integer&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;
We can create instances of this struct by providing an initial
value, and it will be type-checked.
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;make-a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;:a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Other"&gt;#1A&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;pre class="example"&gt;
#S(A :A #(1 2 3))
&lt;/pre&gt;


&lt;p&gt;
We can also omit the argument and get the default specified in the
declaration:
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;make-a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;pre class="example"&gt;
#S(A :A #())
&lt;/pre&gt;


&lt;p&gt;
So far so good. But suppose we now specialise the &lt;code&gt;simple-array&lt;/code&gt; type
against a type such as &lt;code&gt;(unsigned-byte 16)&lt;/code&gt; (the type of unsigned
16-bit integers).
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;defstruct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;B&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Other"&gt;#1A&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;:type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;simple-array&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;unsigned-byte&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;))))&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;make-b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;:b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Other"&gt;#1A&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;
This generates an error, as does using the default value.
&lt;/p&gt;

&lt;p&gt;
Why is this? I eventually tracked the problem down to the fact that
the expression &lt;code&gt;#1A()&lt;/code&gt; is given type &lt;code&gt;(simple-vector 0)&lt;/code&gt; while the
expression &lt;code&gt;#1A(1 2 3)&lt;/code&gt; is given type &lt;code&gt;(simple-vector 3)&lt;/code&gt;, and neither
of these are sub-types of &lt;code&gt;(simple-array (unsigned-byte 16))&lt;/code&gt;:
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;type-of&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Other"&gt;#1A&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;pre class="example"&gt;
(SIMPLE-VECTOR 0)
&lt;/pre&gt;


&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;type-of&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Other"&gt;#1A&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;pre class="example"&gt;
(SIMPLE-VECTOR 3)
&lt;/pre&gt;


&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;typep&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Other"&gt;#1A&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;'&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;simple-vector&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;pre class="example"&gt;
T
&lt;/pre&gt;


&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;typep&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Other"&gt;#1A&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;'&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;simple-array&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;unsigned-byte&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;pre class="example"&gt;
NIL
&lt;/pre&gt;


&lt;p&gt;
So the typing works for &lt;code&gt;integer&lt;/code&gt; (and indeed for &lt;code&gt;number&lt;/code&gt; and &lt;code&gt;float&lt;/code&gt;)
but not for the constrained types like &lt;code&gt;(unsigned-byte 16)&lt;/code&gt; –
although it &lt;i&gt;does&lt;/i&gt; work for &lt;code&gt;unsigned-byte&lt;/code&gt; (with no width).
&lt;/p&gt;

&lt;p&gt;
Interestingly the tests fail for empty arrays as well:
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;typep&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Other"&gt;#1A&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;'&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;simple-array&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;unsigned-byte&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;pre class="example"&gt;
NIL
&lt;/pre&gt;


&lt;p&gt;
I assume that the behaviour is because the compiler is at liberty to
optimise the storage of arrays with specific types, and doing so
makes it awkward to compare against types like &lt;code&gt;simple-vector&lt;/code&gt; that
don't contain their element type. This would also explain why the
check succeeds for types like &lt;code&gt;integer&lt;/code&gt;, whose values are stored
boxed and so can represented uniformly.
&lt;/p&gt;

&lt;p&gt;
There's a simple way around this, of course, once you know what the
problem is: make the type of the value explicit rather than relying
on the reader macro. For example:
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;defstruct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;C&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;make-array&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;'&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;:element-type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;'&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;unsigned-byte&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;:type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;simple-array&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;unsigned-byte&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;))))&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;make-c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;pre class="example"&gt;
#S(C :C #())
&lt;/pre&gt;


&lt;p&gt;
and also:
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;make-c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;:c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;make-array&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;'&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;:element-type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;'&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;unsigned-byte&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;:initial-contents&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;alexandria:iota&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;pre class="example"&gt;
#S(C :C #(0 1 2))
&lt;/pre&gt;


&lt;p&gt;
I can't find this behaviour detailed in the manuals (or anywhere
else) though. However, it seems to be related to the &lt;i&gt;upgraded array
element type&lt;/i&gt;. When an array is created, the implementation is
allowed to use a different type to the one specified in its
representation, which must be a supertype of the type requested. For
types like &lt;code&gt;integer&lt;/code&gt; and &lt;code&gt;unsigned-byte&lt;/code&gt; this is &lt;code&gt;t&lt;/code&gt;, the top type in the lattice:
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;upgraded-array-element-type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;'unsigned-byte&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;pre class="example"&gt;
T
&lt;/pre&gt;


&lt;p&gt;
But for the "constrained" types the upgraded type is the type
itself:
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;upgraded-array-element-type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;'&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;unsigned-byte&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;pre class="example"&gt;
(UNSIGNED-BYTE 16)
&lt;/pre&gt;


&lt;p&gt;
This suggests to me that the compiler (SBCL) is indeed optimising
the representation and then also performing more detailed
type-checking for elements.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;</description><category>lisp</category><category>programming</category><guid>https://simondobson.org/2026/08/07/strange-behaviour-in-lisp-sub-typing/</guid><pubDate>Fri, 07 Aug 2026 09:27:05 GMT</pubDate></item><item><title>A road to Lisp -- Which Lisp?</title><link>https://simondobson.org/2026/08/07/a-road-to-lisp-which-lisp/</link><dc:creator>Simon Dobson</dc:creator><description>&lt;div id="outline-container-org4511ed2" class="outline-2"&gt;
&lt;h2 id="org4511ed2"&gt;A road to Lisp: Which Lisp?&lt;/h2&gt;
&lt;div class="outline-text-2" id="text-org4511ed2"&gt;
&lt;p&gt;
&lt;a href="https://scotto.me/blog/2026-07-17-which-lisp/"&gt;A Road to Lisp: Which Lisp&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
A blog post reviewing four dialects of Lisp that a beginner
wanting to start with Lisp can choose: Common Lisp, Clojure,
Racket, and ELisp. The author, Elia Scotto, interestingly doesn't
include Scheme, although he does present Racket as a Scheme
dialect (which of course it is).
&lt;/p&gt;

&lt;p&gt;
Does the choice too make initially matter?
&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;
Dialect matters, but not as much as a beginner might think.
Learning Lisp is about learning a new type of programming. &lt;b&gt;A new
way of thinking about problems using code.&lt;/b&gt; You will learn the
fundamental concepts with any dialect. Then, once you have learned
one, it will be relatively easy to switch to another.
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;
I think most Lisp devotees would agree with the sentiment that
it's about a new relationship with code; I'm not totally convinced
that Racket is a good place to start, given that it's essentially
&lt;i&gt;several&lt;/i&gt; languages; and ELisp only makes sense if you are already a
devoted Emacs user, otherwise the learning curve will be nearly
vertical.
&lt;/p&gt;

&lt;p&gt;
Scotto's conclusion is that Clojure is the safest first choice,
giving you a modern syntax and full-stack environment with access
to all the Java libraries, while Common Lisp gives you fast native
compilation within a large, stable, and rock-solid ecosystem, and
Racket is a good basis for language research.
&lt;/p&gt;

&lt;p&gt;
For my own part I came to Scheme first when I was an
undergraduate, then picked up ELisp when I started using Emacs,
and then learned Common Lisp when I started wanting to write
significant code – and there I've stayed with the latter two,
quite happily. It's certainly the case that it's been easy to move
between these dialects, modulo some differences that are purely
syntactic. And it's certainly true that Lisp changed my
relationship to code in a deep and persistent way.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;</description><category>lisp</category><category>project:lisp-bibliography</category><category>tutorial</category><guid>https://simondobson.org/2026/08/07/a-road-to-lisp-which-lisp/</guid><pubDate>Fri, 07 Aug 2026 08:59:43 GMT</pubDate></item><item><title>Antwerp</title><link>https://simondobson.org/goodreads/antwerp/</link><dc:creator>Simon Dobson</dc:creator><description>&lt;div&gt;
    &lt;div&gt;
      &lt;img src="https://i.gr-assets.com/images/S/compressed.photo.goodreads.com/books/1616472225l/55877520._SX98_.jpg" style="float: left; margin-right: 10px"&gt;
      &lt;h2&gt;
	Michael Pye
	  (2021)
      &lt;/h2&gt;
    &lt;/div&gt;
    &lt;p&gt;
      Antwerp is, to the modern eye, a strange choice for an urban biography. But it's a place that can make a fair claim to having invented a lot of the modern world, notably the financialisation of trade and especially of art: the first place where one bought paintings from dealers rather than commissioning them from the studios. A place that tried valiantly to separate trade from religion, to protect its minorities and resist anti-Protestant edicts while still being rules from Spain, and to ride-out the waves of regulation and repression that washed around it. It was a bold experiment in trying to re-become a city-state, at a time when that simply wasn't possible any more. &lt;br&gt;&lt;br&gt;It's impossible to read this book and not feel its author's debt to Barbara Tuchman, both in the general style of writing and in the sharp eye for personal detail. There are a couple of quite detailed biographies, of an architect and a printer/publisher, each of which is both engaging gossipy and carefully chosen to show the changes that each man was essential in bringing in. In that way it's a very personal book that seeks to illustrate the history of the city by the histories of individuals, gleaned from a formidable amount of primary research: Pye seems to have read every letter, book, and bill relating to the period.&lt;br&gt;&lt;br&gt;I don't think it quite succeeds, despite the great writing and scholarship: the city's history seems confused and lost amid the detail, it's hard to follow the timeline and understand the sweep of the politics and the events shaping it. But it's still a superb read, packed full of anecdotes and the seeds or modernity.
      &lt;/p&gt;&lt;p&gt;
	3/5.
	  Finished Saturday 1 August, 2026.
	&lt;/p&gt;&lt;p&gt;
	  (Originally published on &lt;a href="https://www.goodreads.com/review/show/8746370121?utm_medium=api&amp;amp;utm_source=rss"&gt;Goodreads&lt;/a&gt;.)
  &lt;/p&gt;&lt;/div&gt;</description><category>books</category><category>reviews</category><guid>https://simondobson.org/goodreads/antwerp/</guid><pubDate>Sat, 01 Aug 2026 00:00:00 GMT</pubDate></item><item><title>Hothouse Earth: An Inhabitant's Guide</title><link>https://simondobson.org/goodreads/hothouse-earth-an-inhabitants-guide/</link><dc:creator>Simon Dobson</dc:creator><description>&lt;div&gt;
    &lt;div&gt;
      &lt;img src="https://i.gr-assets.com/images/S/compressed.photo.goodreads.com/books/1658479574l/61336424._SX98_.jpg" style="float: left; margin-right: 10px"&gt;
      &lt;h2&gt;
	Bill   McGuire
      &lt;/h2&gt;
    &lt;/div&gt;
    &lt;p&gt;
      A horror story, with the additional horror of being entirely backed by science.&lt;br&gt;&lt;br&gt;I'm writing during the 2026 summer heatwaves in the UK, and this was &lt;i&gt;really&lt;/i&gt; not the time to be reading this book. It lays bare the best estimates for changes caused by global heating to everything from diseases and food production to sea levels and increased earthquakes (caused by the land rebounding after the compression caused by ice is removed). The world envisaged is not entirely unlivable, but that's only a slight comfort given the tribulations to come.&lt;br&gt;&lt;br&gt;Had we acted on global heating at the time of the &lt;a href="https://en.wikipedia.org/wiki/Stern_Review" rel="nofollow noopener"&gt;Stern review&lt;/a&gt; of 2006 it might have been possible to avoid the worst at a reasonable economic cost. (McGuire, interestingly, doesn't mention Stern, whose conclusions have often been criticised for being understated in both risks and costs.) We're now in a position where we have to make much more expensive and difficult carbon reductions to avoid terrible harms, while &lt;i&gt;also&lt;/i&gt; having to incur massive costs to mitigate the harms that are already baked-in to the climate system.&lt;br&gt;&lt;br&gt;It's not a book that's entirely without hope: the last chapter paints two pictures of London later in the century under different emission reduction scenarios that highlight that a warmer world would be liveable (and even pleasant) – but only after actions that frankly seem beyond us as a civilisation. McGuire points to the hypocrisy of world leaders as the COP26 conference, promising cuts while permitting more drilling: As I'm writing, &lt;i&gt;more&lt;/i&gt; drilling permits are being issued by the new UK administration, and AI data centres are being proposed that will require local gas-fired power stations exceeding the current generation capacity of the entire UK electricity grid. It seems we still have to grasp the scale of changes required, with those changes growing the longer we wait.
      &lt;/p&gt;&lt;p&gt;
	5/5.
	  Finished Saturday 18 July, 2026.
	&lt;/p&gt;&lt;p&gt;
	  (Originally published on &lt;a href="https://www.goodreads.com/review/show/8758459576?utm_medium=api&amp;amp;utm_source=rss"&gt;Goodreads&lt;/a&gt;.)
  &lt;/p&gt;&lt;/div&gt;</description><category>books</category><category>reviews</category><guid>https://simondobson.org/goodreads/hothouse-earth-an-inhabitants-guide/</guid><pubDate>Sat, 18 Jul 2026 00:00:00 GMT</pubDate></item><item><title>Beautiful Racket: An introduction to language-oriented programming using Racket</title><link>https://simondobson.org/2026/07/14/beautiful-racket-an-introduction-to-language-oriented-programming-using-racket/</link><dc:creator>Simon Dobson</dc:creator><description>&lt;div id="outline-container-orge66a136" class="outline-2"&gt;
&lt;h2 id="orge66a136"&gt;Beautiful Racket: An introduction to language-oriented programming using Racket&lt;/h2&gt;
&lt;div class="outline-text-2" id="text-orge66a136"&gt;
&lt;p class="floater"&gt;
&lt;img src="https://simondobson.org/attachments/e3/7de938-c600-4d44-ae6d-02798869a00b/screenshot.png" alt="nil"&gt;
&lt;/p&gt;

&lt;p&gt;
Matthew Butterick.  &lt;i&gt;&lt;a href="https://beautifulracket.com/"&gt;Beautiful Racket: An Introduction to
Language-Oriented Programming Using Racket&lt;/a&gt;&lt;/i&gt;. 2024.
&lt;/p&gt;

&lt;p&gt;
&lt;a href="https://racket-lang.org/"&gt;Racket&lt;/a&gt; positions itself as a "programmable programming
language" – more so than Lisp's usual claim to this title – which
makes it attractive for exploring multi-paradigm and multi-language
programming.
&lt;/p&gt;

&lt;p&gt;
Racket's main claim to a niche is allowing a programmer to define
new domain-specific languages (DSLs), not necessarily Lisp-like,
that can be combined together to let a program be expressed in the
"most appropriate" form for the problem. This books is structured
around exactly this idea, defining a succession of languages of
increasing sophistication to demonstrate Racket's capabilities.
Each language has a "reader" to convert strings into Lisp
S-expressions and an "expander" to translate these forms into
Racket (or another Racket-defined language). The examples include
a simple stack-based calculator, an embedded JSON parser, and a
Basic interpreter that exercises the power of a full parser.
&lt;/p&gt;

&lt;p&gt;
The description of Racket itself is very thorough, to the extent
that this book could be treated as a language definition itself,
complementing the &lt;a href="/2026/07/10/a-programmable-programming-language/"&gt;article&lt;/a&gt; about it. Certainly it provides the most
accessible way to learn the language and explore what it means to
explore "language-oriented" programming.
&lt;/p&gt;

&lt;p&gt;
It's possible to define DSLs in Common Lisp or Scheme without
Racket's extra functionality, and in many cases that will be
sufficient – especially when the DSL is a Lisp itself. But there
will certainly be applications for which Racket is absolutely the
right tool.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;</description><category>lisp</category><category>project:lisp-bibliography</category><category>tutorial</category><guid>https://simondobson.org/2026/07/14/beautiful-racket-an-introduction-to-language-oriented-programming-using-racket/</guid><pubDate>Tue, 14 Jul 2026 07:07:51 GMT</pubDate></item><item><title>A programmable programming language</title><link>https://simondobson.org/2026/07/10/a-programmable-programming-language/</link><dc:creator>Simon Dobson</dc:creator><description>&lt;div id="outline-container-org90d39a3" class="outline-2"&gt;
&lt;h2 id="org90d39a3"&gt;A programmable programming language&lt;/h2&gt;
&lt;div class="outline-text-2" id="text-org90d39a3"&gt;
&lt;p&gt;
Matthias Felleisen, Robert Bruce Findler, Matthew Flatt, Shriram
Krishnamurthi, Eli Barzilay, Jay McCarthy, and Sam
Tobin-Hochstadt.  &lt;i&gt;&lt;a href="https://doi.org/10.1145/3127323"&gt;A Programmable Programming Language&lt;/a&gt;&lt;/i&gt;.
Communications of the ACM &lt;b&gt;61&lt;/b&gt;, pp.62–71. 2018.
&lt;/p&gt;

&lt;p&gt;
Lisp has been described as a "programmable programming language":
the fact that Lisp code is valid Lisp data and can be manipulated
as such, coupled with macros, makes it easy to construct new Lisp
variants in Lisp, and to combine them with "real" Lisp in
interesting ways.
&lt;/p&gt;

&lt;p&gt;
Racket is a Lisp that takes this to its logical conclusion, making
domain-specific sub-languages into first-class objects that can be
freely interleaved within programs and can be matched to the
"natural" expression of the target domain. The languages don't
even have to be Lisp-like.
&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;
In the ideal world, software developers would analyze each problem in
the language of its domain and then articulate solutions in matching
terms.
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;
Racket languages are formed of two parts: a &lt;b&gt;reader&lt;/b&gt; that turns
strings into properly bracketed S-expressions, and an &lt;b&gt;expander&lt;/b&gt;
that turns these expressions into "real" Racket (or some other
Racket-defined language).
&lt;/p&gt;

&lt;p&gt;
This flexibility adds a whole new level to Lisp programming. For
example, it allows languages that don't readily translate to Lisp
style to be implemented and integrated into Lisp. This may simply
be for user convenience, or may have some deeper semantic
structure. Racket also defines clean interfaces between languages,
which is what allows them to be combined. It's a deeper version
of the usual Lisp multi-paradigm approach, reaching out beyond
macros working on Lisp syntax.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;</description><category>language-reference</category><category>lisp</category><category>project:lisp-bibliography</category><guid>https://simondobson.org/2026/07/10/a-programmable-programming-language/</guid><pubDate>Fri, 10 Jul 2026 14:44:09 GMT</pubDate></item><item><title>Stasiland: Stories from Behind the Berlin Wall</title><link>https://simondobson.org/goodreads/stasiland-stories-from-behind-the-berlin-wall/</link><dc:creator>Simon Dobson</dc:creator><description>&lt;div&gt;
    &lt;div&gt;
      &lt;img src="https://i.gr-assets.com/images/S/compressed.photo.goodreads.com/books/1385280143l/226369._SX98_.jpg" style="float: left; margin-right: 10px"&gt;
      &lt;h2&gt;
	Anna Funder
	  (2003)
      &lt;/h2&gt;
    &lt;/div&gt;
    &lt;p&gt;
      A view of East Germany by a semi-outsider, an Australian living in the East. Perhaps this gives a better perspective.&lt;br&gt;&lt;br&gt;The Stasi come across in this book as the most dedicated and efficient secret police force imaginable. They want to known &lt;i&gt;everything&lt;/i&gt; – to the extent of imprisoning one of their own agents for &lt;i&gt;not&lt;/i&gt; reporting something that he &lt;i&gt;knew&lt;/i&gt; would get him into trouble – and co-opted a large fraction of the East German population to report on their friends and families, even when those reports served no purpose other than simply to &lt;i&gt;be&lt;/i&gt; reported.&lt;br&gt;&lt;br&gt;It's surprising how many former Stasi men (and they were all men) Funder managed to persuade to speak to her, and how open they were about some of the frankly amazing technology and tradecraft they employed. She is clearly a skilled journalist and a good listener, perhaps aided by her outsider status and fluent German.&lt;br&gt;&lt;br&gt;There are some comic incidents, as one would expect, notably the Stasi man who steals a cheap trinket when he retires and is then persistently investigated even though no-one cares about the object itself. And then when Germany re-unifies he is investigated &lt;i&gt;again&lt;/i&gt; by the authorities: once for the theft (which now concerns reunified Germany's state property) and then again for lying about the theft. Kafka would have approved.&lt;br&gt;&lt;br&gt;But the main story is one of persecution, where a single mistake – the details of which may never be apparent – can blight someone's entire life. It can make them unemployable, with the additional twist that they can't actually &lt;i&gt;be&lt;/i&gt; unemployed because that is considered a Western phenomenon that the state has declared does not exist in East Germany. The Party invents and publicises a new dance that's designed to eliminate all contact between dancers so as to avoid temptation. It's hard to imagine the level of false consciousness living under such a system required of everyone – and even harder to understand that some still yearn for its barren certainties.
      &lt;/p&gt;&lt;p&gt;
	4/5.
	  Finished Monday 22 June, 2026.
	&lt;/p&gt;&lt;p&gt;
	  (Originally published on &lt;a href="https://www.goodreads.com/review/show/8635314942?utm_medium=api&amp;amp;utm_source=rss"&gt;Goodreads&lt;/a&gt;.)
  &lt;/p&gt;&lt;/div&gt;</description><category>bonanza</category><category>books</category><category>reviews</category><guid>https://simondobson.org/goodreads/stasiland-stories-from-behind-the-berlin-wall/</guid><pubDate>Mon, 22 Jun 2026 00:00:00 GMT</pubDate></item><item><title>The Lisp curse</title><link>https://simondobson.org/2026/06/18/the-lisp-curse/</link><dc:creator>Simon Dobson</dc:creator><description>&lt;div id="outline-container-orgef71109" class="outline-2"&gt;
&lt;h2 id="orgef71109"&gt;The Lisp curse&lt;/h2&gt;
&lt;div class="outline-text-2" id="text-orgef71109"&gt;
&lt;p&gt;
&lt;a href="https://www.winestockwebdesign.com/Essays/Lisp_Curse.html"&gt;https://www.winestockwebdesign.com/Essays/Lisp_Curse.html&lt;/a&gt;
&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;
The power of Lisp is its own worst enemy.
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;
An interesting essay on the "Lisp curse", the idea that Lisp's
power can sometimes be a &lt;i&gt;disadvantage&lt;/i&gt; for developers. The core
idea expressed as a question: how hard is it to add
object-oriented features to a language? In the C world it's
happened twice, giving rise to C++ and Objective-C, an no-one
would even &lt;i&gt;think&lt;/i&gt; about defining their own. In the Lisp world, by
contrast, building that style of object-oriented extension is a
weekend's work (assuming we didn't already have CLOS, which is in
many ways superior anyway). The point is that it's relatively easy
to build even complex features as libraries, meaning there's less
reason to standardise, and this leads to a proliferation of
mutually incompatible designs that solve 80% of the problem – but
all a &lt;i&gt;different&lt;/i&gt; 80%. This then makes interoperability difficult.
&lt;/p&gt;

&lt;p&gt;
In fact the essay goes farther, to argue that the sorts of people
who write Lisp tend not to be the sorts of people of work well in
the political and compromise-driven world of standardisation. I'm
not sure how true that is, given the stability of the Common Lisp
standard itself since its adoption in 1994, but it's an
interesting reflection on how increased language expressiveness
need not automatically be a strength.
&lt;/p&gt;

&lt;p&gt;
(Some of the links in the article are now broken, or point to what
looks like an AI link farm.)
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;</description><category>experience</category><category>lisp</category><category>project:lisp-bibliography</category><guid>https://simondobson.org/2026/06/18/the-lisp-curse/</guid><pubDate>Thu, 18 Jun 2026 09:07:24 GMT</pubDate></item><item><title>Programming algorithms in Lisp</title><link>https://simondobson.org/2026/06/13/programming-algorithms-in-lisp/</link><dc:creator>Simon Dobson</dc:creator><description>&lt;div id="outline-container-orgbcdd817" class="outline-2"&gt;
&lt;h2 id="orgbcdd817"&gt;Programming algorithms in Lisp&lt;/h2&gt;
&lt;div class="outline-text-2" id="text-orgbcdd817"&gt;
&lt;p class="floater"&gt;
&lt;img src="https://simondobson.org/attachments/ef/0a5cf2-5145-45d5-bee1-da969fcbc18b/pail.jpg" alt="nil"&gt;
&lt;/p&gt;

&lt;p&gt;
Vsevolod Domkin.  &lt;i&gt;&lt;a href="https://doi.org/10.1007/978-1-4842-6428-7"&gt;Programming Algorithms in Lisp&lt;/a&gt;&lt;/i&gt;. Apress. 2021.
&lt;/p&gt;

&lt;p&gt;
This is exactly what it sounds like: an algorithms textbook that
uses Lisp as its implementation language. It has the strengths and
weaknesses of all such textbooks: it shows programmers, especially
new programmers, how to write algorithms that are both correct and
efficient, and the places where incorrectness and inefficiency
will hide; and in doing this it tempts them to write algorithms
that are already implemented in libraries, when they should really
seek out and re-use the already-developed and -debugged code.
&lt;/p&gt;

&lt;p&gt;
But of course there are always new algorithms that &lt;i&gt;don't&lt;/i&gt; have an
existing library and therefore &lt;i&gt;need&lt;/i&gt; to be written from scratch. This
book is excellent preparation for that. It would give a new-ish
programmer the confidence to tackle a challenging algorithm design
and implementation job. It ranges well away from the common
algorithms, to cover things like approximation and (especially
importantly) parallelism and lock-free data structures, and I can
imagine it providing templates that could be used as starting points
for a huge range of new algorithms. Just remember not to re-invent
the wheel.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;</description><category>advanced-tutorial</category><category>lisp</category><category>project:lisp-bibliography</category><guid>https://simondobson.org/2026/06/13/programming-algorithms-in-lisp/</guid><pubDate>Sat, 13 Jun 2026 11:15:03 GMT</pubDate></item><item><title>Modern Common Lisp with FSet</title><link>https://simondobson.org/2026/06/12/modern-common-lisp-with-fset/</link><dc:creator>Simon Dobson</dc:creator><description>&lt;div id="outline-container-org3fbef36" class="outline-2"&gt;
&lt;h2 id="org3fbef36"&gt;Modern Common Lisp with FSet&lt;/h2&gt;
&lt;div class="outline-text-2" id="text-org3fbef36"&gt;
&lt;p&gt;
&lt;a href="https://fset.common-lisp.dev/Modern-CL/Top_html/index.html"&gt;https://fset.common-lisp.dev/Modern-CL/Top_html/index.html&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
A book-length description of a library, &lt;a href="https://github.com/slburson/fset"&gt;FSet&lt;/a&gt;, that provides
functional collections for Lisp. By "functional collections" the
author means collections – sets, trees, maps, and others – where
update always produces a new collection rather than mutating the
original collection in place. This is an attractive property for a
language, and one that's hard to do efficiently. As with &lt;a href="/2024/09/27/purely-functional-data-structures/"&gt;Purely
functional data structures&lt;/a&gt;, it provides a change of emphasis that
makes for more referentially transparent code.
&lt;/p&gt;

&lt;p&gt;
The book contains a lot of discussion about the library's
rationale and design, which makes it useful as a reference for
others designing large libraries (or new languages, which of course
in Lisp can mean much the same thing). There's an equally
important discussion about what's &lt;i&gt;not&lt;/i&gt; provided (for example lazy
collections) which is really interesting by giving an example of
when to stop with a codebase that could otherwise probably grow
indefinitely.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;</description><category>advanced-tutorial</category><category>lisp</category><category>project:lisp-bibliography</category><guid>https://simondobson.org/2026/06/12/modern-common-lisp-with-fset/</guid><pubDate>Fri, 12 Jun 2026 08:56:40 GMT</pubDate></item></channel></rss>