Often those who are curious to try Lisp are faced with a number of choices: Which dialect to choose? Which implementation to choose? Which book or tutorial should one follow? Is it necessary use Emacs? SLIME?
Here are my recommendations:
- Choose Common Lisp because it has been the most popular dialect of Lisp in the overall history of Lisp. It is more convenient than Scheme if one decides to develop serious software in Lisp. Clojure appears to be more popular in the technology industry than Common Lisp among organizations (my workplace included) that use Lisp. I still recommend Common Lisp because I believe that it is more likely that one would work on an independent open source or hobby Lisp project than one would encounter one of the rare organizations who use Clojure at work.
- Choose SBCL (Steel Bank Common Lisp) as the implementation.[1][2] It is the most popular Common Lisp implementation and is recommended in many online discussions. CCL (Clozure CL, not to be confused with Clojure which is a separate dialect) is also another very good implementation. I still recommend SBCL because as a result of its greater popularity, it is readily available via package managers such as brew and apt-get as well IDE packages such as Portacle, Lisp in a Box, etc. CCL is currently missing from both brew and apt-get.
- Work through this book: Practical Common Lisp: http://www.gigamonkeys.com/book/ (available in print too if you search online). Skip the sections about Emacs and SLIME if you don't use Emacs.
- There is no need to use Emacs if you are not an Emacs user. Any good editor would do.
- A Vim user may consider installing Slimv[3][4]. Superior Lisp Interaction Mode for Vim ("SLIME for Vim") or Slimv is similar to Emacs/SLIME, displays the REPL in a Vim buffer, and comes with Paredit mode that makes typing and executing Lisp code quite convenient.
- Emacs with SLIME or Vim with Slimv are quite useful but not necessary. To get started quickly without being bogged down by the details of an editor, just execute the Lisp source code file on shell.[5]
- Optionally, keep another implementation of Common Lisp. Common Lisp is a standard that is implemented by various implementations. Each implementation may have its own extensions or implementation-specific behaviour regarding error handling, command line options, FASL format, unspecified behaviour, etc. Experimenting with concepts with another implementation of Lisp occasionally may offer some perspective about how some things could be different in different implementations. I keep CLISP around for this purpose.[6][7][8]
[1]: Install SBCL on macOS: brew install sbcl
[2]: Install SBCL on Debian-based distro: apt-get install sbcl
[5]: Load (execute) code in a file and exit: sbcl --script foo.lisp
[6]: Install CLISP on macOS: brew install clisp
[7]: Install CLISP on Debian-based distro: apt-get install clisp
[8]: Unfortunately CLISP is missing from Debian's stretch (stable) repository but it is available in its buster (testing) and sid (unstable) repositories. Hopefully this will be addressed when buster becomes stable. CLISP is available on Ubuntu.
What confused me a lot is that nobody seems to give an example on how to build a binary out of a Lisp program/make it runnable from command-line.
Also most tutorials/books I found don't guide you on how to build an application/structure your code – which is rather confusing for a beginner. You have to spend a lot of time and try and error to get things working using Quicklisp. I got often the impression, that since Lisp is so old, everyone using it knows how to do things and forgot to document for newcomers their knowledge.
That's from 2016 and it covers a LOT of practical Lisp lore. Basically Edi wrote down much of his knowledge how to write Lisp code. Not only from hobby projects - Edi also has extensive knowledge from commercial projects.
The commercial, and expensive, Lisps also have extensive facilities and documentation how to deliver applications. LispWorks for example supports delivery as standalone programs, applications with GUI, shared libraries and delivery for iOS and Android apps. Edi Weitz for example wrote a bunch of applications for Windows with LispWorks.
The reason nobody can give you an example for how to make a binary is because there are many many different ways of doing that. To name just a few:
* in ABCL you would generate a jar file, just like with java or clojure
* in SBCL you could dump a core file, there are some tools that can package that up in a command line binary
* if you use a bytecode compiler(like clisp), you'd use that the same way like python or ruby, you'd put your script in a text file, with a #! line at the top and run it like any other shell script.
* if you use a Lisp->C compiler, you'd generate C code and then compile that with GCC or Visual Studio or whatever
* if you use image based programming, you'd just load your code in the lisp image and just use lisp itself as your command line, your "binary" would then be just a normal lisp function.
* If you're deploying a service, you might want to package it in a docker image or even a VM image or have some build and deploy script depending on your environment or needs.
Since Common Lisp is a language standard (not an implementation) it is hard to provide a single set of instructions or guidelines that would work for all implementations. There are various implementations of Common Lisp that target native machine code, C code, bytecode, JVM, etc. So the build instructions, project structure, etc. depend on the target.
Here is a minimal example that builds a Lisp program into a binary executable with SBCL:
(defun main () (format t "hello, world~%"))
(sb-ext:save-lisp-and-die "hello" :executable t :toplevel 'main)
The SBCL-specific `save-lisp-and-die` function saves the Lisp process as a core image. The `:executable` argument includes the SBCL runtime in the image to ensure that the image is a standalone executable. This is why the executable for even a simple hello-world program tends to be quite large (30 MB to 50 MB)! The `:toplevel` argument specifies which function to run when the core file is run.
Here are some example commands to get you started:
$ cat hello.lisp
(defun main () (format t "hello, world~%"))
(sb-ext:save-lisp-and-die "hello" :executable t :toplevel 'main)
$ sbcl --script hello.lisp
$ ./hello
hello, world
If you would rather not have SBCL specific code in the Lisp source code file, then you could move the `sb-ext:save-lisp-and-die` call out of your source file to the SBCL command invocation. The source code now looks like this:
(defun main () (format t "hello, world~%"))
The shell commands now look like this:
$ cat hello.lisp
(defun main () (format t "hello, world~%"))
$ sbcl --load hello.lisp --eval "(sb-ext:save-lisp-and-die \"hello\" :executable t :toplevel 'main)"
$ ./hello
hello, world
By the way, there is also Buildapp[1] that provides a layer of abstraction for building executables from Lisp programs. It works with SBCL and CCL. It requires the toplevel function to be called with an argument though. Therefore the source code needs to be modified to:
(defun main (argv) (declare (ignore argv)) (format t "hello, world~%"))
Then Buildapp can be invoked like this:
$ cat hello.lisp
(defun main (argv) (declare (ignore argv)) (format t "hello, world~%"))
$ buildapp --load hello.lisp --entry main --output hello
;; loading file #P"/Users/susam/hello.lisp"
$ ./hello
hello, world
You are doing yourself a huge disservice developing in lisp without slime. I've been using a vi-like for 25 years and vim for 20 years and still use emacs/slime for my lisp development environment.
I'd recomment a ClozureCL instead of SBCL for a newcomer, because CCL does not do some optimizations and it is easier to debug. For example, it will show you local variables created by `let`, but SBCL – does not.
- Choose SBCL (Steel Bank Common Lisp) as the implementation.[1][2] It is the most popular Common Lisp implementation and is recommended in many online discussions.
And note that if you find its interactive interface very spartan, you're not doing anything wrong. It is very spartan. It's not really meant for direct human use; you're supposed to throw expressions at it from your editor. (Do one thing and do it well and all that.)
$ brew search ccl
==> Searching local taps...
cclive
==> Searching taps on GitHub...
==> Searching blacklisted, migrated and deleted formulae...
$ brew search clozure
==> Searching local taps...
==> Searching taps on GitHub...
==> Searching blacklisted, migrated and deleted formulae...
No formula found for "clozure".
Open pull requests:
clozure-cl 1.11.5 (restoration of a deleted formula) (https://github.com/Homebrew/homebrew-core/pull/25768)
Looks like the Homebrew formula for CCL was removed.
Here are my recommendations:
- Choose Common Lisp because it has been the most popular dialect of Lisp in the overall history of Lisp. It is more convenient than Scheme if one decides to develop serious software in Lisp. Clojure appears to be more popular in the technology industry than Common Lisp among organizations (my workplace included) that use Lisp. I still recommend Common Lisp because I believe that it is more likely that one would work on an independent open source or hobby Lisp project than one would encounter one of the rare organizations who use Clojure at work.
- Choose SBCL (Steel Bank Common Lisp) as the implementation.[1][2] It is the most popular Common Lisp implementation and is recommended in many online discussions. CCL (Clozure CL, not to be confused with Clojure which is a separate dialect) is also another very good implementation. I still recommend SBCL because as a result of its greater popularity, it is readily available via package managers such as brew and apt-get as well IDE packages such as Portacle, Lisp in a Box, etc. CCL is currently missing from both brew and apt-get.
- Work through this book: Practical Common Lisp: http://www.gigamonkeys.com/book/ (available in print too if you search online). Skip the sections about Emacs and SLIME if you don't use Emacs.
- There is no need to use Emacs if you are not an Emacs user. Any good editor would do.
- A Vim user may consider installing Slimv[3][4]. Superior Lisp Interaction Mode for Vim ("SLIME for Vim") or Slimv is similar to Emacs/SLIME, displays the REPL in a Vim buffer, and comes with Paredit mode that makes typing and executing Lisp code quite convenient.
- Emacs with SLIME or Vim with Slimv are quite useful but not necessary. To get started quickly without being bogged down by the details of an editor, just execute the Lisp source code file on shell.[5]
- Optionally, keep another implementation of Common Lisp. Common Lisp is a standard that is implemented by various implementations. Each implementation may have its own extensions or implementation-specific behaviour regarding error handling, command line options, FASL format, unspecified behaviour, etc. Experimenting with concepts with another implementation of Lisp occasionally may offer some perspective about how some things could be different in different implementations. I keep CLISP around for this purpose.[6][7][8]
[1]: Install SBCL on macOS: brew install sbcl
[2]: Install SBCL on Debian-based distro: apt-get install sbcl
[3]: Slimv in a ZIP file: https://www.vim.org/scripts/script.php?script_id=2531
[4]: Slimv as a Git repo: https://github.com/kovisoft/slimv/
[5]: Load (execute) code in a file and exit: sbcl --script foo.lisp
[6]: Install CLISP on macOS: brew install clisp
[7]: Install CLISP on Debian-based distro: apt-get install clisp
[8]: Unfortunately CLISP is missing from Debian's stretch (stable) repository but it is available in its buster (testing) and sid (unstable) repositories. Hopefully this will be addressed when buster becomes stable. CLISP is available on Ubuntu.