Simply Scheme Appendix B: Common Lisp Simply Scheme: Introducing Computer Science 2/e Copyright (C) 1999 MIT

Appendix B

Common Lisp

cover photo
Brian Harvey
University of California, Berkeley
Matthew Wright
University of California, Santa Barbara

Download PDF version
Back to Table of Contents
BACK chapter thread NEXT
MIT Press web page for Simply Scheme

The two most popular dialects of Lisp are Scheme and Common Lisp. This appendix, which assumes that you have finished the rest of this book, describes the most important differences between Scheme and Common Lisp so that you will be able to use Common Lisp if you need to. Common Lisp is the most popular language among Artificial Intelligence researchers, so AI courses often use Common Lisp.

Why Common Lisp Exists

Since the beginning of Lisp, many versions of the language were developed. Each dialect reflected different ideas about the most important capabilities to include in the language. This diversity made Lisp an exciting arena for research, but it also meant that a Lisp program written for one dialect couldn't be used elsewhere.

In 1984, a group of Lisp developers decided to define a version of Lisp that would combine the capabilities of all their favorite dialects, so that in the future they would all use the same language; thus the name "Common" Lisp. Common Lisp was not the first attempt at a universal Lisp dialect, but it was more successful than earlier efforts. In 1985 a revision of the language was begun under the aegis of ANSI, the American National Standards Institute. This ANSI sponsorship gave Common Lisp an official status that has contributed to its growing acceptance.

Since Common Lisp was designed by combining the capabilities of many earlier dialects, it's an enormous language with nearly 1000 primitives, including versions of several programs in this book. There is a primitive sort procedure, a procedure like number-name that spells numbers in English, and a substitute procedure identical to the one you wrote in an exercise, to name a few.

If you're writing your own programs in Common Lisp, you can ignore all the extra features and just use the capabilities you already know from Scheme. If you're trying to read someone else's Common Lisp program, we expect that you will have to look up many primitive procedures in a reference manual.

Defining Procedures and Variables

One minor difference between Scheme and Common Lisp is in the way procedures are defined. In Common Lisp,

(defun square (x)
  (* x x))

means the same as Scheme's

(define (square x)
  (* x x))

In Scheme, define is used both for procedures and for variables whose values aren't procedures. In Common Lisp, procedures are given names by a mechanism separate from the general variable mechanism; defun is only for procedures. To define a variable, use defvar:

common-lisp> (defvar x 6)
6

common-lisp> x
6

In Common Lisp, defvar returns the name of the variable you define. If a variable has already been defined, defvar will not change its value; for that you must use setq.

The Naming Convention for Predicates

In Common Lisp, names of predicate procedures end in a "p" (for "predicate") instead of a question mark. Unfortunately, this convention isn't followed strictly. For example, Common Lisp's version of the null? predicate is just "null," not "nullp."

No Words or Sentences

We've mentioned that Scheme doesn't really have words and sentences built in; neither does Common Lisp. So none of the following procedures have Common Lisp equivalents: accumulate, appearances, before?, bf, bl, butfirst, butlast, count, empty?, every, first, item, keep, last, member?, se, sentence, word, and word?. (Common Lisp does have lists, though, and list-related procedures such as map, reduce, append, and so on do have equivalents.)

True and False

Common Lisp doesn't have the Boolean values #t and #f. Instead, it has a single false value, nil, which is also the empty list.

common-lisp> (= 2 3)
NIL

common-lisp> (cdr '(one-word-list))
NIL

common-lisp> '()
NIL

Nil is a strange beast in Common Lisp. It isn't a variable with the empty list as its value; it's a special self-evaluating symbol. There is also t, a self-evaluating symbol with a true value.

common-lisp> 'nil
NIL

common-lisp> nil
NIL

common-lisp> t
T

Like Scheme, Common Lisp treats every non-false (i.e., non-nil) value as true. But be careful; in Common Lisp

common-lisp> (if (cdr '(one-word-list)) 'yes 'no)

has the value NO, because the empty list is nil.

In Common Lisp's cond, there is no equivalent to else; Common Lisp programmers instead use t as the condition for their last clause, like this:

(defun sign (n)
  (cond ((> n 0) 'positive)
	((= n 0) 'zero)
	(t 'negative)))

Files

Common Lisp's mechanism for dealing with files is trivially different from Scheme's. What Scheme calls "ports," Common Lisp calls "streams." Also, there is only one procedure for opening streams; the direction is specified this way:

common-lisp> (defvar out-stream (open "outfile" :direction :output))
#<OUTPUT STREAM "outfile">

common-lisp> (close out-stream)
T

common-lisp> (defvar in-stream (open "infile" :direction :input))
#<INPUT STREAM "infile">

common-lisp> (close in-stream)
T

Note that the close procedure closes both input streams and output streams.

To read from an input stream, you must invoke read with three arguments:

common-lisp> (read stream nil anything)

The nil indicates that reaching the end of the file should not be an error. If read does reach the end of the file, instead of returning a special end-of-file object it returns its third argument. It's possible to choose any value as the indicator for reaching the end of the file:

(let ((next (read stream nil 'xyzzy)))
  (if (equalp next 'xyzzy)
      'done
      (do-something next)))

It's important to choose an end-of-file indicator that couldn't otherwise appear as a value in the file.

Arrays

In Common Lisp, vectors are just a special case of the multidimensional array data type that you invented in Exercise 23.15. There are quite a few differences between Common Lisp arrays and Scheme vectors, none very difficult, but too numerous to describe here. If you need to use arrays, read about them in a Common Lisp book.

Equivalents to Scheme Primitives

Other than the word and sentence procedures, here is a table of the Scheme primitives from the table on page funlist that have different names, slightly different behavior, or do not exist at all in Common Lisp. Scheme procedures not in this list (other than the word and sentence ones) can be used identically in Common Lisp.

SchemeCommon Lisp
align Common Lisp's format primitive has a similar purpose
begin progn
boolean? Doesn't exist; see the section in this appendix about true and false values.
c...r The same, but (c...r nil) is nil instead of an error.
children You can use our version from Chapter 18.
close-...-port close
close-all-ports    Doesn't exist.
cond The same, except for else; use t instead.
datum You can use our version from Chapter 18.
define Either defun, for procedure, or defvar, otherwise.
display princ
eof-object? See the section on files.
equal? equalp
even? evenp
filter remove-if-not
for-each mapc
integer? integerp
lambda Discussed later in this appendix.
list? listp, except that listp also returns true for improper lists.
list-ref nth, except that the arguments come in reverse order.
list->vector See the section about arrays.
make-node You can use our version from Chapter 18.
make-vector See the section about arrays.
map mapcar
newline terpri
null? null
number? numberp
odd? oddp
open-...-file See the section on files.
procedure? functionp
quotient truncate
read Identical except for end of file. See the section on files.
read-line Doesn't exist. (Common Lisp's read-line is like our read-string.)
read-string read-line
reduce The same, but computes (f (f a b) c) instead of (f a (f b c))
remainder rem
repeated Doesn't exist.
show Doesn't exist but easy to write.
show-line Doesn't exist.
vector-anything See the section about arrays.
write prin1

A Separate Name Space for Procedures

All of the differences noted in this table are fairly minor ones, in the sense that the translation needed to account for these differences requires little more than renaming. There is one major conceptual difference between the two languages, however, in the way they treat names of procedures. Common Lisp allows a procedure and a variable to have the same name. For example, the program

(defun three-copies (list)
  (list list list list))

is perfectly legal.

common-lisp> (three-copies '(drive my car))
((DRIVE MY CAR) (DRIVE MY CAR) (DRIVE MY CAR))

How can Common Lisp tell that one of the lists means the primitive procedure, but the other ones mean the formal parameter? Symbols in the first position in a list (right after an open parenthesis) are taken to be names of globally defined procedures.

In Chapter 7 we introduced the image of a blackboard with all the global variables written on it, which all the Scheme little people can see. In Common Lisp, there are two blackboards: one for global variables, just as in Scheme, and another one for procedures. The procedure blackboard contains the primitive procedures and the procedures you define with defun. Names in the first position of an expression are looked up on the procedure blackboard.

Therefore, the names of procedures are not variables and cannot be used as actual argument expressions:

common-lisp> (sqrt 144)
12

common-lisp> (mapcar sqrt '(9 16 25 36))
ERROR: The variable SQRT is unbound.

(Common Lisp's equivalent of map is named mapcar.)

How, then, do you tell Common Lisp that you want to use the procedure named sqrt as data? You must use the function special form.[1]

common-lisp> (function sqrt)
#<PROCEDURE>

common-lisp> (mapcar (function sqrt) '(9 16 25 36))
(3 4 5 6)

Function's job is to look up names on the procedure blackboard. (Function actually has a more general definition, as you'll see in a few paragraphs.)

Lambda

In Common Lisp, as in Scheme, procedures can be named or unnamed. Just as procedure names in Common Lisp are meaningful only in certain contexts, so are lambda expressions. They make sense at the beginning of an expression:

common-lisp> ((lambda (x) (* x x)) 4)
16

or as the argument to function:

common-lisp> (function (lambda (x) (* x x)))
#<PROCEDURE>

common-lisp> (mapcar (function (lambda (x) (* x x))) '(3 4 5 6))
(9 16 25 36)

but they're meaningless on their own:

common-lisp> (lambda (x) (* x x))
ERROR: LAMBDA is not a function

common-lisp> (mapcar (lambda (x) (* x x)) '(3 4 5 6))
ERROR: LAMBDA is not a function

More about Function

The official rule is that function returns the "functional interpretation" of its argument. If the argument is a symbol, that means looking up the procedure associated with that name. If the argument is a lambda expression, it means creating a new procedure. Function uses the same rule that's used to interpret the first element of a procedure invocation.

Since function is a very commonly used special form, it has an abbreviation:

common-lisp> (mapcar #'(lambda (x) (* x x)) '(3 4 5 6))
(9 16 25 36)

common-lisp> (mapcar #'cdr '((hey jude) (eleanor rigby) (yes it is)))
((JUDE) (RIGBY) (IT IS))

Don't confuse

#'(lambda (x) (* x x))

with

'#(lambda (x) (* x x))

The first of these is a function that squares its argument; the second is an array containing three elements.

It's unfortunate that the abbreviation for function contains a single quote mark, because the job of function is nothing like the job of quote. You'll just have to get used to the "hashquote" notation.

Writing Higher-Order Procedures

Think about this attempted translation of the map procedure:

(defun map (fn lst)                          ;; wrong!
  (if (null lst)
      '()
      (cons (fn (car lst))
	    (map fn (cdr lst)))))

(In Common Lisp, null is one of the predicates whose names don't end in "p." Otherwise, this is the same program we showed you in Chapter 19, except for the defun, of course.)

According to our rule about names in the front of a list, this procedure doesn't work. Think about what happens when we say

(map #'square '(1 2 3 4 5))

According to the substitution model, the parameters fn and lst are replaced in the body with #'square and '(1 2 3 4 5). But Common Lisp makes an exception for the first element of a compound expression. It uses the procedure blackboard instead of substitution:

(if (null '(1 2 3 4 5))
    '()
    (cons (fn (car '(1 2 3 4 5))
	  (map #'square (cdr '(1 2 3 4 5))))))

Note that one of the appearances of fn was left unchanged. Since there is no global procedure named fn, this program will produce an error:

common-lisp> (map #'square '(1 2 3 4 5))
ERROR: FN is not a procedure.

How, then, do you write higher-order procedures in Common Lisp? The answer is that you must use funcall:

(defun map (fn lst)
  (if (null lst)
      '()
      (cons (funcall fn (car lst))
	    (map fn (cdr lst)))))

Funcall takes one or more arguments. The first is a procedure and the rest are arguments for that procedure. It applies that procedure to the given arguments.[2] Since fn is no longer at the beginning of a compound expression, the corresponding argument, #'square, is substituted for it.


[1] Common Lisp uses the word "function" to mean "procedure," whether or not the procedure implements a function.

[2] This is a lot like apply, you may have noticed. Look at the difference:

common-lisp> (funcall #'+ 1 2 3)
6

common-lisp> (apply #'+ '(1 2 3))
6

In the first case, each argument to + is a separate argument to funcall. In the second case, a list of the arguments to + is a single argument to apply. Apply always takes exactly two arguments, the procedure and the argument list.

(back to Table of Contents)

BACK chapter thread NEXT

Brian Harvey, bh@cs.berkeley.edu