Lisp quest discovering a parenthesis world

SBCL printing output twice

While learning the basics of the SBCL REPL you may have noticed its strange behaviour when it comes to the output of some instructions.

Making a sum will produce a single output with the result of the operation.

* (+ 1 5)
  6

The same will happen when calculating the square root of a number.

* (sqrt 4)
  2.0

But if we try to print a string using the print function, the result will be quite strange - an empty line followed by the same string printed twice.

* (print "twice")

  "twice"
  "twice"

In order to understand why a blank line is added to the output, we can try using another printing function called prin1. Its output is equal to print except for the missing blank line.

* (prin1 "twice")
  "twice"
  "twice"

As you can see from the functions’ documentation, the only difference between them is exactly this empy line (a new line actually) printed before the output. The print function will add it to the output, while prin1 not. But we have not yet discovered why the string is printed twice. The mystery is quite simple to solve, because the first string printed by the function is its output in the standard out. The second string is the value returned by the function and printed by the REPL - in a non-interactive program you will never see this behaviour.

If you need another prove of this behaviour you could try to assign the output of the print function to a variable (str) and then transforming it in uppercase.

* (let ((str (print "Hello, world!")))
    (string-upcase str))

  "Hello, world!"
  "HELLO, WORLD!"

Here the behaviour is clear. The blank line is added by print as the first string (the case has been kept). The last line is the uppercase version of the string, but we have not explicitly printed it. So it could have been printed only by the REPL itself - and this is the proof we were looking for.

Installing, running and quitting SBCL

Steel Bank Common Lisp SBCL is a Common Lisp implementation derived from the Carniege Mellon University Common Lisp (CMUCL). The “steel” and the “bank” in the name are references to the businesses of its founders (Andrew Carnegie and Andrew Mellon) so the relationship between them is clear. SBCL is very popular and you can get it running on your machine quite easily.

Installing on Linux

Almost all Linux distributions include a sbcl package.

  • Fedora -> sudo dnf install sbcl (not always updated to the latest version)
  • Ubuntu -> sudo apt install sbcl
  • Arch -> sudo pacman -S sbcl

Windows, Mac and other platforms

You can download a prebuild binary or sources for any platform from the dedicated page on the SBCL website. Also a ready-to-use docker image exists, and even if it is not an official image you can trust it because it is from a well known Lisper.

Running

Executing sbcl from a command line will show you an initial information message and the prompt - the last line starting with *.

$ sbcl
This is SBCL 2.0.1, an implementation of ANSI Common Lisp.
More information about SBCL is available at <http://www.sbcl.org/>.

SBCL is free software, provided as is, with absolutely no warranty.
It is mostly in the public domain; some portions are provided under
BSD-style licenses.  See the CREDITS and COPYING files in the
distribution for more information.
*

In this way we have started the SBCL interactive REPL1 so we can type instructions and execute them pressing Enter. The result of the computation will be shown below.

* (+ 1 2)
3

Quitting

Now you may be wondering how to quit the REPL, and so you may have pressed the ubiquitous CTRL-C. It doesn’t work and this weird error is shown.

* ^C
debugger invoked on a SB-SYS:INTERACTIVE-INTERRUPT in thread
#<THREAD "main thread" RUNNING {1000510083}>:
Interactive interrupt at #x7F41875058D7.

Type HELP for debugger help, or (SB-EXT:EXIT) to exit from SBCL.

restarts (invokable by number or by possibly-abbreviated name):
0: [CONTINUE] Return from SB-UNIX:SIGINT.
1: [ABORT   ] Exit debugger, returning to top level.

("bogus stack frame")

Sometimes stopping an application is not as obvious as we might think. And it looks like this is another chapter from the Art of Quitting book. To quit from the SBCL REPL you just need to type (quit) followed by Enter.

  1. Read–eval–print loop. The first REPL was truly invented in 1964 by L. Peter Deutsch and Edmund Berkeley while implementing Lisp on the PDP-1. Peter Deutsch was 17

Brief introduction to Lisp dialects and implementations

Your journey into the Lisp land starts with a choice - and it is not the choice between starting or not. The choice you have to make is about the Lisp dialect you want to learn. Since Lisp is a family of programming languages you can’t actually write Lisp code. Therefore you need to use a Lisp dialect such as Scheme, Common Lisp, Clojure or Racket. The complete list is much longer but these four are the most popular and active nowadays.

Suppose you choose Common Lisp. Do you think you could just download it and start writing code? Unfortunately it is not so easy and another choice is required. Since Common Lisp is a specified language1, this time you need to pick an implementation among the many available implementations. SBCL (Steel Bank Common Lisp), Allegro Common Lisp and LispWorks are just three examples from the existing dozens.

Every specification-compliant Common Lisp implementation behaves similarly to the others. So how to choose the right one for you? Despite being all similar, each implementation is different from the others. In fact, some implementations could support some operating systems and particular architectures (e.g. ARM) while others do not. Another key difference is the license. For example, SBCL is free software while Allegro Common Lisp has a commercial license with a freeware option. Moreover, some implementations provide useful extentions and advanced features for specific use cases. For example, LispWorks which is shipped with a Java interface2 and a multiplatform GUI Toolkit.

When using Scheme or Clojure you have a similar situation. With Clojure you can pick Clojure itself, running on the JVM, Clojure CLR, running on the .NET platform or many other implementations. If you want, you can even use it in your browser using ClojureScript. The only exception in the four Lisps listed at the beginning of this post is Racket, and in future posts we will see why.

So, where to start? A wise choice is to start with SBCL that is free and available for almost every platform3. After the installation you run it and start playing with the REPL (read-eval-print-loop) from the command line. They have also created a mirror on Github so you can follow the releases using Github notifications. If you are not satisfied, you can always pick another implementation and use it - your code will continue to work in the same way as before.

All these options can be a bit confusing, but after learning the relationships between Lisp dialects and the implementations, everything will be clear and you will be happy to have so many choices.

  1. ANSI Common Lisp. 

  2. If you need to interact heavily with Java, Clojure is a better choice. 

  3. An sbcl package is available in almost all Linux distribution 

It's all about Lisp(s)

This blog is dedicated to Lisps of all flavours, so why don’t we start with the canonical “hello world” program?

(print "Hello, World!")

Stay tuned!