Lisp is a deep language with many unusual and powerful features. The goal of this tutorial is not to teach you many of those powerful features: rather it's to teach you just enough of Lisp that you can get up and coding quickly if you have a previous background in a procedural language such as C or Java.

Notably this tutorial does not teach macros, CLOS, the condition system, much about packages and symbols, or very much I/O.



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

Just like in a debugger, at any break or error condition, you have a bunch of options (like examining the stack, changing what the return value should be, etc.) You can even continue the infinite loop we just broke out of. But you probably just want to escape. The easiest option is to escape out of all of your error conditions, right back up to the top.

These conditions can be stacked: if you keep working while in a condition, and then get in another condition and so on, you're piling up conditions on a stack.

After you press Control-C, the command line changes to a "subsidiary" command line to reflect that you are in a break or error condition . Kinda like pressing Control-C in a debugger.

On zeus, you start lisp by typing clisp at the command line. This fires up an implementation of lisp called CLISP.

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

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

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.

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

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.

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.

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 .

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

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

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.

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.

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.

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

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

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.

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 .

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.

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.

Guess what function is associated with each of these symbols.

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.

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

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.

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

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.

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).

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 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.

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 .

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.

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

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 .

Variables are set with the macro setf . For now, as far as you're concerned, this macro looks like this: (setf variable-symbol expression )

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.

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

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.

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.

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).

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 )

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

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.

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

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 )

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.

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 )

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

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.

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

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.

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.

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

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

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

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

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 .

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.

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.

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 ...)

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

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

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

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 .

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

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.

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.

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!

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!

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

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.

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 a file is compiled, the object file created has a .fas or .fsl or .fasl or .afasl extension. Depends on the Lisp compiler.

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.

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

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.

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

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

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

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.

. 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.

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))))