Myroslava Dzikovska
CS244/444
Fall 2002
1
Style note: (
ar x) == (first x), (
dr x) == (rest x). It makes for more readable
ode if you avoid using
ar and
dr, and use first and rest instead.
2
2 Equality Tests
Summary: eq is true on identi
al pointers only (implementation dependent whether same numbers or
hars are same
pointers). eql is true on identi
al pointers and identi
al numbers and
hars. equal is true on obje
ts with isomorphi
stru
ture. Normally you want to use equal for your
omparisons, unless you really
are about pointers or dealing with
ir
ular lists. equal
an enter an innite loop on
ir
ular lists.
(eq 'a 'a) => T
(eql 'a 'a) => T
(equal 'a 'a) => T
3
3 Fun
tions and variables
3.1 Dening a fun
tion
Fun
tions are dened using defun form.
(defun <name> (<list of parameters>)
<"optional do
umentation string">
<body>
)
Reverse the list
(defun reverse-re
ursive (l)
"Reverse a list using re
ursion"
(if (null l)
nil
(append (reverse-re
ursive (rest l)) (list (first l)))))
4
3.3 Fun
tion Parameters
You probably won't use these, but need to know them to understand the notation in the LISP books.
&rest means that the following parameter stands for an arbitrary number or arguments. For example,
fun
all fn &rest args
means that the fun
tion fun
all takes a required argument fn and an arbitrary number of arguments following it. You
an
all it as
(fun
all #'
ons 'a '(b
)) => (a b
)
(fun
all #'list 'a 'b '
) => (a b
)
&key is used to denote optional named parameters. For example,
position item sequen
e &key :from-end :test :test-not :start :end :key
means that find fun
tion takes an item, a sequen
e, and may have 6 dierent optional arguments. The optional arguments
are denoted with :arg on the
all. For example,
(position 'a '(a b
d a) :from-end t) => 4
5
4 Flow Control
Conditionals are best done using
ond predi
ate. Below is a denition of a sign fun
tion
(defun sign (x)
"Sign fun
tion: return -1 if x is negative, 1 if positive, and 0 otherwise"
(
ond
((< x 0) -1)
((eql x 0) 0)
((> x 0) 1)))
The
onditions are evaluated sequentially. The default
ondition is \T".
(defun test24 (x)
"Returns 4 if x is divisible by 4, 2 if x is divisible by 2 but not 4, and 1 otherwise"
(
ond
((eql (mod x 4) 0) 4)
((eql (mod x 2) 0) 2)
(t 1)
))
Iteration over a list
an be done using dolist. Given a list of numbers, this will
ount all divisible by 4, all divisible by
2, and the rest
(defun
ount24 (x)
"Return a list with 3 elemenst:
a number of elements in x divisible by 4,
a number of elements divisible by 2,
and a number of elements not divisible by 2"
(let ((div4 0) (div2 0) (other 0))
(dolist (el x)
(
ond
((eql (mod el 4) 0)
(setq div4 (+ 1 div4))
(setq div2 (+ 1 div2)))
((eql (mod el 2) 0)
(setq div2 (+ 1 div2)))
(t (setq other (+ 1 other))))
)
(list div4 div2 other)
))
Note that a variable el dened by dolist is automati
ally
onsidered lo
al.
If there's only 1
ondition, use when. Count all positive numbers in the list
(defun
ountpositive (x)
"Return the number of positive elements in x"
(let ((
ount 0))
(dolist (el x)
(when (>= el 0) (setq
ount (+
ount 1))))
ount))
6
5 Transforming lists
For all the examples, we use the following denition, a list of oÆ
e numbers, with some people sharing oÆ
es
(setq x '((Mary 221) (John 314) (Jane 221)))
Given the oÆ
e list, get the list of
oors people are on, when
oors denoted by the rst digit of the oÆ
e number.
Similarly, we apply a fun
tion getFloor whi
h we will dene to all elements of the oÆ
e list to get our
oor list.
(defun get-floor (entry)
"Given an entry with the name and offi
e number, returns the name
and the floor where the offi
e is"
(list (first entry) (floor (se
ond entry) 100))
)
But we don't need two separate fun
tions for su
h a simple task. Instead of dening a separate getFloor fun
tion, we
an
\inline" it by using a generi
lambda fun
tion.
(defun get-floors2 (phonelist)
"Find out the floors on whi
h people are lo
ated"
(map
ar (lambda (entry)
(list (first entry) (floor (se
ond entry) 100)))
phonelist))
Given the oÆ
e list, write a generi
fun
tion that produ
es phone numbers, assuming that the number is formed by adding
a spe
ied extension to the oÆ
e number. Again, we
an inline the fun
tion, and it
an a
ess the variable extension
from the en
losing blo
k.
(defun make-phone-list (offi
elist extension)
"Given an offi
e list,
reates a phone list by adding a spe
ified
extension to the offi
e numbers"
(map
ar (lambda (entry)
(list (first entry) (+ (se
ond entry) extension)))
offi
elist))
7
Given the oÆ
e list, write a fun
tion that nds all
oors on whi
h people reside. We have a pattern for it in our
get-floors2 fun
tion, but it also returns people's names. We need to get the se
ond elements of the list returned by
get-floors2 to get the
oor numbers only.
(get-floors-a x) => (2 3 2)
That's almost right, but there are dupli
ate numbers in the list. Fun
tion remove-dupli
ates removes them
(defun get-floors (phonelist)
(remove-dupli
ates
(map
ar #'se
ond (get-floors2 phonelist))))
(get-floors x) => (3 2)
Note that if 2 elements are equal, the earlier one in the sequen
e will be dis
arded by remove-dupli
ates. If you want
the last one to be dis
arded, add :from-end t as the optional argument to the
all.
8
6 Examples of Useful data stru
tures
6.1 Asso
iation lists (a-lists)
Lists
omposed of key-value pairs. Easy to sear
h and transform.
(setf age-list '((Mary . 22) (John . 19) (Jane . 30)))
(a
ons 'Jill 25 age-list)
=> ((Jill . 25) (Mary . 22) (John . 19) (Jane . 30))
(asso
'John age-list)
=> (John . 19)
(setf birth-year-list
(map
ar (lambda (x) (
ons (
ar x) (- 1999 (
dr x))))))
=> ((Jill . 1974) (Mary . 1977) (John . 1980) (Jane . 1969))
Note that you must use setf and not setq as the assignment operator to work with stru ture elds.