(dotimes (x 10) (format t "~d " x))
Another binding form is a variant of LET
, LET*
. The difference is that in a LET
, the variable names can be used only in the body of the LET
—the part of the LET
after the variables list—but in a LET*
, the initial value forms for each variable can refer to variables introduced earlier in the variables list. Thus, you can write the following:
(let* ((x 10)
(y (+ x 10)))
(list x y))
but not this:
(let ((x 10)
(y (+ x 10)))
(list x y))
However, you could achieve the same result with nested LET
s.
(let ((x 10))
(let ((y (+ x 10)))
(list x y)))
Lexical Variables and Closures
By default all binding forms in Common Lisp introduce lexically scoped variables. Lexically scoped variables can be referred to only by code that's textually within the binding form. Lexical scoping should be familiar to anyone who has programmed in Java, C, Perl, or Python since they all provide lexically scoped "local" variables. For that matter, Algol programmers should also feel right at home, as Algol first introduced lexical scoping in the 1960s.
However, Common Lisp's lexical variables are lexical variables with a twist, at least compared to the original Algol model. The twist is provided by the combination of lexical scoping with nested functions. By the rules of lexical scoping, only code textually within the binding form can refer to a lexical variable. But what happens when an anonymous function contains a reference to a lexical variable from an enclosing scope? For instance, in this expression:
(let ((count 0)) #'(lambda () (setf count (1+ count))))
the reference to count
inside the LAMBDA
form should be legal according to the rules of lexical scoping. Yet the anonymous function containing the reference will be returned as the value of the LET
form and can be invoked, via FUNCALL
, by code that's not in the scope of the LET
. So what happens? As it turns out, when count
is a lexical variable, it just works. The binding of count
created when the flow of control entered the LET
form will stick around for as long as needed, in this case for as long as someone holds onto a reference to the function object returned by the LET
form. The anonymous function is called a closure because it "closes over" the binding created by the LET
.
The key thing to understand about closures is that it's the binding, not the value of the variable, that's captured. Thus, a closure can not only access the value of the variables it closes over but can also assign new values that will persist between calls to the closure. For instance, you can capture the closure created by the previous expression in a global variable like this:
(defparameter *fn* (let ((count 0)) #'(lambda () (setf count (1+ count)))))
Then each time you invoke it, the value of count will increase by one.
CL-USER> (funcall *fn*)
1
CL-USER> (funcall *fn*)
2
CL-USER> (funcall *fn*)
3
A single closure can close over many variable bindings simply by referring to them. Or multiple closures can capture the same binding. For instance, the following expression returns a list of three closures, one that increments the value of the closed over count
binding, one that decrements it, and one that returns the current value:
(let ((count 0))
(list
#'(lambda () (incf count))
#'(lambda () (decf count))
#'(lambda () count)))
Dynamic, a.k.a. Special, Variables
Lexically scoped bindings help keep code understandable by limiting the scope, literally, in which a given name has meaning. This is why most modern languages use lexical scoping for local variables. Sometimes, however, you really want a global variable—a variable that you can refer to from anywhere in your program. While it's true that indiscriminate use of global variables can turn code into spaghetti nearly as quickly as unrestrained use of goto
, global variables do have legitimate uses and exist in one form or another in almost every programming language.[73] And as you'll see in a moment, Lisp's version of global variables, dynamic variables, are both more useful and more manageable.
Common Lisp provides two ways to create global variables: DEFVAR
and DEFPARAMETER
. Both forms take a variable name, an initial value, and an optional documentation string. After it has been DEFVAR
ed or DEFPARAMETER
ed, the name can be used anywhere to refer to the current binding of the global variable. As you've seen in previous chapters, global variables are conventionally named with names that start and end with *
. You'll see later in this section why it's quite important to follow that naming convention. Examples of DEFVAR
and DEFPARAMETER
look like this:
(defvar *count* 0
"Count of widgets made so far.")
(defparameter *gap-tolerance* 0.001
"Tolerance to be allowed in widget gaps.")
The difference between the two forms is that DEFPARAMETER
always assigns the initial value to the named variable while DEFVAR
does so only if the variable is undefined. A DEFVAR
form can also be used with no initial value to define a global variable without giving it a value. Such a variable is said to be unbound.
Practically speaking, you should use DEFVAR
to define variables that will contain data you'd want to keep even if you made a change to the source code that uses the variable. For instance, suppose the two variables defined previously are part of an application for controlling a widget factory. It's appropriate to define the *count*
variable with DEFVAR
because the number of widgets made so far isn't invalidated just because you make some changes to the widget-making code.[74]
On the other hand, the variable *gap-tolerance*
presumably has some effect on the behavior of the widget-making code itself. If you decide you need a tighter or looser tolerance and change the value in the DEFPARAMETER
form, you'd like the change to take effect when you recompile and reload the file.
After defining a variable with DEFVAR
or DEFPARAMETER
, you can refer to it from anywhere. For instance, you might define this function to increment the count of widgets made:
(defun increment-widget-count () (incf *count*))
The advantage of global variables is that you don't have to pass them around. Most languages store the standard input and output streams in global variables for exactly this reason—you never know when you're going to want to print something to standard out, and you don't want every function to have to accept and pass on arguments containing those streams just in case someone further down the line needs them.
73
Java disguises global variables as public static fields, C uses extern
variables, and Python's module-level and Perl's package-level variables can likewise be accessed from anywhere.
74
If you specifically want to reset a DEFVAR
ed variable, you can either set it directly with SETF
or make it unbound using MAKUNBOUND
and then reevaluate the DEFVAR
form.