(multiple-value-bind (x y) (values 1 2)
(+ x y)) ==> 3
Another macro, MULTIPLE-VALUE-LIST
, is even simpler—it takes a single form, evaluates it, and collects the resulting multiple values into a list. In other words, it's the inverse of VALUES-LIST
.
CL-USER> (multiple-value-list (values 1 2))
(1 2)
CL-USER> (values-list (multiple-value-list (values 1 2)))
1
2
However, if you find yourself using MULTIPLE-VALUE-LIST
a lot, it may be a sign that some function should be returning a list to start with rather than multiple values.
Finally, if you want to assign multiple values returned by a form to existing variables, you can use VALUES
as a SETF
able place. For example:
CL-USER> (defparameter *x* nil)
*X*
CL-USER> (defparameter *y* nil)
*Y*
CL-USER> (setf (values *x* *y*) (floor (/ 57 34)))
1
23/34
CL-USER> *x*
1
CL-USER> *y*
23/34
A special operator you'll need to understand in order to write certain kinds of macros is EVAL-WHEN
. For some reason, Lisp books often treat EVAL-WHEN
as a wizards-only topic. But the only prerequisite to understanding EVAL-WHEN
is an understanding of how the two functions LOAD
and COMPILE-FILE
interact. And understanding EVAL-WHEN
will be important as you start writing certain kinds of more sophisticated macros, such as the ones you'll write in Chapters 24 and 31.
I've touched briefly on the relation between LOAD
and COMPILE-FILE
in previous chapters, but it's worth reviewing again here. The job of LOAD
is to load a file and evaluate all the top-level forms it contains. The job of COMPILE-FILE
is to compile a source file into a FASL file, which can then be loaded with LOAD
such that (load 'foo.lisp')
and (load 'foo.fasl')
are essentially equivalent.
Because LOAD
evaluates each form before reading the next, the side effects of evaluating forms earlier in the file can affect how forms later in the form are read and evaluated. For instance, evaluating an IN-PACKAGE
form changes the value of *PACKAGE*
, which will affect the way subsequent forms are read.[217] Similarly, a DEFMACRO
form early in a file can define a macro that can then be used by code later in the file.[218]
COMPILE-FILE
, on the other hand, normally doesn't evaluate the forms it's compiling; it's when the FASL is loaded that the forms—or their compiled equivalents—will be evaluated. However, COMPILE-FILE
must evaluate some forms, such as IN- PACKAGE
and DEFMACRO
forms, in order to keep the behavior of (load 'foo.lisp')
and (load 'foo.fasl')
consistent.
So how do macros such as IN-PACKAGE
and DEFMACRO
work when processed by COMPILE- FILE
? In some pre-Common Lisp versions of Lisp, the file compiler simply knew it should evaluate certain macros in addition to compiling them. Common Lisp avoided the need for such kludges by borrowing the EVAL-WHEN
special operator from Maclisp. This operator, as its name suggests, allows you to control when specific bits of code are evaluated. The skeleton of an EVAL-WHEN
form looks like this:
(eval-when (
There are three possible :compile-toplevel
, :load-toplevel
, and :execute
—and which ones you specify controls when the EVAL-WHEN
with multiple situations is equivalent to several EVAL-WHEN
forms, one per situation, each with the same body code. To explain the meaning of the three situations, I'll need to explain a bit about how COMPILE-FILE
, which is also referred to as the
To explain how COMPILE-FILE
compiles EVAL- WHEN
forms, I need to introduce a distinction between compiling PROGN
are compiled as top-level forms since the PROGN
itself doesn't MACROLET
or SYMBOL-MACROLET
are compiled as top-level forms because after the compiler has expanded the local macros or symbol macros, there will be no remnant of the MACROLET
or SYMBOL-MACROLET
in the compiled code. Finally, the expansion of a top-level macro form will be compiled as a top-level form.
Thus, a DEFUN
appearing at the top level of a source file is a top-level form—the code that defines the function and associates it with its name will run when the FASL is loaded—but the forms within the body of the function, which won't run until the function is called, aren't top-level forms. Most forms are compiled the same when compiled as top-level and non-top-level forms, but the semantics of an EVAL-WHEN
depend on whether it's being compiled as a top- level form, compiled as a non-top-level form, or simply evaluated, combined with what situations are listed in its situation list.
The situations :compile-toplevel
and :load-toplevel
control the meaning of an EVAL-WHEN
compiled as a top-level form. When :compile- toplevel
is present, the file compiler will evaluate the subforms at compile time. When :load- toplevel
is present, it will compile the subforms as top-level forms. If neither of these situations is present in a top-level EVAL-WHEN
, the compiler ignores it.