Книга: Practical Common Lisp
Other Special Operators
Other Special Operators
The four remaining special operators, LOCALLY
, THE
, LOAD-TIME-VALUE
, and PROGV
, all allow you to get at parts of the underlying language that can't be accessed any other way. LOCALLY
and THE
are part of Common Lisp's declaration system, which is used to communicate things to the compiler that don't affect the meaning of your code but that may help the compiler generate better code—faster, clearer error messages, and so on.[220] I'll discuss declarations briefly in Chapter 32.
The other two, LOAD-TIME-VALUE
and PROGV
, are infrequently used, and explaining the reason why you might ever want to use them would take longer than explaining what they do. So I'll just tell you what they do so you know they're there. Someday you'll hit on one of those rare times when they're just the thing, and then you'll be ready.
LOAD-TIME-VALUE
is used, as its name suggests, to create a value that's determined at load time. When the file compiler compiles code that contains a LOAD-TIME-VALUE
form, it arranges to evaluate the first subform once, when the FASL is loaded, and for the code containing the LOAD-TIME-VALUE
form to refer to that value. In other words, instead of writing this:
(defvar *loaded-at* (get-universal-time))
(defun when-loaded () *loaded-at*)
you can write the following:
(defun when-loaded () (load-time-value (get-universal-time)))
In code not processed by COMPILE-FILE
, LOAD-TIME-VALUE
is evaluated once when the code is compiled, which may be when you explicitly compile a function with COMPILE
or earlier because of implicit compilation performed by the implementation in the course of evaluating the code. In uncompiled code, LOAD-TIME-VALUE
evaluates its form each time it's evaluated.
Finally, PROGV
creates new dynamic bindings for variables whose names are determined at runtime. This is mostly useful for implementing embedded interpreters for languages with dynamically scoped variables. The basic skeleton is as follows:
(progv symbols-list values-list
body-form*)
where symbols-list is a form that evaluates to a list of symbols and values-list is a form that evaluates to a list of values. Each symbol is dynamically bound to the corresponding value, and then the body-forms are evaluated. The difference between PROGV
and LET
is that because symbols-list is evaluated at runtime, the names of the variables to bind can be determined dynamically. As I say, this isn't something you need to do often.
And that's it for special operators. In the next chapter, I'll get back to hard-nosed practical topics and show you how to use Common Lisp's package system to take control of your namespaces so you can write libraries and applications that can coexist without stomping on each other's names.