Common Lisp

From ArchWiki

Common Lisp is a highly dynamic, multi-paradigm language that emphasizes interactivity and performance. Being fully standardized, there are multiple independent implementations from which to choose.

Installation

sbcl (http://www.sbcl.org/) is the most popular FOSS implementation and generally has the highest compatibility across the ecosystem. Its compiler produces native machine code and the project has monthly releases.

It is configured in Lisp within ~/.sbclrc, but you may not need this depending on the dependency management strategy you choose.

Alternate Implementations

There are numerous other implementations available. Apart from the options below, there are two major commercial Lisp implementations, Allegro and LispWorks, but they have strict licensing terms are not packaged within the Arch Linux ecosystem.

Active

These function seamlessly with modern tooling and can be used for serious projects.

  • ABCL — Armed Bear Common Lisp: runs on the Java Virtual Machine.
https://common-lisp.net/project/armedbear/ || abclAUR
  • CCL — Clozure Common Lisp: based on Open Macintosh Common Lisp and is known for its fast compiling times.
https://ccl.clozure.com/ || cclAUR
  • Clasp — Clasp: a newer Common Lisp implementation that interoperates with C++ libraries and uses LLVM for compilation to native code.
https://clasp-developers.github.io/ || clasp-clAUR
  • ECL — Embeddable Common Lisp: compiles to C code, thus offering good C integration and embeddability.
https://common-lisp.net/project/ecl/ || ecl

Historical

While packages are available for these, library and tooling compatibility is sometimes dubious, and some implementations are no longer actively maintained.

  • CLISP — ANSI Common Lisp interpreter, compiler and debugger: offers good C integration and embeddability.
https://www.gnu.org/software/clisp/ || clisp
  • CMUCL — CMU Common Lisp: a POSIX-only implementation originally developed at Carnegie Mellon.
https://gitlab.common-lisp.net/cmucl/cmucl/-/wikis/home || cmucl
  • GCL — GNU Common Lisp: A descendant of Kyoto Common Lisp from the 80s and a sibling to ECL.
https://www.gnu.org/software/gcl/ || gclAUR
  • MKCL — Mankai Common Lisp: A similar descendant of Kyoto Common Lisp.
https://mkcl.common-lisp.dev/ || mkcl-gitAUR

Dependency Management

Quicklisp

Quicklisp is a system for fetching and loading libraries into a Common Lisp program. By default it has a single, global package cache shared by all programs on your machine, and it pulls packages from a conservatively updated repository also called (perhaps confusingly) Quicklisp.

After installing the quicklisp package, it can be registered for a particular compiler as follows:

> sbcl --load /usr/share/quicklisp/quicklisp.lisp
* (quicklisp-quickstart:install)
* (ql:add-to-init-file)

After which (ql:quickload "foo") can be used in all future REPL sessions to load a dependency, downloading it if necessary.

To update all packages installed through Quicklisp, run the following in a REPL:

(ql:update-all-dists)
Note: Generally speaking, Quicklisp assumes that all Common Lisp projects you create are located under ~/common-lisp/.

Ultralisp

Ultralisp is an alternate Quicklisp repository that offers rolling releases of all packages, generally up-to-date with what is available on Github, etc.

To register it, run the following in a REPL:

(ql-dist:install-dist "http://dist.ultralisp.org/" :prompt nil)

Then, if a package you load via ql:quickload is newer in Ultralisp, it will be loaded from there instead of Quicklisp.

Qlot

Alternatively, if you want project-local dependencies, you can use Qlot (qlotAUR).

Once installed, a project repository can be initialized to use it via:

qlot init

Custom Dependencies

With Qlot, all custom dependency locations are declared within a qlfile. For instance, to declare Ultralisp usage, simply add:

dist http://dist.ultralisp.org

Or to specify a dependency on your local filesystem:

local foobar /home/you/code/common-lisp/foobar

See Qlot's README for more options.

To install declared dependencies, run:

qlot install

Invoking a REPL

To load a REPL with the current Qlot environment, run:

qlot exec sbcl

For Emacs users of Sly/Slime, consider configuring how your in-editor REPL is launched via:

(setq sly-default-lisp 'qlot-sbcl
      sly-lisp-implementations '((qlot-sbcl ("qlot" "exec" "sbcl") :coding-system utf-8-unix)))

Adjust as necessary for Slime.

Development Environments

Emacs

Common Lisp development is often done in Emacs, through slime or the newer sly. Both are widely adopted in the community and have a similar usage interface.

Lem

Lem (lem-editor-gitAUR) is a newer editor in the style of Emacs, but written and configured entirely in Common Lisp. It has terminal and GUI frontends, and supports many languages.

Tips

Managing Init Files

Library authors often test their code with multiple compiler implementations. However, each implementation has their own uniquely named init file, such as .sbclrc or .eclrc, but the content of these files is often identical. Rather than handwrite these files for each compiler, you can create one master file and symlink the others to it. For instance, if you consider .sbclrc to be your "master config", then:

ln -s /home/you/.sbclrc .eclrc
ln -s /home/you/.sbclrc .abclrc

And so on. The main init files are:

~/.sbclrc          # for SBCL
~/.abclrc          # for ABCL
~/.ccl-init.lisp   # for CCL
~/.clasprc         # for CLASP
~/.eclrc           # for ECL
~/.clisprc.lisp    # for CLISP
~/.cmucl-init.lisp # for CMUCL
~/.mkclrc          # for MKCL
~/.clinit.cl       # for Allegro

Less Verbose Compilation Output

SBCL in particular can be quite enthusiastic about the number of compiler "notes" it outputs. To silence these notes, while still displaying the usual errors and warnings, set the following in your ~/.sbclrc:

(declaim (sb-ext:muffle-conditions sb-ext:compiler-note))

Troubleshooting

Quicklisp can't load a local project

(ql:quickload "...") is used to load both external dependencies but also local projects. However, if your local project is not located under ~/common-lisp/, it will fail to load (or may even be pulled from online if you've published it).

In truth, Quicklisp is just fetching and organizing packages. Internally, it uses the ASDF build system to actually load them. It's also possible to load any local project or a package you've already downloaded via (asdf:load-system "foo"), and by default ASDF only looks in ~/common-lisp/ for local projects.

While configurable, a simpler way around this is to use a symlink:

ln -s /home/you/code/common-lisp/ common-lisp
Note: If using Qlot, the above symlink isn't necessary. As long as you have done qlot install, then (asdf:load-package "foo") will "just work".

What are Projects, Systems, and Packages?

The rest of this article has used the term "package" in the way it is usually used in other programming languages, synonymous with "library". However, although standardized in the mid-90s, the earliest forms of Common Lisp date from the 80s, and so terms involving project management differ. In essence:

  • Project: A group of systems. Sometimes called a "workspace" in other languages.
  • System: A group of packages. These can represent both libraries and "executables".
  • Package: A group of functions and type definitions. Often called a "module" in other languages, but can span multiple files.

As you can see, what is usually called a library elsewhere is known as a "system" in Common Lisp. Hence the name asdf:load-system. See here for an example of an inter-depending, multi-system project.

See also