Lisp is a divisive force in the software world. On the one hand, Lisp fans swear up and down that Lisp is faster, cleaner and more powerful than any other language out there, while detractors argue that with uncertain implementations and poor library support it’s difficult to write any real software in it. The thing is, they’re both right.
The first Lisp was written almost 50 years ago making it, along with FORTRAN, one of the most venerable programming languages still in use. It’s got arguably (and they will) the biggest feature list of any language, and was the first language to include a whole host of language features we all consider standard today, such as garbage collection, recursion, functions as objects and even the humble if-then-else clause. At the same time it’s considered a good teaching language: MIT uses Scheme, a Lisp derivative, to teach their introductory programming class.
We’ll run through getting the most powerful and project ready version of Lisp up and running: Common Lisp, and get you cranking out some Lisp.
- There’s no difference between code and data – In Lisp your code is just a list of function objects. Not distinguishing between source code and a data source allows Lisp to expose its internals to the compiler, interpreter and the the programmer. This allows you to read in and evaluate code natively with no problems, and even better allows you to use macros.
- Macros – Define and redefine any part of the language. Don’t like how conditions, or loops, or functions work? That’s fine, define your own notation. If you’re doing something specific a lot of times in your code, wouldn’t it be easier to add that feature to the language? With Lisp, you can.
- Speed – While it’s not in most cases faster than speed demons like C or OCaml, Common Lisp still performs well in a wide range of tests, and typically at a fraction of the program length. With a basic knowledge of how the compiler works, you can write code dealing with lists and big numbers that rivals anything else around in terms of execution speed and memory use.
- Simplicity – Everything in Lisp is based off a few basic ideas — once you have those under your belt you can tackle pretty much anything. It’s a common boast of Lisp programmers that you can implement a Lisp interpreter in almost any language you like in just a couple hundred lines of code (like say, in C++ or Haskell).
- Flexibility – Write code however you like. Prefer a functional programming approach? No problem. Want to write completely iteratively? Jot down a few quick macros and you’re set. You can write programs in the way that’s easiest and most efficient for you, and they’ll work fine.
Okay, enough already, I’m sold. Where do I get it?
That’s the tricky part. Unlike say, Python or C#, there’s no standard implementation of Common Lisp — the language is defined by a specification, not an implementation. Common Lisp also doesn’t have the advantage of C, a dominant implementation on each platform or a popular implementation that works on every platform. Every version should implement the standard but there are a few details which are left up to the compiler or interpreter that makes each implementation a little different.
You’ve got a few options — for this article I’ll be using CLISP, which works fine on Windows, Linux and Mac (PPC only). If you’ve got an Intel Mac, you’ll have to use another implementation, such as Allegro Common Lisp or SBCL. It won’t matter what you’re using for the simple examples in this quick start though.
An easy way to get a Common Lisp system up and running quickly is to use Lispbox, which gives you a Common Lisp implementation, Emacs and SLIME — Superior Lisp Integration Mode for Emacs, which many Lisp programmers will tell you is the only way to use Lisp. If you’re not an Emacs user (and personally, I’m with you there) then don’t worry, it’s not essential, it just makes things a lot easier when writing Common Lisp.
Installation differs on each platform, on Windows you can just run the installer, most Linux package managers will have packages, etc. Pick an implementation and follow the instructions and you should be fine. Come back here when you’ve got the REPL (interactive prompt) open and we’ll continue.
REPL stands for Read-Evaluate-Print-Loop, which simply means an interactive prompt into the interpreter. Here is where you can start typing out some basic Lisp. If you’ve worked with another interpreter prompt, you might start here by typing out some basic mathematical expressions using the prompt as a calculator for instance — but it won’t work. Typing 5 * 2 into CLISP won’t give you back anything sensible:
> 5 * 2 5 > 5 > 2
Lisp just doesn’t work that way, rather than operators, such as ‘+’, going in between their operators they go at the front, as if they were a function name. So if you wanted to use the REPL like a calculator you’d have to type:
> (* 5 2) 10 > (+ 1 2 3 4) 10 > (+ (* 5 2) (* 10 3) (/ 100 4)) 65
This is harder to get your head around but it’s got a few advantages: it’s easy for the compiler to parse, it’s the same for all functions and all operators and it let’s you have as many arguments for functions as you like — for example the second example above can scale as high as you like, making your plus and sum functions identical.
The second thing you’ll notice is that function names go inside the parentheses rather than outside like in most other languages. This means you write
(function arguments) rather than
Every Lisp expression will return a value, a function always returns the result of the last expression — even if it is NIL, the equivalent of null in Java or C++. This is why a hello world in Lisp is as simple as:
> "Hello World" "Hello World"
If you need to print something to the screen and return something else, you should use the print function instead:
> (print "Hello World") "Hello World" "Hello World"
The string is displayed twice, once by print and once as the return result of the function.
Lisp stands for LISt Processor, and almost everything in Lisp is in some way a list, so at some point you’ll have to work with them. Defining lists is easy:
> (list 1 2 3 4 5) (1 2 3 4 5) > '(1 2 3 4 5) (1 2 3 4 5)
The second way is called quoting, and it’s much more useful than just defining simple lists, but we’ll have to return to that topic in a later article.
Lisp has all the standard control flow methods. A simple loop iterating over one value couldn’t be easier:
> (dotimes (i 10) (print i)) 0 1 2 3 4 5 6 7 8 9 NIL
Likewise iterating over a list is just as easy:
> (dolist (i '(0 1 2 3 4 5 6 7 8 9)) (print i)) 0 1 2 3 4 5 6 7 8 9 NIL
These two are both specialised versions of the DO function, which works like a combination of a while and a for in other languages. It has three branches: the loop variable definition, stopping condition and the body of the statement:
> (do ((i 0 (+ 1 i))) ((> i 10)) (print i)) 0 1 2 3 4 5 6 7 8 9 10 NIL
In this example, the variable definition branch is
((i 0 (+ 1 i))), it defines a variable i to be 0 and the function (+ 1 0) called on each loop. The stopping condition is ((> i 10)) which means stop when i is greater than 10. Finally the body prints the value of i.
Lisp also has conditionals, the most basic being if:
> (if (> 10 20) (print "Hello") (print "World")) "World" "World"
If has three branches, the condition, the then statement and the else statement. If the condition is true, the then statement is executed, otherwise, the else statement is.
You may have noticed that at this point we’ve only used single statements — but what if you need to string a few statements together. In Lisp, you need to use a special control flow function called progn:
> (progn (print "Hello") (print "World")) "Hello" "World" "World"
This allows you to have more than one statement in the body of conditionals and loops, for instance.
Well that’s enough to get you started: with what you’ve got you can write toy programs to test the language out. Keep your eyes peeled for the next article in this series, when we’ll start introducing the list processing mechanics that really make Lisp shine.