Steel Bank Common Lisp (2026-08-20)

SBCL: Steel Bank Common Lisp

I’ve been playing with SBCL, or Steel Bank Common Lisp.

SBCL is one of the main modern implementations of Common Lisp. It is both a compiler and runtime, and it compiles Lisp into native machine code.

The name is amusing.

SBCL descends from CMUCL — Carnegie Mellon University Common Lisp.

The developers turned Carnegie Mellon into a joke:

  • Carnegie → Andrew Carnegie → steel
  • Mellon → Mellon family → banking
  • Carnegie MellonSteel Bank

Hence:

Steel Bank Common Lisp

The simplest possible program

(format t "Hello, world!~%")

Save that as:

hello.lisp

and run:

sbcl --script hello.lisp

Output:

Hello, world!

A function looks like this:

(defun square (x)
  (* x x))

(format t "~D~%" (square 12))

Output:

144

Or interactively, start SBCL:

$ sbcl

and use the REPL:

* (+ 2 3)
5

* (defun square (x) (* x x))
SQUARE

* (square 12)
144

Nothing especially strange yet.

But Lisp gets interesting when you realize that Lisp programs are represented using the same data structures Lisp programs manipulate.

Code that writes code

Here is a macro:

(defmacro repeat (n &body body)
  `(loop repeat ,n
         do (progn ,@body)))

Now we can write:

(repeat 3
  (format t "The machine dreams in parentheses.~%"))

Output:

The machine dreams in parentheses.
The machine dreams in parentheses.
The machine dreams in parentheses.

This looks like we added a new construct called repeat to the language.

In a sense, we did.

The macro receives Lisp source code as data and transforms it into another Lisp program before compilation.

We can see what it generates:

(macroexpand-1
 '(repeat 3
    (format t "hello~%")))

Conceptually it becomes:

(loop repeat 3
      do (progn
           (format t "hello~%")))

The strange-looking part is:

`(loop repeat ,n
       do (progn ,@body))

The backtick is quasiquote.

Inside it:

,n

inserts one value, while:

,@body

splices an entire list of expressions into the generated program.

Lisp isn’t merely executing code here.

It is constructing code, transforming it, and then compiling the result.

Creating a function at runtime

It gets stranger.

(let ((operation '+))
  (let ((f
          (compile nil
                   `(lambda (x y)
                      (,operation x y)))))
    (funcall f 100 23)))

Result:

123

What happened?

First:

(operation '+)

stores the symbol + as ordinary data.

Then this:

`(lambda (x y)
   (,operation x y))

constructs the Lisp program:

(lambda (x y)
  (+ x y))

Then:

compile

asks SBCL to compile that newly constructed function.

Finally:

(funcall f 100 23)

executes it.

So a running program just:

  1. represented another program as data;
  2. generated source code;
  3. compiled that source code;
  4. produced a native function;
  5. called the function.

All at runtime.

Ask SBCL what machine code it generated

SBCL also lets us look beneath Lisp and inspect the actual native machine code produced by the compiler.

(defun mysterious-function (x)
  (+ (* x x) 42))

(compile 'mysterious-function)

(disassemble #'mysterious-function)

SBCL will print the native instructions generated for the function.

Instead of treating Lisp as some interpreted scripting language, SBCL can turn something like:

(+ (* x x) 42)

into actual machine code for the host CPU.

This combination is one of the things that makes Common Lisp fascinating:

  • interactive REPL;
  • runtime compilation;
  • native code;
  • macros;
  • introspection;
  • code represented as data;
  • programs capable of constructing other programs.

The important distinction

Strictly speaking, the language here is Common Lisp.

SBCL is the implementation.

That is analogous to saying:

Language:       Common Lisp
Implementation: SBCL

Other Common Lisp implementations exist, including:

  • Clozure CL
  • ECL
  • ABCL
  • LispWorks
  • Allegro CL
  • CMUCL

But on a modern Unix system, if I wanted to simply install Common Lisp and start programming, SBCL would probably be my default choice.

On Debian/Ubuntu:

sudo apt install sbcl

On macOS:

brew install sbcl

Then:

sbcl

and suddenly you’re sitting at a descendant of a programming tradition that goes back to John McCarthy’s Lisp work in 1958.

Almost seventy years later, the parentheses are still alive.