Lisp Quickstart

Lisp is a big and deep language. This quickstart is only intended to get you introduced to very basic concepts in Lisp, not any of the really cool stuff Lisp does. As such it's geared to how to do C in Lisp, not good functional style (no closures, no macros). It's enough to get you up to speed so you can more easily understand a good book (ANSI Common Lisp, etc.) The quickstart also does not teach many functions -- you'll need to root around in the ANSI Common Lisp index and play with some of the functions there. The quickstart also shows you how to manipulate the command line, and to load and compile files.

Don't be intimidated by the size of this file. Just go through it at your own pace. We'll be teaching this stuff on the board anyway.

If you're done with this tutorial, go on to Tutorial 2 and Tutorial 3.

Legend

The table cell to the right shows what you type, and the output, for this tutorial. Text shown in blue you are responsible for typing, with a Return at the end of the line. Text shown in black indicates stuff that is printed back to you. Text shown in red are remarks -- do not type them.

If the cell is divided by a line, as is shown at right, then this indicates two different examples.

This text is being printed out.
You would type this text         [This is a remark]

Here is another example.



Running, Breaking, and Quitting Lisp

On osf1 or mason2, you start lisp by typing lisp at the command line. This fires up an implementation of lisp by Xanalys called LispWorks.

If you've downloaded clisp or are using clisp on the ITE cluster, you typically start it by typing clisp and this is what you see:


[On osf1...]
osf1.gmu.edu> lisp
LispWorks(R): The Common Lisp Programming Environment
Copyright (C) 1987-1998 Xanalys Incorporated.  All rights reserved.
Version 4.1.20
Saved by root as lispworks, at 29 May 2001 16:35
User sluke on osf1.gmu.edu
; Loading text file /usr/local/lispworks_4.1/hcl/4-1-0-0/
      config/siteinit.lisp

CL-USER 4 >



[On chrono...] chrono[~]> clisp i i i i i i i ooooo o ooooooo ooooo ooooo I I I I I I I 8 8 8 8 8 o 8 8 I \ `+' / I 8 8 8 8 8 8 \ `-+-' / 8 8 8 ooooo 8oooo `-__|__-' 8 8 8 8 8 | 8 o 8 8 o 8 8 ------+------ ooooo 8oooooo ooo8ooo ooooo 8 Copyright (c) Bruno Haible, Michael Stoll 1992, 1993 Copyright (c) Bruno Haible, Marcus Daniels 1994-1997 Copyright (c) Bruno Haible, Pierpaolo Bernardi, Sam Steingold 1998 Copyright (c) Bruno Haible, Sam Steingold 1999-2001 [1]>
In the previous examples, the very last line is the command line. Lisp has a command line where you type in things to execute. Here are the command lines in Lispworks and in clisp.

[On osf1...]
CL-USER 4 > 


[On chrono...] [1]>
Think of the Lisp command line like the command line in a Unix shell or at a DOS prompt. Pressing Control-C in a Unix shell or at a DOS prompt halts the current running process and returns you to the command line. Similarly, pressing Control-C in Lisp halts whatever is presently running and returns you to the command line.

After you press Control-C, the command line changes to a "subsidiary" command line to reflect that you are in a break condition. Kinda like pressing Control-C in a debugger. In LispWorks, the break condition is signified by a colon in the command line. In clisp, the break condition is signified by the word "Break" in the command line.

You don't have to escape out of a break condition -- you can just keep on working from there. But it's probably best to escape out. On LispWorks, this is done by typing :top (including the colon). On clisp, this is done by repeatedly typing :a (including the colon) until you get out of the "Break" command line. In this example (and usuallly) you only need to type it once.


[On osf1...]
CL-USER 4 > (loop)             [Press Return at this point,
                                and you go into an infinite loop]

                               [Now press Control-C, and you get...]

Break.
  1 (continue) Return from break.
  2 (abort) Return to level 0.
  3 Restart top-level loop.

Type :b for backtrace, :c <option number> to proceed,
or :? for other options

CL-USER 5 : 1 > :top

CL-USER 6 >


[On chrono...] [1]> (loop) [Press Return at this point, and you go into an infinite loop] [Now press Control-C, and you get...] ** - Continuable Error EVAL: User break If you continue (by typing 'continue'): Continue execution 1. Break [2]> :a [3]>
You can quit your lisp session by getting to the command line (possibly through pressing Control-C), then typing (quit) and pressing return. Here are examples using Lispworks or using clisp.

[On osf1...]
CL-USER 4 > (quit)
osf1.gmu.edu>


[On chrono...] [1]> (quit) Bye. chrono[~]>



Evaluating Simple Expressions

From now on, we will only use examples in clisp. But it works basicallly the same on all Lisp systems.

An expression is something that is evaluated, by which we mean, submitted to Lisp and executed. All things that are evaluated will return a value. If you type in an expression at the command line, Lisp will print its value before it returns the command line to you.

Numbers are expressions. The value of a number is itself. Lisp can represent a great many kind of numbers: integers, floating-point expressions, fractions, giant numbers, complex numbers, etc.

A fraction is straightforwardly represented with the form x/y Note that here the / does not mean "divide".

A complex number a+bi takes the form #C(a b)


[3]> -3    
-3
[4]> 2.43
2.43
[5]> 1233423039234123234113232340129234923412312302349234102392344123
1233423039234123234113232340129234923412312302349234102392344123
[6]> #C(3.2 2)             [the complex number 3.2 + 2i ]
#C(3.2 2)
[7]> 2/3                   [the fraction 2/3.  NOT "divide 2 by 3"]
2/3
[8]> -3.2e25               [the number -3.2 x 10^25]
-3.2E25
[9]>

Individual characters are expressions. Like a number, the value of a character is itself. A character is represented using the #\ syntax. For example, #\A is the character 'A'. #\% is the character '%'.

Control characters have very straightforward formats:

#\tab
#\newline
#\space
#\backspace
#\escape

(etc.)


[3]> #\g    
#\g
[4]> #\{
#\{
[5]> #\space
#\Space
[6]> #\newline
#\Newline
[7]> #\\       [The character '\']
#\\
[8]>

Strings are expressions. Just like a numbers and characters, the value of a string is itself.

A Lisp string is a sequence of characters. Lisp strings begin and end with double-quotes. Unlike in C++ (but like Java) a Lisp string does not terminate with a \0.

Like C++ and Java, Lisp strings have an escape sequence to put special characters in the string. The escape sequence begins with the backslash \ . To put a double-quote in the middle of a string, the sequence is \" To put a backslash in the middle of a string, the sequence is \\ Lisp tries to return values in a format that could be typed right back in again. Thus, it will also print return values with the escape sequences shown.

Unlike C++, you do not normally add returns and tabs to strings using an escape sequence. Instead, you just type the tab or the return right in the string itself.


[14]> "Hello, World!"
"Hello, World!"
[15]> "It's a glorious day."
"It's a glorious day."
[16]> "He said \"No Way!\" and then he left."
"He said \"No Way!\" and then he left."
[17]> "I think I need a backslash here:  \\  Ah, that was better."
"I think I need a backslash here:  \\  Ah, that was better."
[18]> "Look, here are      tabs      and some

returns!

Cool, huh?"
"Look, here are      tabs      and some

returns!

Cool, huh?"
[19]> 

In Lisp, the special constant nil (case insensitive) all by itself represents "false". nil evaluates to itself.

Every other expression but nil is considered to be "true". However, Lisp also provides an "official" constant which represents "true", for your convenience. This is t (also case-insensitive). t also evaluates to itself.


[3]> t    
T
[4]> nil
NIL
[5]>




Evaluating Lists as Functions

Lisp program code takes the form of lists. A list begins with a parenthesis, then immediately contains a symbol, then zero or more expressions separated with whitespace, then a closing parenthesis.

We'll discuss the format of symbols further down. In the examples at right, + and * are symbols, and denote the addition and multiplication functions respectively.


[14]> (+ 3 2 7 9)       [add 3+2+7+9 and return the result]
21
[15]> (* 4 2.3)     [multiply 4 by 2.3 and return the result]
9.2

Like everything else in Lisp, lists are expressions. This means that lists return a value when evaluated.

An atom is every expression that is not a list. Among other things, strings and numbers and boolean values are atoms.

When Lisp evaluates a list, it first examines (but does not evaluate) the symbol at the beginning of the list. Usually this symbol is associated with a function. Lisp looks up this function.

Then each expression in the list (except the beginning symbol) is evaluated exactly once, usually (but not necessarily) left-to-right.

The values of these expressions are then passed in as parameters to the function, and the function is called. The list's return value is then the value returned by the function.


[14]> (+ 3 2)     [Look up the + function, evaluate
                  3 and 2 (numbers evaluate to themselves),
                  then pass their values (3 and 2) into the
                  + function, which returns 5, 
                  which is then returned].
5
[15]> (subseq "Hello, World" 2 9)     [Look up the subseq function,
                                       evaluate "Hello, World", 2,
                                       and 9 (they evaluate to 
                                       themselves), then pass their
                                       values in as arguments.  The
                                       subseq function will return
                                       the substring in "Hello, World"
                                       starting at character #2 and
                                       ending just before character #9.
"llo, Wo"


A symbol is a series of characters which typically do not contain whitespace, parentheses ( ), pound ( # ), quote ( ' ), double-quote ( " ), period ( . ), or backquote ( ` ), among a few others. Symbols generally don't take the form of numbers. It's very common for symbols to have hyphens ( - ) or asterisks ( * ) in them -- that's perfectly fine. Symbols are case-INSENSITIVE. Here are some interesting symbols:

+   *   1+   /   string-upcase
reverse   length   sqrt

Guess what function is associated with each of these symbols.

In C++ and in Java, there are operators like +, <<, &&, etc. But in Lisp, there are no operators: instead, there are only functions. For example, + is a function.


[23]> (+ 27/32 32/57)
2563/1824
[24]> (* 2.342 3.2e4)
74944.0
[25]> (* 2.342 9.212 -9.23 3/4)      [You can mix number types]
-149.34949
[26]> (/ 3 5)
3/5                 [The return type stays as general as possible]
[27]> (/ 3.0 5)
0.6                 [Here Lisp had no choice: convert to a float]
[28]> (1+ 3)
4
[29]> (string-upcase "How about that!")
"HOW ABOUT THAT!"
[30]> (reverse "Four score and seven years ago")
"oga sraey neves dna erocs ruoF"
[31]> (length "Four score and seven years ago")
30
[32]> (sqrt 2)   
1.4142135
[33]> (sqrt -1.0)
#C(0 1.0)
[34]> (SqRt -1.0)     [Lisp symbols are case-insensitive]
#C(0 1.0)

While some functions require a fixed number of arguments, other ones (like + or *) can have any number of arguments.

[23]> (+ 100 231 201 921 221 231 -23 12 -34 134)
1994

Other functions have a fixed number of arguments, plus an optional argument at the end.

For example, subseq takes a string followed by one or two numbers. If only one number i is provided, then subseq returns the substring starting a position i in the string and ending at the end of the string.

If two numbers i and j are provided, then subseq returns the substring starting a position i in the string and ending at position j.


[23]> (subseq "Four score and seven years ago" 9)
"e and seven years ago"
[24]> (subseq "Four score and seven years ago" 9 23)
"e and seven ye"

Lisp has a special name for functions which return "true" (usually t) or "false" (nil). These functions are called predicates. Traditionally, many Lisp predicate names end with a p. Here are some predicates.


[5]> (= 4 3)               [is 4 == 3 ? ]
NIL
[6]> (< 3 9)               [is 3 < 9 ?]
T
[7]> (numberp "hello")     [is "foo" a number?]
NIL
[8]> (oddp 9)              [is 9 an odd number?]
T
[9]>

When an expression is evaluated which generates an error, Lisp breaks and returns to the command prompt with a break sequence, just like what happens when you press Control-C.

[26]> (/ 1 0)

*** - division by zero
1. Break [27]> :a       [clisp's way of exiting a break sequence]
[28]>

Errors can also occur if there is no function associated with a given symbol in a list.

[26]> (blah-blah-blah 1 0 "foo")

*** - EVAL: the function BLAH-BLAH-BLAH is undefined
1. Break [27]> :a
[28]>

When a list contains another list among its expressions, the evaluation procedure is recursive. The example at left thus does the following things:

  1. The + function is looked up.
  2. 33 is evaluated (its value is 33).
  3. (* 2.3 4) is evaluated:
    1. The * function is looked up.
    2. 2.3 is evaluated (its value is 2.3)
    3. 4 is evaluated (its value is 4)
    4. 2.3 and 4 are passed to the * function.
    5. The * function returns 9.2. This is the value of (* 2.3 4).
  4. 9 is evaluated (its value is 9).
  5. 33, 9.2, and 9 are passed to the + function.
  6. The + function returns 51.2. This is the value of (+ 33 (* 2.3 4) 9).
  7. The Lisp system returns 51.2.

[44]> (+ 33 (* 2.3 4) 9)
51.2
[45]>

Here are some more examples.

Now you see how easy it is to get lost in the parentheses!


[44]> (+ (length "Hello World") 44)
55
[45]> (* (+ 3 2.3) (/ 3 (- 9 4)))    [in C++: (3+2.3) * (3 / (9-4)) ]
3.1800003
[46]> (log (log (log 234231232234234123)))
1.3052895
[47]> (+ (* (sin 0.3) 
            (sin 0.3))         [expressions may use multiple lines]
         (* (cos 0.3)
            (cos 0.3)))        [ sin(0.3)^2 + cos(0.3)^2 ]
1.0000001                      [ = 1.  Rounding inaccuracy]
[48]> (and (< 3 (* 2 5))
           (not (>= 2 6)))     [ (3 < 2 * 5) && !(2 >= 6) ]
T
[49]>

One particularly useful function is print, which takes the form (print expression-to-print). This function evaluates its argument, then prints it, then returns the argument.

As can be seen at right, if you just use print all by itself, the screen will appear to print the element twice. Why is that? It's because print printed its argument, then returned it, and Lisp always prints [again] the final return value of the expression.

One nice use of print is to stick it in the middle of an expression, where it will print elements without effecting the final return value of the whole expression.


[41]> (print (+ 2 3 4 1))
10
10
[42]> (print "hello")
"hello"
"hello"
[43]> (+ (* 2 3) (/ 3 2) 9)
33/2
[44]> (+ (print (* 2 3)) (print (/ 3 2)) 9)
6 
3/2 
33/2
[45]>




Control Structures and Variables

There are some evaluatable lists which are not functions because they do not obey the function rule ("evaluate each argument exactly one time each"). These lists are known as macros or special forms. For now we will not distinguish between these two terms, though there is a massive difference underneath.

Macros and special forms are mostly used as control structures. For example, the control structure if is a special form. if takes the form:

(if test-expression
    then-expression
    optional-else-expression)

if evaluates test-expression. If this returns true, then if evaluates and returns then-expression, else it evaluates and returns optional-else-expression (or if optional-else-expression is missing, returns nil).

Because if is an expression, unlike most languages it's quite common to see it embedded inside other expressions (like the last expression at right). This is roughly equivalent to C's i?j:k expression form.

Why can't if be a function? Because it may not necessarily evaluate the then-expression, or if it does, it will not evaluate the optional-else-expression. Thus it violates the function rule.


[44]> (if (<= 3 2) (* 3 9) (+ 4 2 3))   [if 3<=2 then return 3*9 
                                                 else return 4+2+3]
9
[45]> (if (> 2 3) 9)    [if 2>3 then return 9 else return nil]
NIL
[46]> (if (= 2 2) (if (> 3 2) 4 6) 9)      [if 2==2,
                                               then if 3>2, 
                                                       then return 4
                                                       else return 6
                                               else return 9]
4
[47]> (+ 4 (if (= 2 2) (* 9 2) 7))    [NOTE: the 'if' evaluates to 18!]
22

if only allows one test-expression, one then-expression, and one optional-else-expression. What if you want to do three things in the then-expression? You need to make a block (a group of expressions executed one-by-one). Blocks are made with the special form progn, which takes the form:
(progn expr1 expr2 expr3 ...)

progn can take any number of expressions, and evaluates each of its expressions in order. progn then returns the value of the last expression.


[44]> (if (> 3 2)
           (progn (print "hello") (print "yo") 
                  (print "whassup?") 9)
           (+ 4 2 3))
"hello" 
"yo" 
"whassup?" 
9

Except when they're at the head of a list, symbols are also expressions. When it's not the head of a list, a symbol represents a variable. When evaluated, a symbol will return the value of a variable.

The value of a symbol's variable has nothing to do with the function, special form, or macro associated with the symbol. You can thus have variables called print, if, etc.

Variables are set with the macro setf. For now, as far as you're concerned, this macro looks like this:

(setf variable-symbol expression)

setf is a macro and not a function because it does not evaluate variable-symbol. Instead, it just evaluates expression, and stores its value in the variable associated with variable-symbol. Then it returns the value of expression.

If a symbol is evaluated before anything has been stored in its variable, it will generate an error.

Be careful with setf. Lisp doesn't need to declare variables before they are used. Therefore, unless variables are declared to be local (discussed later), setf will make global variables. And setf is the first operation we've seen with side effects -- so the order of operations will matter! See the example at right.


[27]> (setf x (* 3 2))
6
[28]> x
6
[29]> (setf y (+ x 3))
9
[30]> (* x y)
54
[31]> (setf sin 9)     [ you really can do this! ]
9
[32]> (sin sin)        [ huh! ]
0.4121185
[33]> z                [ z not set yet ]

*** - EVAL: variable Z has no value
1. Break [34]> :a

[Keep in mind that + is a function, so in most lisp systems it evaluates its
arguments left-to-right.  So x is evaluated -- returning 6; then 
(setf x 3) is evaluated, which sets x to 3 and returns 3; then
x is evaluated -- and now it returns 3.  So + will return 6+3+3]
[35]> (+ x (setf x 3) x)
12
[Just like in C++/Java:   x + (x = 3) + x ]

Because special forms and macros don't obey the function rule, they can take whatever syntax they like. Here is let, a special form which declares local variables:
(let ( declaration1 declaration2 ... )
     expr1
     expr2
     ... )

let declares local variables with each declaration. Then it evaluates the expressions in order (as a block). These expressions are evaluated in the context of these local variables (the expressions can see them). let then gets rid of the local variables and returns the value of the last expression. Thus the local variables are only declared within the scope of the let expression.

A declaration takes one of two forms:

varA symbol representing the variable. It is initialized to nil.
(var expr)A list consisting of the variable symbol followed by an expression. The expression is evaluated and the variable is initialized to that value.

You can use setf to change the value of a local variable inside a let statement. You can also nest let statements within other let statements. Locally declared variables may shadow outer local and global variables with the same name, just as is the case in C++ and in Java.


[1]> (setf x 4)             [x set globally]
4
[2]> (let ((x 3))           [x declared local]
        (print x)
        (setf x 9)          [the local x is set]
        (print x)
        (print "hello"))    [Why does "hello" print twice? Think.]
3 
9 
"hello" 
"hello"
[3]> x               [outside the let, we're back to global again]
4
[4]> (let ((x 3) (y (+ 4 9)))    [declare x and y locally]
        (* x y))
39
[5]> (let ((x 3))              [declare x locally]
        (print x)
        (let (x)               [declare x locally again (nested)]
           (print x)  
           (let ((x "hello"))  [declare x locally again! (nested)]
              (print x))
           (print x))
        (print x) 
        (print "yo"))          [Why does "yo" print twice?]
3 
NIL 
"hello" 
NIL 
3 
"yo" 
"yo"

Another reason a list might be a special form or macro is because it repeatedly evaluates its arguments. One example is dotimes. This macro is an iterator (a looping control structure). Like most iterators in Lisp, dotimes requires a variable. Here's the format:
(dotimes (var high-val
                optional-return-val)
         expr1
         expr2
         ...)

Here, dotimes first evaluates the expression high-val, which should return a positive integer. Then it sets the variable var (which is a symbol, and is not evaluated) to 0. Then it evaluates the zero or more expressions one by one. Then it increments var by 1 and reevaluates the expressions one by one. It does this until var reaches high-val. At this time, optional-return-val is evaluated and returned, or nil is returned if optional-return-val is missing.

You don't need to declare the dotimes variable in an enclosing let -- dotimes declares the variable locally for you. The dotimes variable is local only to the dotimes scope -- when dotimes exits, the variable's value resumes its previous setting (or none at all).


[26]> (setf x 3)
3
[27]> (dotimes (x 4 "yo") (print "hello"))
"hello"
"hello"
"hello"
"hello"
"yo"
[28]> x
3                             [x was local in dotimes]
[29]> (setf bag 2)
2
[30]> (dotimes (x 6) (setf bag (* bag bag)))
NIL                           [No return expression was given]
[31]> bag
18446744073709551616          [ Understand why? ]




Writing Functions

In Lisp, functions are created by calling a function-making macro. This macro is called defun.

A simple version of defun takes the following general form:

(defun function-name-symbol 
            (param1 param2 param3 ...)
    expr1
    expr2
    expr3
    ... )

defun builds a function of zero or more arguments of the local-variable names given by the parameter symbols, then evaluates the expressions one by one, then returns the value of the last expression. The name of the function is the function-name-symbol. defun defines the function, sets it to this symbol, then returns the symbol -- you rarely use the return value of defun.

At right is a really simple example: a function of no arguments which simply returns the string "Hello, World!".


[44]> (defun do-hello-world ( )
          "Hello, World!")  ["Hello, World!" is last expression]
DO-HELLO-WORLD
[45]> (do-hello-world)      [ No arguments ]
"Hello, World!"

Here are some examples with one, two, and three arguments but just one expression.


[44]> (defun add-four (x)
          (+ x 4))  
ADD-FOUR
[45]> (add-four 7)      
11
[46] (defun hypoteneuse (length width)
          (sqrt (+ (* length length) 
                   (* width width))))  
HYPOTENEUSE
[47]> (hypoteneuse 7 9)      
11.401754
[48]> (defun first-n-chars (string n reverse-first)
          (if reverse-first      [if reverse-first is "true" ]
            (subseq (reverse string) 0 n)
            (subseq string 0 n)))
      
FIRST-N-CHARS
[49]> (first-n-chars "hello world" 5 nil)      
"hello"
[50]> (first-n-chars "hello world" 5 t)      
"dlrow"
[51]> (first-n-chars "hello world" 5 18)      [ 18 is "true"! ]
"dlrow"


Here are some examples with several expressions in the function Remember, the function returns the value of the last expression.


[44]> (defun print-string-stuff (string-1)
          (print string-1)
          (print (reverse string-1))
          (print (length string-1))
          string-1)  [ string-1 is returned ]
PRINT-STRING-STUFF
[45]> (print-string-stuff "Hello, World!")      
"Hello, World!" 
"!dlroW ,olleH" 
13 
"Hello, World!"
[46] (setf my-global-counter 0)
0
[47] (defun increment-global-and-multiply (by-me)
          (setf my-global-counter (1+ my-global-counter))
          (* my-global-counter by-me))  
INCREMENT-GLOBAL-AND-MULTIPLY
[48]> (increment-global-and-multiply 3)      
3
[49]> (increment-global-and-multiply 5)      
10
[50]> (increment-global-and-multiply 4)      
12
[51]> (increment-global-and-multiply 7)      
28


Lisp functions can have local variables, control structures, whatnot. Try to use local variables rather than global variables! Declare local variables with let.


[ In C++: long factorial (long n) {
              long sum = 1;
              for (int x=0;x<n;x++)
                  sum = sum * (1 + x);
              return sum; }            ]
[44]> (defun factorial (n)
          (let ((sum 1))
            (dotimes (x n)
              (setf sum (* sum (1+ x))))
            sum))
FACTORIAL
 [ ... but try doing *this* with C++ :-)  ]
[45]> (factorial 1000)
4023872600770937735437024339230039857193748642107146325437999
1042993851239862902059204420848696940480047998861019719605863
1666872994808558901323829669944590997424504087073759918823627
7271887325197795059509952761208749754624970436014182780946464
9629105639388743788648733711918104582578364784997701247663288
9835955735432513185323958463075557409114262417474349347553428
6465766116677973966688202912073791438537195882498081268678383
7455973174613608537953452422158659320192809087829730843139284
4403281231558611036976801357304216168747609675871348312025478
5893207671691324484262361314125087802080002616831510273418279
7770478463586817016436502415369139828126481021309276124489635
9928705114964975419909342221566832572080821333186116811553615
8365469840467089756029009505376164758477284218896796462449451
6076535340819890138544248798495995331910172335555660213945039
9736280750137837615307127761926849034352625200015888535147331
6117021039681759215109077880193931781141945452572238655414610
6289218796022383897147608850627686296714667469756291123408243
9208160153780889893964518263243671616762179168909779911903754
0312746222899880051954444142820121873617459926429565817466283
0295557029902432415318161721046583203678690611726015878352075
1516284225540265170483304226143974286933061690897968482590125
4583271682264580665267699586526822728070757813918581788896522
0816434834482599326604336766017699961283186078838615027946595
5131156552036093988180612138558600301435694527224206344631797
4605946825731037900840244324384656572450144028218852524709351
9062092902313649327349756551395872055965422874977401141334696
2715422845862377387538230483865688976461927383814900140767310
4466402598994902222217659043399018860185665264850617997023561
9389701786004081188972991831102117122984590164192106888438712
1855646124960798722908519296819372388642614839657382291123125
0241866493531439701374285319266498753372189406942814341185201
5801412334482801505139969429015348307764456909907315243327828
8269864602789864321139083506217095002597389863554277196742822
2487575867657523442202075736305694988250879689281627538488633
9690995982628095612145099487170124451646126037902930912088908
6942028510640182154399457156805941872748998094254742173582401
0636774045957417851608292301353580818400969963725242305608559
0370062427124341690900415369010593398383577793941097002775347
2000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000
000000

Actually, it is surprisingly rare in Lisp to have more than one expression in a function. Instead, expressions tend to get nested together. Lisp functions tend to take on functional form rather than declarative form. In C++ or Java, usually you set local variables a lot. In Lisp you don't -- you nest functions.


[ a declarative style -- yuck ]
[44]> (defun my-equation (n)
          (let (x y z)
            (setf x (sin n))
            (setf y (cos n))
            (setf z (* x y))
            (+ n z)))
MY-EQUATION
 [ ... a functional style  ]
[45]> (defun my-equation (n)
          (+ n (* (sin n) (cos n))))
MY-EQUATION

Like Java, Lisp is pass-by-value. The parameters of a function are considered to be local variables to that function, and can be set with setf. This does not change the values of things passed in.


[44]> (defun weird-function (n)
            (setf n 4)
            n)
WEIRD-FUNCTION
[45]> (setf abc 17) 
17
[46]> (weird-function abc)
4
[47]> abc
17

You can also make recursive functions. Lisp style often makes heavy use of recursion.

You'll find that functional style and recursion together result in a need for very few local variables.

Here's the factorial function again, only done recursively.


[44]> (defun factorial (n)
          (if (<= n 0)
            1
            (* n (factorial (- n 1)))))

FACTORIAL

You can make functions with an optional argument using the special term &optional, followed by the optional parameter name, at the end of your parameter list.

If the optional parameter isn't provided when the function is called, then the parameter is set to nil.

Alternatively you can provide the default value to set the parameter to when it's not provided when the function is called. You can do this by following &optional not by a parameter name but by a list of the form (param-name default-value)

You can have only one optional parameter.


[48]> (defun first-n-chars (string n &optional reverse-first)
          (if reverse-first
            (subseq (reverse string) 0 n)
            (subseq string 0 n)))

REVERSE-FIRST
[49]> (first-n-chars "hello world" 5 nil)      
"hello"
[50]> (first-n-chars "hello world" 5)  [ nil is default]
"hello"
[51]> (first-n-chars "hello world" 5 t)
"dlrow"
[52]> (defun multiply-then-maybe-add (x y &optional (z 0) )
          (+ (* x y) z))
MULTIPLY-THEN-MAYBE-ADD
[53]> (multiply-then-maybe-add 9 2)
18
[54]> (multiply-then-maybe-add 9 2 7)
25

Lisp can also have keyword parameters. These are parameters which can appear or not appear, or be in any order, because they're given names. Keyword parameters are very much like the <foo arg1=val arg2=val ... > arguments in the "foo" html tag.

Keyword parameters appear at the end of a parameter list, after the term &key. Similarly to optional arguments, each keyword parameter is either a parameter name (whose value defaults to nil if not passed in when the function is called) or is a list of the form (param-name default-value)

Keyword parameters may appear only at the end of the parameter list.

You pass a keyword parameter whose name is foo into a function by using the term :foo followed by the value to set foo to. Keyword parameters can be passed in in any order, but must appear at the end of the parameter list.

Though it's possible to have both keyword parameters and optional parameters in the same function, don't do it. Gets confusing.

Many built-in Lisp functions use lots of keyword parameters to "extend" them!


[48]> (defun first-n-chars (string n 
                  &key reverse-first  nil by default
                       (capitalize-first t) )   t by default
          (let ((val (if capitalize-first 
                              (string-upcase string)
                              string)))
            (if reverse-first
              (subseq (reverse val) 0 n)
              (subseq val 0 n))))
 [ take a while to understand the LET before going on... ] 

FIRST-N-CHARS
[49]> (first-n-chars "hello world" 5 :reverse-first t)      
"DLROW"
[50]> (first-n-chars "hello world" 5 
            :reverse-first t :capitalize-first nil)      
"dlrow"
[51]> (first-n-chars "hello world" 5 
            :capitalize-first nil :reverse-first t )      
"dlrow"
[52]> (first-n-chars "hello world" 5)      
"HELLO"
[53]> (first-n-chars "hello world" 5 :capitalize-first nil)      
"hello"




Lists and Symbols as Data

Lists are normally evaluated as function or macro calls. Symbols are normally evaluated as variable references. But they don't have to be. Lists and symbols are data as well!

The special form quote can be used to bypass the evaluation of its argument. quote takes a single argument, and instead of evaluating that argument, it simply returns the argument as you had typed it ... as data!


[48]> (quote (hello world 1 2 3))

(HELLO WORLD 1 2 3)
[49]> (quote (what is (going on) here?))      
(WHAT IS (GOING ON) HERE?)
[50]> (quote my-symbol)      
MY-SYMBOL
[51]> (quote (+ 4 (* 3 2 9)))      
(+ 4 (* 3 2 9))

What is a symbol when used in data form? It's just itself. The symbol foo is just a thing that looks like foo (case insensitive of course). It is a data type like any other. You can set variables to it.

What is a list when used in data form? A list is a singly-linked list. It is a data type like any other. You can set variables to it. There are a great many functions which operate on lists as well.

first returns the first item in a list. The old name of first is car.

rest returns a list consisting of everything but the first item. It does not damage the original list. The old name of rest is cdr.

append hooks multiple lists together.

cons takes an item and a list, and returns a new list consisting of the old list with the item tacked on the front.


[48]> (setf my-variable (quote hello))

HELLO
[49]> my-variable    [ stores the symbol HELLO ]
HELLO
[50]> (setf my-variable (quote (hey yo yo)))
(HEY YO YO)
[51]> my-variable      
(HEY YO YO)
[52]> (setf var2 (first my-variable))
HEY
[53]> (setf var3 (rest my-variable))
(YO YO)
[54]> (cons 4 (rest my-variable))
(4 YO YO)
[55]> (append my-variable (quote (a b c)) my-variable)
(HEY YO YO A B C HEY YO YO)
[56]> my-variable
(HEY YO YO)     [ See?  No damage ]
[57]> (quote "hello")
"hello"     [ makes no difference ]
[58]> (quote 4.3)
4.3     [ makes no difference ]


quote is so common that there is a special abbreviation for it...a single quote at the beginning of the item:

'hello-there

...is the same as...

(quote hello-there)

Here's how it's done for lists:

'(a b c d e)

...is the same as...

(quote (a b c d e))

Here's a repeat of some the previous code, but with the abbreviation.


[48]> (setf my-variable 'hello)
HELLO
[50]> (setf my-variable '(hey yo yo))
(HEY YO YO)
[55]> (append my-variable '(a b c) my-variable)
(HEY YO YO A B C HEY YO YO)
[57]> '"hello"
"hello"     [ makes no difference ]
[58]> '4.3
4.3     [ makes no difference ]


Lists as data can of course contain sublists.

In data form, the first item of a list can be anything -- it's not restricted to be just a symbol.


[48]> '(123.32 "hello" (how are (you there)) a)
(123.32 "hello" (HOW ARE (YOU THERE)) A)
[49]> '(((wow)) a list consisting of a list of a list!)
(((WOW)) A LIST CONSISTING OF A LIST OF A LIST!)

nil isn't just "false". It's also the empty list, '()


[48]> '()
NIL
[49]> (rest '(list-of-one-thing))
NIL
[50]> (append '(list-of-one-thing) nil)
(LIST-OF-ONE-THING)
[51]> '(a b c () g h i)
(A B C NIL G H I)

Lists have a common control structure, dolist, which iterates over a list. The format of dolist is very similar to dotimes:

(dolist (var list-to-iterate-over
                optional-return-val)
         expr1
         expr2
         ...)

dolist evaluates the list-to-iterate-over, then one by one sets var to each element in the list, and evaluates the expressions. dolist then returns the optional return value, else nil if none is provided.


[48]> (dolist (x '(a b c d e))
          (print x))
A 
B 
C 
D 
E 
NIL
[49]> (defun my-reverse (list)
          (let (new-list)   [initially nil, or empty list] 
            (dolist (x list)
              (setf new-list (cons x new-list)))
            new-list))
MY-REVERSE
[50]> (my-reverse '(a b c d e f g))
(G F E D C B A)

Lists and strings share a common supertype, sequences.

There are a great many sequence functions. All sequence functions work on any kind of sequence (including strings and lists). Here are two sequence functions we've seen so far.


[48]> (reverse '(a b c d e))
(E D C B A)
[49]> (reverse "abcde")
"edcba"
[50]> (subseq "Hello World" 2 9)
"llo Wor"
[51]> (subseq '(yo hello there how are you) 2 4)
(THERE HOW)




Loading and Compiling Lisp

Lisp is both an interpreter and a compiler.

If you type in code at the command line, it is (on most Lisp systems) interpreted.

You can compile a function by passing its symbol name (quoted!) to the compile function.

You can time the speed of any expression, and its garbage collection, with the time function.


[48]> (defun slow-function (a)
       (dotimes (x 100000)
          (setf a (+ a 1)))
       a)

SLOW-FUNCTION
[49]> (time (slow-function 0))

Real time: 1.197806 sec.
Run time: 1.15 sec.
Space: 0 Bytes
100000

[50]> (compile 'slow-function)
SLOW-FUNCTION ;
NIL ;
NIL

[51]> (time (slow-function 0))

Real time: 0.066849 sec.
Run time: 0.07 sec.
Space: 0 Bytes
100000

You don't have to type all your code in on the command line. Instead, put it in a file named "myfile.lisp" (or whatever, so long as it ends in ".lisp"). Then load it with the load command.

load works exactly as if you had typed in the code directly at the command line.

By default, load is fairly silent -- it doesn't print out all the return values to the screen like you'd get if you typed the code in at the command line. If you'd like to see these return values printed out, you can add the :print t keyword parameter.

You can load and reload files to your heart's content.


[ Make a file called "myfile.lisp", containing this: ]
(setf foo 3)
(defun my-func ()
       (print 'hello))
foo
(sin foo)
(my-func)

[ At the command line, you type: ] [49]> (load "myfile.lisp") ;; Loading file myfile.lisp ... HELLO [ because we called (my-func), which printed ] ;; Loading of file myfile.lisp is finished. T [ load returns t ] [ To get the return values for each item entered in: ] [50]> (load "myfile.lisp" :print t) ;; Loading file myfile.lisp ... 3 MYFUNC 3 0.14112 HELLO HELLO ;; Loading of file myfile.lisp is finished. T
You can also compile a whole file with the compile-file function.

When a file is compiled, the object file created has a .fas or .fsl or .fasl or .afasl extension. Depends on the Lisp compiler.

You load object files with the load function as well.

You can omit the extension (".lisp", ".afasl", etc.) from the filename, but what happens as a result is implementation-dependent. Some systems load the most recent version (either the source or the .afasl file); others may load the .afasl file always but warn you if there's a more recent .lisp file, etc. In general, to be safe, always load the full name of the file including the extension.

When the compiler compiles the file, one common thing it will complain of is special variables. For all intents and purposes, a special variable is a global variable. With very few exceptions, you should never use global variables when you can use local variables instead.

In our file we had declared a global variable (foo). Look at the warnings when we compile!


[18]> (compile-file "myfile.lisp")

Compiling file myfile.lisp ...
WARNING in function #:TOP-LEVEL-FORM-1 in line 1 :
FOO is neither declared nor bound,
it will be treated as if it were declared SPECIAL.
WARNING in function #:TOP-LEVEL-FORM-3 in lines 4..5 :
FOO is neither declared nor bound,
it will be treated as if it were declared SPECIAL.
WARNING in function #:TOP-LEVEL-FORM-4 in line 5 :
FOO is neither declared nor bound,
it will be treated as if it were declared SPECIAL.

Compilation of file myfile.lisp is finished.
The following special variables were not defined:
 FOO
0 errors, 3 warnings
#P"myfile.fas" ;
3 ;
3

[19]> (load "myfile.fas")
;; Loading file myfile.fas ...
HELLO 
;; Loading of file myfile.fas is finished.
T



Lisp Style

As you can see, Lisp can get quite confusing because of the parentheses. How tedious it is reading code based on parentheses! That's why Lisp programmers don't do it.

Lisp programmers don't rely much on the parentheses when reading code. Instead, they rely heavily on breaking expressions into multiple lines and indenting them in a very peculiar way. There is a "cannonical" indent format and style for Lisp. Code which adheres to the standard format can be read very rapidly by Lisp programmers who have developed a "batting eye" for this format.

Important formatting rules:

  • Put a single space between each item in a list.
  • Do NOT put space between the opening parenthesis and the first item in a list. Similarly, do NOT put space between the closing parenthesis and the last item.
  • Never put parentheses all by themselves on lines like a C++/Java brace. Do not be afraid to pile up parentheses at the end of a line.

Do NOT use simplistic editors like pico or Windows Notepad. You will regret it. Deeply. Use an editor designed for Lisp. Integrated Lisp systems (the big three are Franz Allegro Common Lisp, Xanalys Harlequin Common Lisp, and Macintosh Common Lisp) with graphical interfaces have built-in editors which will automatically indent text for you in the official style, will colorize your text, will tell you whether your syntax is right or not, and will match parentheses for you.

Another good choice, indeed the classic option in Lisp systems, is the editor emacs. It is written in its own version of Lisp, and is very good at editing Lisp code and working with Lisp systems, especially with an add-on Lisp-editing plug-in called slime. emacs is the program whose auto-indent facilities established the "cannonical" style of Lisp formatting.

If you can't find an editor which can do the cannonical style, there are still plenty of choices which do a reasonable job. Any professional-grade code editor will do in a pinch. Without a good editor, writing large Lisp programs is painful. GET A CODE EDITOR. You are an adult now, and will soon be a professional. Use real tools to get your job done.

[BAD Lisp Style Formatting Examples]

(if(< (* 3 4)5)(sin(+ 3 x) ) ( - x y ))


(If
    (< 
       (* 3 4)
       5
    )
    (SIN
       (+ 3 x)
    )
    (- x y )
)

[A reasonably GOOD Lisp Style Formatting Example]

(if (< (* 3 4) 5)
      (sin (+ 3 x))
      (- x y))

[A more canonical Lisp Indent Format]

(if (< (* 3 4) 5)
    (sin (+ 3 x))
  (- x y))

Comments in Lisp are of three forms.

Winged comments (the equivalent of /* and */ in C++ or Java) begin with a #| and end with a |# They are not commonly used in Lisp except to temporarily eliminate chunks of code, because it's hard to tell they exist by examining your code.

Inline comments (the equivalent of // in C++ or Java) begin with a semicolon ; and end with a return.

Many Lisp structures have built-in documentation comments. For example, if the first expression in a defun statement is a string, that string is not part of the code but instead is considered to be the "documentation" for the function. You can access the documentation for an object with the documentation function.

It is common in Lisp to pile up several semicolons ;; or ;;; to make the comment more visible.

Here is a common approach:

  • Use one semicolon for inline code.
  • Use two semicolons to comment the head of a function.
  • Use three semicolons to comment the head of a file or other big region.
  • Use winged comments only to comment-out a region temporarily.

[A well-commented file]
;;; pi-estimation package
;;; Sean Luke
;;; Wednesday, 8/21/2002



;; ESTIMATE-PI will compute the value of pi to
;; the degree given, maintaining the value as a giant
;; fraction.  It uses the Leibniz (1674)
;; formula of pi = 4 * ( 1/1 - 1/3 + 1/5 - 1/7 + ...  )
;; degree must be an integer > 0.

(defun estimate-pi (degree)
  "Estimates pi using Leibniz's formula.
degree must be an integer greater than 0."
  (let ((sum 0) (inc 1))                ; inc goes 1, 5, 7, ...
    (dotimes (x degree (* 4 sum))       ; we return 4*sum
         #| (setf sum (+ sum (/ 1 inc))
                 (- 0 (/ 1 (+ inc 2)))) |#     ; yucky
      (setf sum (+ sum (/ 1 inc) (/ -1 (+ inc 2))))
      (setf inc (+ 4 inc)))))



[...after estimate-pi has been entered into Lisp...] [13]> (documentation 'estimate-pi 'function) "Estimates pi using Leibniz's formula. degree must be an integer greater than 0." [14]> (describe 'estimate-pi) [Get ready for more information than you really need!] ESTIMATE-PI is the symbol ESTIMATE-PI, lies in #<PACKAGE COMMON-LISP-USER>, is accessible in the package COMMON-LISP-USER, names a function, has the properties SYSTEM::DOCUMENTATION-STRINGS, SYSTEM::DEFINITION. Documentation as a FUNCTION: Estimates pi using Leibniz's formula. degree must be an integer greater than 0. For more information, evaluate (SYMBOL-PLIST 'ESTIMATE-PI). #<PACKAGE COMMON-LISP-USER> is the package named COMMON-LISP-USER. It has the nicknames CL-USER, USER.It imports the external symbols of the packages COMMON-LISP, EXT and exports no symbols, but no package uses these exports. #<CLOSURE ESTIMATE-PI (DEGREE) (DECLARE #) (BLOCK ESTIMATE-PI #)> is an interpreted function. argument list: (DEGREE)
Lisp has important style rules about symbols, used for both variables and function names.
  • Although Lisp symbols are case-insensitive, ALWAYS use lower-case. There is a good reason for this. Keep in mind that Lisp is an interactive system: both you and the system are producing text on the screen. Lisp systems spit out symbols in UPPER-CASE. By sticking with lower-case yourself, you can distinguish between the text you typed and the text the Lisp system generated.
  • Do NOT use underscores in symbols. Use hyphens.
  • Although the previous examples above didn't do it to avoid confusing you, you should always denote global variables by wrapping them with *asterisks*. Global variable names should also be self-explanatory.
  • Variable names should be nouns.
  • Function names should be verbs.
  • Though you can always name variables the same names as functions, it's more readable not to do so.

[BAD Lisp Style Symbols:]
my_symbol_name
mySymbolName
MySymbolName
MY_SYMBOL_NAME         


[A GOOD Lisp Style Symbol]
my-symbol-name



[A BAD Global Variable Name]
aprintf


[A GOOD Global Variable Name]
*alpha-print-format*


Lisp is a functional language. Learn to use functional style. One way you can tell you're using functional style is if you have very few (or even no) local variables, and rarely if ever use a global variable.

As Paul Graham says, "treat setf as if there were a tax on its use."


[HORRIBLE Lisp Style]

(defun do-the-math (x y z)
	(setf w (+ x y))
	(setf n (* z w))
	(+ x n))



[MERELY BAD Lisp Style -- no global variables]

(defun do-the-math (x y z)
	(let (w n)
		(setf w (+ x y))
		(setf n (* z w))
		(+ x n)))



[BETTER Lisp Style -- functional style]

(defun do-the-math (x y z)
  (+ x (* z (+ x y))))	



Declare your global variables once with defparameter before you start using them in setf statements.
(defparameter var-symbol initial-value
      optional-documentation-string)

Declare global constants with defconstant.

(defconstant var-symbol value 
      optional-documentation-string)

The documentation strings can be accessed via documentation, and of course, describe.



[13]> (defparameter *tuning-value* 4.0 
      "The tuning value of the amplitude dial")
*TUNING-VALUE*
[14]> (defconstant *low-quality-pi* 3.14159
      "Pi to only six digits")
*LOW-QUALITY-PI*
[15]> (documentation '*tuning-value* 'variable)
"The tuning value of the amplitude dial"
[16]> (describe '*low-quality-pi*)

*LOW-QUALITY-PI* is the symbol *LOW-QUALITY-PI*, 
lies in #<PACKAGE COMMON-LISP-USER>, is accessible 
in the package COMMON-LISP-USER, a constant, 
value: 3.14159, has the property SYSTEM::DOCUMENTATION-STRINGS.
Documentation as a VARIABLE:
Pi to only six digits
For more information, evaluate (SYMBOL-PLIST '*LOW-QUALITY-PI*).

#<PACKAGE COMMON-LISP-USER> is the package named 
COMMON-LISP-USER. It has the nicknames CL-USER, USER.
It imports the external symbols of the packages 
COMMON-LISP, EXT and exports no symbols, but no 
package uses these exports.

3.14159 is a float with 24 bits of mantissa (single-float).