This is my attempt to make a Common Lisp tutorial, since all of the ones I found on the internet were either out of date or needlessly confusing.
This is a guide that I made of information I wish I had when starting with Lisp. It does assume prior programming knowledge in another language. It's hardly comprehensive, but will hopefully be a good starting place for learning the language. Enjoy!
In Lisp, nearly everything is a function. Even the mathematical operators. For example:
(+ (* 2 3) 1)
equals 7.
As you can tell, the functions open and close with parenthesis. The format for calling functions in Lisp is
(function arg1 arg2)
setq
is used to set variables.
(setq var 32)
(setq str "Texas")
(setq lst '(1 2 3))
The three types of data here are numbers, strings, and lists. Notice that Lisp, unlike Java, is dynamically typed.
Note: The '
in list statement is called the quote operator, and tells Lisp that the input is a list, and not to interpret it as a function.
setq
sets the variable globally. To create a local variable (e.g. inside a function), use the let
function.
(let
((a 1)
(b 2))
... )
The variables a
and b
will only be defined within let
's parentheses.
To comment in Lisp, prefix the line with ;
; This is a comment!
The if
statement is a bit different from other programming languages.
(if (< 2 3)
(... true ...)
(... false ...))
Lisp executes the first block of code if the conditional statement is true. The second statement (which is optional) serves as the else statement.
If you want to execute multiple functions in the if statement (which is common) use the progn
function, which serves to group multiple functions together.
(if (> 3 4)
(progn
(setq x (+ x 1))
(setq y x))
(setq x 0))
If you want an if else statement, then you'd want to use the cond
function
(cond
((> x 1) (setq y 1))
((< x 1) (setq y 2))
(t (setq y 0)))
For boolean values, t
represents true, and nil
represents false. Lisp treats an empty list '()
(or nil
) as false and all other inputs as true.
This is a convenient feature of the language to know. For instance, to do something only if a list is not empty, the following two chunks of code are identical.
(if (> (length lst) 0)
(...))
(if lst
(...))
While loops are accomplished in the following manner:
(loop while (> n 0)
(setq n (- n 1)))
Although for the most part, recursion is the more popular way to accomplish loops.
Lists are important in Lisp, which is why Lisp stands for LISt Processing. I'd recommend reading up on Wikipedia's article on linked lists to fully understand this section.
(setq lst '(1 2 3))
To get the first item from the list, use the first
function. To get the rest of the items, use rest
. The are historically known as car
and cdr
, so you may see it referred to as such in older texts.
(first lst) => 1
(rest lst) => (2 3)
Lisp provides some helpful shortcuts to access other items in the list as well.
(second lst) => 2
(third lst) => 3
(fourth lst) => nil
Note: You could access these elements without these functions through repeatedly using first
and rest
. For instance, second
is equivalent to (first (rest lst)))
.
These functions are to save you a bit of typing.
To add an item to the beginning of the list, use the cons
function. cons
returns a new list with the element prefixed to the beginning of the list.
(cons 0 lst) => (0 1 2 3)
These functions really only make sense in the context of recursion, which is very prevalent in Lisp. Below is an example of a recursive sum function which uses both first
and rest
in a recursive context.
(defun sum (lst)
(if (not lst)
0
(+ (first lst) (sum (rest lst)))))
defun
is used to define functions.
(defun square (x)
(* x x))
(defun add (x y)
(+ x y))
Note: Lisp implicitly returns the value of the last statement in a function.
Calling functions is pretty straight forward; we've been doing it throughout this guide.
(square 9) => 81
(add 2 4) => 6
One of Lisp's most powerful features is the ability to pass functions to other functions. I'll list below some of the built in functions in Lisp that take advantage of this feature and are important to know. Most of these functions take two arguments, a function and a list.
mapcar
(map). Returns the list the results from applying the function to each of the items in the list. The following example returns a new list with all the elements squared.(mapcar 'square '(1 2 3 4 5)) => '(1 4 9 16 25)
remove-if
(filter). Removes items from the list if the item, when plugged into the function, returns true. The following example returns a new list with all the odd numbers removed.(remove-if 'oddp '(1 2 3 4 5)) => '(2 4)
Note: Built-in functions in Lisp that end in a 'p' are predicates and return a boolean value.
reduce
. Reduces a list to a single value by applying the function to each of the items. The following example is equivalent to the sum function.(reduce '+ '(1 2 3 4 5)) => 15
Writing your own function to take in a functions is not particularly hard. Below is an example of how you could implement your own mapcar
.
(defun my-mapcar (fn lst)
(if lst
(cons (funcall fn (first lst)) (my-mapcar fn (rest lst)))))
Note: funcall
is used to run functions that are stored in variables
It's occasionally useful (particularly with the higher-order functions listed above) to create a function without a name, typically because it is only getting used once.
For instance, say you wanted to double all the elements in a list. A function to double a number would rarely get used outside this call, so this is a good opportunity to create an anonymous function. The following two chunks of code are equivalent.
(defun double (x) (* x 2))
(mapcar 'double '(1 2 3 4 5)) => '(1 4 6 8 10)
(mapcar (lambda (x) (* x 2)) '(1 2 3 4 5)) => '(1 4 6 8 10)
It'll be a judgement call whether to go with the brevity of an anonymous function or the readability afforded by naming the function.
The print
function can be used for basic output.
(print 512)
More complicated printing in Lisp is a bit difficult. Lisp has the format
function, which is analogous to the printf
function in C. The basic structure is
(format t "~a ~a of beer on the wall.~%" 99 "bottles")
The t
argument means to print to the standard output, ~a
says to replace with the variable, and ~%
means newline.
For a more in depth look at Lisp's format
function, refer to this chapter in Practical Common Lisp. It has everything you could possibly want to know and more about printing in Lisp.
by Max Timkovich (if you have any suggestions for improvements, shoot me an email)
last updated August 6, 2014