Now we'll look at several special forms and macros. Over the next four lessons, we'll build up a repertoire that will let you write simple functions using the most elementary Lisp data type, the list. Later chapters will cover more complex program structures and data types.
Earlier, I told you that Lisp evaluates a symbol form by retrieving its
variable value. SETQ
gives you a way to set that value:
(setq my-name "David") "David" my-name "David" (setq a-variable 57) 57 a-variable 57 (setq a-variable :a-keyword) :A-KEYWORD
SETQ
's first argument is a symbol. This is not evaluated.
The second argument is assigned as the variable's value.
SETQ
returns the value of its last argument.
SETQ
doesn't evaluate its first argument because you want to assign a value to the symbol itself. IfSETQ
evaluated its first argument, the value of that argument would have to be a symbol. TheSET
form does this:(setq var-1 'var-2) VAR-2 var-1 VAR-2 var-2 Error: Unbound variable (set var-1 99) 99 var-1 VAR-2 VAR-2 99Did you notice the
'
in the first form? This keeps the following form,var-2
, from being evaluated. Later in this lesson, when we look atQUOTE
, I'll explain this in greater detail.In the example, we first make the value of
VAR-1
be the symbolVAR-2
. Checking the value ofVAR-2
, we find that it has none. Next, we useSET
(notSETQ
) to assign the value99
to the symbol,VAR-2
, which is the value ofVAR-1
.
The SETQ
form can actually take any even number of
arguments, which should be alternating symbols and values:
(setq month "June" day 8 year 1954) 1954 month "June" day 8 year 1954
SETQ
performs the assignments from left to right, and
returns the rightmost value.
The LET
form looks a little more complicated that what we've
seen so far. The LET
form uses nested lists, but because it's a
special form, only certain elements get evaluated.
(let ((a 3) (b 4) (c 5)) (* (+ a b) c)) 35 a Error: Unbound variable b Error: Unbound variable c Error: Unbound variable
The above LET
form defines values for the symbols
A
, B
, and C
, then uses these as
variables in an arithmetic calculation. The calculation's result is also
the result of the LET
form. Note that none of the variables
defined in the LET
have a value after Lisp has finished
evaluating the form.
In general, LET
looks like this:
(let (bindings) forms)
where bindings is any number of two-element lists -- each
list containing a symbol and a value -- and forms is any number
of Lisp forms. The forms are evaluated, in order, using the values
established by the bindings. LET
returns the value(s)
returned by the last form.
Indentation doesn't affect the operation of LET
, but proper
indentation does improve readability. Consider these equivalent forms:
(let ((p 52.8) (q 35.9) (r (f 12.07))) (g 18.3) (f p) (f q) (g r t)) (let ((p 52.8) (q 35.9) (r (f 12.07))) (g 18.3) (f p) (f q) (g r t))
In the first case, indentation makes clear which are the bindings and
which are the forms. Even if the reader doesn't know about the different
roles played by the two parts of the LET
form, the
indentation suggests a difference.
In the second case, you'll have to count parentheses to know where the
bindings end and the forms begin. Even worse, the absence of indentation
destroys visual cues about the different roles played by the two parts of
the LET
form.
If you define a variable using SETQ
and then name the same
variable in a LET
form, the value defined by LET
supersedes the other value during evaluation of the LET
:
(setq a 89) 89 a 89 (let ((a 3)) (+ a 2)) 5 a 89
Unlike SETQ
, which assigns values in left-to-right order,
LET
binds variables all at the same time:
(setq w 77) 77 (let ((w 8) (x w)) (+ w x)) 85
LET
bound W
to 8
and X
to W
. Because these bindings happened at the same time,
W
still had its value of 77
.
Lisp has a variation ofLET
, calledLET*
, that does perform bindings in order:(setq u 37) 37 (let* ((v 4) (u v)) (+ u v)) 8
The COND
macro lets you evaluate Lisp forms conditionally.
Like LET
, COND
uses parentheses to delimit
different parts of the form. Consider these examples:
(let ((a 1) (b 2) (c 1) (d 1)) (cond ((eql a b) 1) ((eql a c) "First form" 2) ((eql a d) 3))) 2
In the above COND
form we defined three clauses. Each
clause is a list beginning with a test form and followed by as many body
forms as desired. The body forms are simply code that you want to execute
if the test succeeds. The clauses are selected in order -- as soon as one
test succeeds, the corresponding body forms are evaluated and the value of
the last body form becomes the value of the COND
form.
COND
is more general than the special form,IF
, which only allows one test and one form each for the then and else parts.
Let's look at what happened in the example. EQL
returns
T
if its two arguments are identical, or the same number
(there's a subtle difference that we'll cover in Chapter 17). Only two of the three tests executed.
The first, (EQL A B)
, returned NIL. Therefore, the rest of
that clause (containing the number 1
as its only form) was
skipped. The second clause tested (EQL A C)
, which was true.
Because this test returned a non-NIL
value, the remainder of
the clause (the two atomic forms, "First form"
and
2
) was evaluated, and the value of the last form was returned
as the value of the COND
, which was then returned as the value
of the enclosing LET
. The third clause was never tested,
since an earlier clause had already been chosen -- clauses are tested in
order.
Conventional use of COND
uses T
as the
test form in the final clause. This guarantees that the body forms of the
final clause get evaluated if the tests fail in all of the other clauses.
You can use the last clause to return a default value or perform some
appropriate operation. Here's an example:
(let ((a 32)) (cond ((eql a 13) "An unlucky number") ((eql a 99) "A lucky number") (t "Nothing special about this number"))) "Nothing special about this number"
Sometimes we'd like to suppress Lisp's normal evaluation rules. One such case is when we'd like a symbol to stand for itself, rather than its value, when it appears as an argument of a function call:
(setq a 97) 97 a 97 (setq b 23) 23 (setq a b) 23 a 23 (setq a (quote b)) B a B
The difference is that B
's value is used in
(SETQ A B)
, whereas B
stands for itself
in (SETQ A (QUOTE B))
.
The QUOTE
form is so commonly used that Lisp provides a
shorthand notation:
(QUOTE form) 'form
The symbol
means that the two Lisp forms are equivalent. Lisp arranges the
equivalence of '
and QUOTE
through a reader
macro. We'll take a brief look at how you can define your own reader
macros in Lesson 12.