Sei sulla pagina 1di 10

CSC 244/444 Notes Sept.

10, 2002

A Qui k Introdu tion to Common Lisp


Lisp is a fun tional language well-suited to sym-
boli AI, based on the - al ulus and with list
stru tures as a very exible basi data type; pro-
grams are themselves list stru tures, and thus an
be reated and manipulated just like other data.

This introdu tion isn't intended to give you all the details, but just enough to get a ross
the essential ideas, and to let you get under way qui kly. The best way to make use of
it is in front of a omputer, trying out all the things mentioned.

Basi hara teristi s of Lisp and Common Lisp:


 Lisp is primarily intended for manipulating symboli data in the form of list stru -
tures, e.g.,
(THREE (BLIND MICE) SEE (HOW (THEY RUN)) !)
 Arithmeti is in luded, e.g.,
(SQRT (+ (* 3 3) (* 4 4))) or (sqrt (+ (* 3 3) (* 4 4)))
(Common Lisp is ase-insensitive, ex ept in strings between quotes " ... ", spe ially
delimited symbols like |Very Unusual Symbol!|, and for hara ters pre xed with
\\").
 Common Lisp (unlike John M Carthy's original \pure" Lisp) has arrays and re ord
stru tures; this leads to more understandable and eÆ ient ode, mu h as in typed
languages, but there is no obligatory typing.
 All omputation onsists of expression evaluation. For instan e, typing in the above
(SQRT ...) expression and hitting the enter key immediately gives 5.
 Lisp is a fun tional language based on Alonzo Chur h's - al ulus (whi h like
Turing ma hines provides a omplete basis for all omputable fun tions). For
instan e, a fun tion for the square root of the sum of two squares an be expressed
as
(lambda (x y) (sqrt (+ (* x x) (* y y)))).
We an save this fun tion by giving it a name using defun (examples will be seen
soon), or we an apply it dire tly, as in
((lambda (x y) (sqrt (+ (* x x) (* y y)))) base height),
where base and height are assumed to be variables that have been assigned some
numeri al values.
 Sin e data are list stru tures and programs are list stru tures, we an manipulate
programs just like data. We an also easily de ne spe ial-purpose list-stru tured

1
languages (e.g., for planning or for NLP) and write interpreters for these languages
in Lisp.
 List stru tures are a very exible data type { it's hard to think of any types of
information that an't be easily represented as list stru tures. And as long as we're
using list stru tures as our data types, we an enter data just by supplying list
stru tures { we need not write spe ial reading or stru ture-building fun tions. For
instan e,
(SETQ X '(THREE (BLIND MICE) SEE (HOW (THEY RUN)) !))
sets the variable X to the indi ated list stru ture value; and
(READ)
will read in any list stru tre. Similarly printing out list stru tures requires no
spe ial printing fun tions (the fun tions PRINT and FORMAT do almost everything
we need). Common Lisp arrays and re ord stru tures are also pretty easy to handle
in I/O.
 The simpli ity and elegan e of Lisp, and its unmat hed exibility and ease of use
for AI appli ations, have made it very durable: it is the se ond-oldest high-level
programming language (after FORTRAN), yet is still in ommon use.

Getting started
Go to the dire tory where you want to work (and where you'll typi ally have various
program les and data les), and type
lisp
The system will respond with loading and initialization messages, followed by a prompt
like
CL-USER(1):
You an now type in expressions and have them evaluated. Whenever you've got balan ed
bra kets and hit enter, the value (or an error message) is printed, and then you're
prompted for further input.

Getting out
To es ape from Common Lisp, type
(exit), or :exit

Saying \Hello"
A ording to N. Wirth (author of ALGOLW and Pas al), a good way to get an initial
glimpse of a language is to see a program that prints \hello". Here's the Lisp version
(just one quoted symbol!):
'hello
When you hit enter, you'll get

2
HELLO
whi h is the result of evaluating 'hello. If you want lower ase, you an use the hara ter
string
"hello"
whi h yields "hello" (still in quotes) { i.e., strings evaluate to themselves. If you want
the quotes to be invisible, you an use
(format t "hello")
However, besides getting \hello" without quotes you'll now also get NIL on a new line;
that's be ause the format fun tion is spe ial, having both an e e t and a value: the e e t
is to print out the material in quotes (plus possibly values of variables { see example
below), and the value is NIL.
But suppose we want a more elaborate greeting, wherein the user is asked for her/his
name. Then we ould de ne a hello-fun tion as follows:
(defun hello ()
(format t "Hello, what's your first name?~%")
(setq *name* (read))
(format t "Ni e to meet you, ~a" *name*) )
Note that the rst argument of defun is a fun tion name, the se ond is a list of arguments
(here, none), and after that we have any number of expressions whi h will be evaluated
in sequen e, and whi h omprise the \body" of the de nition. In e e t, defun just
makes a -expression out of the argument list and the body, and makes this lambda
expression the fun tion-value of the rst argument (the fun tion name). In other words,
it provides a way of naming a -expression. (Note that the fun tion value of a symbol
won't interfere with other ordinary values we might asso iate with it; but generally it's
wise to steer away from su h multiple uses of a symbol.)
The ~% in the rst format statement means \go to new line". The setq expression
sets the global value of *name* to be whatever Lisp expression is read in by (read).
A symbol an have both a global value, and a value lo al to a parti ular fun tion all.
But it's onventional to use an initial and nal \*" for global variables, and to avoid
using these as lo al variables. (We'll see lo al variables in later examples.) The ~a in
the se ond format statement means \print the value of the next expression given as
additional argument of format" { and in this ase the next argument is *name*, and its
value is whatever name the user supplied.
When we type in this fun tion de nition and hit enter, we get
HELLO
whi h is just the name of the fun tion we've de ned. (So even an expression that de nes
a fun tion gets a value.) However, defun is primarily evaluated for its e e t, not its
value, and the e e t as indi ated is that Lisp will now \remember" the de nition of the
hello fun tion.
To exe ute the hello fun tion, we type
(hello)

3
and hit enter, with the result
Hello, what's your first name?
Joe (assumed as user input)
Ni e to meet you, JOE
NIL
The nal NIL is the value returned by the hello fun tion when it terminates. Of ourse,
we an also use the expression (hello) as part of another program, whi h does not
immediately terminate after the greeting.
In general, we an evaluate fun tions for parti ular arguments by writing
(fun tion-name arg1 arg2 ... argn )
Sin e hello had no arguments, we wrote (hello). Ex ept for ertain fun tions like
defun, setq, and a few others, arguments are rst evaluated, and only then is the
fun tion applied to the argument values.

Loading Lisp ode from a le

If you have pla ed Lisp ode (a series of symboli expressions) in a le my-file.lisp,


you an run this ode and then ontinue on-line as follows (assuming you are already in
Lisp, having typed lisp at some point):
(load "myfile.lisp")
assuming that this le is in the same dire tory as the one from whi h you are running
Lisp. You an also use the shorter version (load "myfile"), i.e., without the \.lisp"
extension { but this will use a ompiled version of the le if one exists. If you are user
\smith" and the desired le my-file is in a dire tory lisp-programs, you ould also
use
(load "/u/smith/lisp-programs/my-file.lisp")
(or without the \.lisp"), no matter what dire tory you are urrently in. After this is
evaluated, you an use fun tions and onstants that were de ned in my-file.lisp.
4
Data types
The smallest symboli expressions are atoms, and we build larger expressions out of
these. Atoms ome in several varieties, as indi ated in the following tree:
fixed point, e.g., −17, 3400, ...
numeric fractions (ratios), e.g.,1/2, 8/3, ...
floating point, e.g.,−17.0, 34.5, 2.3E15, ...
atoms
boolean values:T, NIL (= ())
symbols nonboolean,
(literal atoms)
e.g., John, LOVES, Mary123,
123Mary?!, |Strange symbol|,
@%^*+=/~<−>, \(op\.cit\.\)

characters, e.g.,#\a, #\A, #\b, #\B, #\!, #\#, #\Space, ...


(can be printed asa, A, b, !, #, , ...)
strings, e.g., "This is a long string"

As an oddball ategory of literal atoms we should also mention keywords;


these start with a olon (e.g., :key) and have very spe ial uses. A olon in
the middle of an atom also has a spe ial meaning: the part before the olon is
a pa kage name, and the part after it is the name of a fun tion in the pa kage
referred to. But we won't go into that here.

Dotted pairs { dis ussed below


List stru tures { e.g.,
(3 "blind" mi e)
(A B (C D E))
NIL (same as ( ))
(this (list (is (nested to (depth 5) see?))))

Note: In general, expressions are evaluated when they o ur as an argument


(non-initial list element). However, T, NIL, numbers, hara ters, strings and
keywords evaluate to themselves. In addition, quotation { e.g., 'THIS or
'(a b) { prevents evaluation of the expression quoted (in the two examples
we just get ba k THIS and (A B)). Also as previously noted, ertain spe ial
fun tions prevent evaluation of (some of) their arguments (e.g., defun, setq,
et .). Initial list elements are interpreted as fun tions, unless the list is inside
a quoted ontext. So for instan e (+ x y) evaluates to the sum of values
asso iated with x and y, but '(+ x y) just evaluates to the expression (+ x
y).

Arrays { e.g., we an de ne an array A using

5
(setq A (make-array '(3 4) :initial- ontents
'((a b d) 2 3 4)
("this" 5 6 7)
(#\C 8 9 10)) ))

Retrieving a value: (setq value (aref A 2 3)) ) 6


Changing a value: (setf (aref A 2 3) 12)

The :initial- ontents keyword, together with the expression following it


supplying the initial ontents of the array, is optional. Optional parameters
are standardly indi ated with keywords, whi h as mentioned start with a
olon and evaluate to themselves.

Hash tables { e.g.,

(setq A (make-hash-table)) ; reates it


(setf (gethash ' olor A) 'brown) ; sets value of an entry
(setf (gethash 'name A) 'fred) ; sets value of an entry
(gethash ' olor A) ; yields BROWN
(gethash 'name A) ; yields FRED
(gethash 'pointy A) ; yields NIL

Re ord stru tures { e.g.,

(defstru t ourse
name time redits room instru tor)
(setq CSC242 (make- ourse :name "Artifi ial Intelligen e"
:time 'TR3\:00-4\:15
: redits 4
:room 'CSB601
:instru tor "John M Carthy"))
(setf ( ourse-instru tor CSC242) "Marvin Minsky") ; hanges instru tor
( ourse-time CSC242) ; yields |TR3:00-4:15|

Other data stru tures:


fun tions, pa kages, streams, ...

6
Dotted pairs and binary trees
It's usually most onvenient to think of our data (and programs) as atoms and lists.
However, list stru tures are a tually built out of dotted pairs. You an think of these as
pairs of storage lo ations ( ells) where ea h lo ation ontains a pointer either to an atom
or to another dotted pair. In this way we an build up arbitrary binary trees, and these
an be used to represent list stru tures. (But while all list stru tures an be represented
as binary trees, not all binary trees represent list stru tures; so dotted pairs in prin iple
provide slightly more exibility than list stru tures.) Here are examples of how we build
list stru tures out of dotted pairs:
(A) is really (A . NIL), or internally, Here denotes a
pointer to NIL
A

(A B) is really (A . (B . NIL)), or internally,

as tree drawn more


like a list:
A
A B
B

(A B C) is really (A . (B . (C . NIL))), i.e.,

A B C

(A B (C D E)) −− suppose this is the value of X; then we have

A B

C D E

An example showing that not all binary trees are lists is the following tree:

As a dotted pair structure this is


(A . (B . C))
A
(also written as (A B . C)), where
B C we can’t get rid of all the dots

The left part of a dotted pair (i.e., the destination of the left pointer) is alled its CAR,
and the right part its CDR (pronoun ed \ ould'r"). CAR also has the alternative name
first, sin e it pi ks out the rst element of a list, as seen in the following.

( ar '(A)) is the same as ( ar '(A . NIL)) whi h yields A


( dr '(A)) is the same as ( dr '(A . NIL)) whi h yields NIL

( ar '(A B)) is the same as ( ar '(A . (B . NIL)) whi h yields A

7
( dr '(A B)) is the same as ( dr '(A . (B . NIL)) whi h yields
(B . NIL),
i.e., (B)
Similarly ( ar '(A B C)) yields A "first of list"
( dr '(A B C)) yields (B C) "rest of list"

There are also fun tions se ond, third, ..., tenth for easy a ess to the rst few ele-
ments of a list, though we ould also use ( ar ( dr ...)), ( ar ( dr ( dr ...))),
et . Additional \easy a ess" fun tions you should know about are aar, adr, dar,
ddr, aaar, ... ddddr as well as nth, nth dr, and last (whi h does not give
the last element of a list, but rather the last dotted pair, i.e., a list ontaining just the
last element). Here are some more examples, assuming that we have de ned x by the
indi ated setq:

(setq x '(A B (C D E)))

( ar x) ==> A
( dr x) ==> (B (C D E))
( ar ( dr x)) = ( adr x) ==> B
( dr ( dr x)) = ( ddr x) ==> ((C D E))
( ar ( dr ( dr x))) = ( addr x) ==> (C D E)
( dr ( dr ( dr x))) = ( dddr x) ==> NIL
(first (third x)) = ( aaddr x) ==> C
(se ond (third x)) ==> D
(last (third x)) ==> (E)

Constru ting a dotted pair


CONS onstru ts a new dotted pair and returns a pointer to it. Examples:
( ons 'A 'B) ==> (A . B)
( ons 'A NIL) ==> (A . NIL) = (A)
When the se ond argument of a CONS is a list, we an think of its operation as inserting
the rst argument at the head of the list given as se ond argument. Thus
new dotted
(CONS ’A ’(B C)) yields (A B C) pair

B C
(CONS ’(A B) ’(C (D E))) yields ((A B) C (D E))

(CONS ’( ) ’( )) yields (( )) = (NIL)

etc.

8
Basi me hanism: expression evaluation
Note that expressions like
yielding
~~~~~~~~
'hello HELLO
(load "my-file") NIL
(setq n 5) 5
( ar '(a b )) A
( ons 3 n) (3 . 5)

are omplete stand-alone programs.


This is in ontrast with other programming languages, where expressions analogous
to these ould only o ur within the body of some fun tion or pro edure de nition
(well, ex ept for the \load" statement). However, only the se ond and third of the
above statements have any lasting e e t. In parti ular, the se ond statements (as you've
learned) loads a le, and this le may ontain fun tion de nitions, et ., that an be used
thereafter. The third statement, as dis ussed before, sets the global value of a variable.
Note again that setq does not evaluate its rst argument; it does evaluate the se ond,
but sin e this is a number, it evaluates to itself. (Re all that the boolean literals T, NIL
(or ( )), hara ters, strings, and keywords also evaluate to themeselves.)
Of ourse, an extremely important type of expression is defun, whose evaluation makes
a fun tion available for subsequent use. We now look at some simple examples.

Some simple examples of fun tions


true-listp { a fun tion that he ks whether its argument is a true list at the top level
(its elements need not be lists). Note the use of \tail-re ursion" (re ursion on the
dr of the input).
Note: The prede ned fun tion LISTP just he ks if its argument is nil or a ons
(i.e., a dotted pair); e.g., (listp '(a . b)) = T. Also note that we an put
omments after a semi olon { the Lisp reader ignores semi olons and everything
following them.

(defun true-listp (x)


;~~~~~~~~~~~~~~~~~~~~
(or (null x) (and (listp x) (true-listp ( dr x)))) )

e.g., (true-listp '(a (b . ) )) ==> T


(true-listp '(a . b)) ==> NIL
(true-listp 3) ==> NIL
(true-listp NIL) ==> T
(true-listp '(a . (b ))) ==> T

9
list-stru ture { a fun tion that he ks whether its argument is a true list stru ture
(i.e., it's not an atom other than NIL and prints without \dots"). Again we use
tail-re ursion.

(defun list-stru ture (x)


;~~~~~~~~~~~~~~~~~~~~
(or (null x)
(and (not (atom x)); we ould use (listp x) instead
(or (atom ( ar x)) (list-stru ture ( ar x)))
(list-stru ture ( dr x)) )))

e.g., (list-stru ture 'a) ==> NIL


(list-stru ture '(a b )) ==> T
(list-stru ture '(a (b . ) )) ==> NIL
(list-stru ture '(a . (b ))) ==> T

standard-dev { a fun tion for omputing the standard deviation (root mean square
deviation from the mean) of a list of numbers. This illustrates the use of the \fell
swoop" fun tions redu e and map ar, as well as dire t use of a lambda-expression.

(defun standard-dev (data)


;~~~~~~~~~~~~~~~~~~~~~~~~~
; data: a list of numbers
; RESULT: the root mean square deviation from the mean of the data
;
(let ((n (length data)) mean); define 2 lo al variables, supplying
; initial value = (length data) for n
(if (zerop n) (return-from standard-dev nil))
(if (= n 1) (return-from standard-dev 0))
(setq mean (/ (redu e #'+ data) n))
(sqrt (/ (redu e #'+
(map ar #'(lambda (x) (expt (- x mean) 2))
data ))
n )))); end of standard-dev

e.g., (standard-dev '()) ==> NIL


(standard-dev '(1)) ==> 0
(standard-dev '(2 6)) ==> 2
(standard-dev '(1 4 1 5 9 2 6 5)) ==> 2.5708704
( f., 5/sqrt(3) = 2.89 :-)

10

Potrebbero piacerti anche