;;; -*- Mode:gate; Fonts:(HL12 HL12I HL12B CPTFONTB HL12BI HL12B HL12I ) -*- =Node: What a Closure Is =Text: 3WHAT A CLOSURE IS* A 1closure* is a type of Lisp functional object useful for implementing certain advanced access and control structures. Closures give you more explicit control over the environment by allowing you to save the dynamic bindings of specified variables and then to refer to those bindings later, even after the construct (2let*, etc.) which made the bindings has been exited. There is a view of dynamic variable binding that we use in this section because it makes it easier to explain what closures do. In this view, when a variable is bound dynamically, a new binding is created for it. The old binding is saved away somewhere and is inaccessible. Any references to the variable then get the contents of the new binding, and any 2setq*'s change the contents of the new value cell. Evantually the new binding goes away, and the old binding, along with its contents, becomes current again. For example, consider the following sequence of Lisp forms: 3(defvar a 3)* 3;2 a becomes 3.** 3(let ((a 10))* 3;2 a rebound to 10.** 3 (print (+ a 6))) ;2 16 is printed.** 3(print a)* 3;2 3 is printed.** Initially there is a binding for 2a*, and the 2setq* form makes the contents of that binding be 23*. Then the 2lambda*-combination is evaluated. 2a* is bound to 210*: the old binding, which still contains 23*, is saved away, and a new binding is created with 210* as its contents. The reference to 2a* inside the 2lambda* expression evaluates to the current binding of 2a*, which is the contents of its current binding, namely 210*. So 216* is printed. Then the newer binding is discarded and the old binding, which still contains a 23*, is restored. The final 2print* prints 23*. The form 2(closure 1var-list* 1function*)*, where 1var-list* is a list of variables and 1function* is any function, creates and returns a closure. When this closure is applied to some arguments, all of the bindings of the variables on 1var-list* are saved away, and the bindings that those variables had 1at the time 2closure* was called* (that is, at the time the closure was created) are made to be the bindings of the symbols. Then 1function* is applied to the arguments. (This paragraph is somewhat complex, but it completely describes the operation of closures; if you don't understand it, come back and read it again after reading the next two paragraphs.) Here is another, lower-level explanation. The closure object stores several things inside it. First, it saves the 1function*. Secondly, for each variable in 1var-list*, it remembers what that variable's binding was when the closure was created. Then when the closure is called as a function, it first temporarily restores the bindings it has remembered inside the closure, and then applies 1function* to the same arguments to which the closure itself was applied. When the function returns, the bindings are restored to be as they were before the closure was called. Now, if we evaluate the form 3(setq a * 3 (let ((x 3))* 3(declare (special x))* 3(closure '(x) 'frob)))* what happens is that a new binding is created for 2x*, containing a fixnum 23*. Then a closure is created, which remembers the function 2frob*, the symbol 2x*, and that binding. Finally the old binding of 2x* is restored, and the closure is returned. Notice that the new binding is still around, because it is still known about by the closure. When the closure is applied, say by doing 2(funcall a 7)*, this binding is temporarily restored and the value of 2x* is 23* again. If 2frob* uses 2x* as a free variable, it sees 23* as the value. A closure can be made around any function, using any form that evaluates to a function. The form could evaluate to a compiled function, as would 2(function (lambda () x))*. In the example above, the form is 2'frob* and it evaluates to the symbol 2frob*. A symbol is also a good function. It is usually better to close around a symbol that is the name of the desired function, so that the closure points to the symbol. Then, if the symbol is redefined, the closure will use the new definition. If you actually prefer that the closure continue to use the old definition that was current when the closure was made, use 2function*, as in: 3(closure '(x) (function frob))* Explicit closures made with 2closure* record only the dynamic bindings of the specified variables. Another closure mechanism is activated automatically to record lexical bindings whenever 2function* is used around an explicit lambda expression, but 2closure* itself has no interaction with lexical bindings. It is the user's responsibility to make sure that the bindings that the closure is intended to record are dynamic bindings, either by means of special declarations (see 4(EVAL-4)Declarations*) as shown above or by making the variables globally special with 2defvar* or equivalent. If the function closed over is an explicit lambda expression, it is occasionally necessary to use declarations within it to make sure that the variables are considered special there. But this is not needed if the variables are globally special or if a special declaration is lexically visible where 2closure* is called. Usually the compiler can tell when a special declaration is missing, but when making a closure the compiler detects this only after acting on the assumption that the variable is lexical, by which time it is too late to fix things. The compiler warns you if this happens. In Zetalisp's implementation of closures, lambda-binding never really allocates any storage to create new bindings. Bindings receive separate storage only when the 2closure* function itself finds they need it. Thus, there is no cost associated with closures when they are not in use. Zetalisp closures differ from the closures of Lisp 1.5 (which were made with 2function*) in that they save specific variables rather than the entire variable-binding environment. For their intended applications, this is an advantage. The explicit declaration of the variables in 2closure* permits higher efficiency and more flexibility. In addition the program is clearer because the intended effect of the closure is made manifest by listing the variables to be affected. Lisp 1.5 closures are more similar to Zetalisp's automatic handling of lexical variables. Closure implementation (which it not usually necessary for you to understand) involves two kinds of value cells. Every symbol has an 1internal value cell*, part of the symbol itself, which is where its dynamic value is normally stored. When a variable is closed over, it gets an 1external value cell* to hold its value. The external value cells behave according to the lambda-binding model used earlier in this section. The value in the external value cell is found through the usual access mechanisms (such as evaluating the symbol, calling 2symeval*, etc.), because the internal value cell is made to contain a forwarding pointer to the external value cell that is current. Such a forwarding pointer is present in a symbol's value cell whenever its current binding is being remembered by some closure; at other times, there won't be an invisible pointer, and the value resides directly in the symbol's internal value cell. =Node: Examples of the Use of Closures =Text: 3EXAMPLES OF THE USE OF CLOSURES* One thing we can do with closures is to implement a 1generator*, which is a kind of function which is called successively to obtain successive elements of a sequence. We implement a function 2make-list-generator*, which takes a list and returns a generator that returns successive elements of the list. When it gets to the end it should return 2nil*. The problem is that in between calls to the generator, the generator must somehow remember where it is up to in the list. Since all of its bindings are undone when it is exited, it cannot save this information in a bound variable. It could save it in a global variable, but the problem is that if we want to have more than one list generator at a time, they will all try to use the same global variable and get in each other's way. Here is how to solve this problem using closures: 3(defun make-list-generator (l)* 3 (declare (special l))* 3 (closure '(l)* 3 #'(lambda ()* 3 (prog1 (car l)* 3 (setq l (cdr l))))))* 2(make-list-generator '(1 2 3))* returns a generator which, on successive calls, returns 1, 2, 3, and 2nil*. Now we can make as many list generators as we like; they won't get in each other's way because each has its own binding for 2l*. Each of these bindings was created when the 2make-list-generator* function was entered, and the bindings are remembered by the closures. The following example uses closures which share bindings: 3(defvar a)* 3(defvar b)* 3(defun foo () (setq a 5))* 3(defun bar () (cons a b))* 3(let ((a 1) (b 1))* 3 (setq x (closure '(a b) 'foo))* 3 (setq y (closure '(a b) 'bar)))* When the 2let* is entered, new bindings are created for the symbols 2a* and 2b*, and two closures are created that both point to those bindings. If we do 2(funcall x)*, the function 2foo* is be run, and it changes the contents of the remembered binding of 2a* to 25*. If we then do 2(funcall y)*, the function 2bar* returns 2(5 . 1)*. This shows that the binding of 2a* seen by the closure 2y* is the same binding seen by the closure 2x*. The top-level binding of 2a* is unaffected. Here is how we can create a function that prints always using base 16: 3(deff print-in-base-16* 3 (let ((*print-base* 16.))* 3 (closure '(*print-base*) 'print)))* =Node: Closure-Manipulating Functions =Text: 3CLOSURE-MANIPULATING FUNCTIONS closure* 1var-list* 1function* Creates and returns a closure of 1function* over the variables in 1var-list*. Note that all variables on 1var-list* must be declared special if the function is to compile correctly. To test whether an object is a closure, use the 2closurep* predicate (see 4(PRIMOBJTYPE-1)Data Type Predicates*) or 2(typep 1object* 'closure)*. 3symeval-in-closure* 1closure* 1symbol* Returns the binding of 1symbol* in the environment of 1closure*; that is, it returns what you would get if you restored the bindings known about by 1closure* and then evaluated 1symbol*. This allows you to ``look around inside'' a closure. If 1symbol* is not closed over by 1closure*, this is just like 2symeval*. 1symbol* may be a locative pointing to a value cell instead of a symbol (this goes for all the whatever-in-closure functions). 3set-in-closure* 1closure* 1symbol* 1x* Sets the binding of 1symbol* in the environment of 1closure* to 1x*; that is, it does what would happen if you restored the bindings known about by 1closure* and then set 1symbol* to 1x*. This allows you to change the contents of the bindings known about by a closure. If 1symbol* is not closed over by 1closure*, this is just like 2set*. 3locate-in-closure* 1closure* 1symbol* Returns the location of the place in 1closure* where the saved value of 1symbol* is stored. An equivalent form is 2(locf (symeval-in-closure 1closure* 1symbol*))*. 3boundp-in-closure* 1closure* 1symbol* Returns 2t* if 1symbol*'s binding in 1closure* is not void. This is what 2(boundp 1symbol*)* would return if executed in 1closure*'s saved environment. 3makunbound-in-closure* 1closure* 1symbol* Makes 1symbol*'s binding in 1closure* be void. This is what 2(makunbound 1symbol*)* would do if executed in 1closure*'s saved environment. 3closure-alist* 1closure* Returns an alist of 2(1symbol* . 1value*)* pairs describing the bindings that the closure performs when it is called. This list is not the same one that is actually stored in the closure; that one contains pointers to value cells rather than symbols, and 2closure-alist* translates them back to symbols so you can understand them. As a result, clobbering part of this list does not change the closure. The list that is returned may contain void cells if some of the closed-over variables were void in the closure's environment. In this case, printing the value will get an error (accessing a cell that contains a void marker is always an error unless done in a special, careful way) but the value can still be passed around. 3closure-variables* 1closure* Returns a list of variables closed over in 1closure*. This is 2equal* to the first argument specified to the function 2closure* when this closure was created. 3closure-function* 1closure* Returns the closed function from 1closure*. This is the function that was the second argument to 2closure* when the closure was created. 3closure-bindings* 1closure* Returns the actual list of bindings to be performed when 1closure* is entered. This list can be passed to 2sys:%using-binding-instances* to enter the closure's environment without calling the closure. See 4(SUBPRIMITIVES-3)Closure Subprimitives*. 3copy-closure* 1closure* Returns a new closure that has the same function and variable values as 1closure*. The bindings are not shared between the old closure and the new one, so that if the old closure changes some closed variable's values, the values in the new closure do not change. 3let-closed* 1((variable* 1value)...)* 1function* 1Macro* When using closures, it is very common to bind a set of variables with initial values only in order to make a closure over those variables. Furthermore, the variables must be declared special. 2let-closed* is a special form which does all of this. It is best described by example: 3(let-closed ((a 5) b (c 'x))* 3 (function (lambda () ...)))* 2macro-expands into* 3(let ((a 5) b (c 'x))* 3 (declare (special a b c))* 3 (closure '(a b c)* 3 (function (lambda () ...))))* Note that the following code, which would often be useful, does not work as intended if 2x* is not special outside the 2let-closed*: 3(let-closed ((x x))* 3 (function ...))* This is because the reference to 2x* as an initialization for the new binding of 2x* is affected by the special declaration that the 2let-closed* produces. It therefore does not see any lexical binding of 2x*. This behavior is unfortunate, but it is required by the Common Lisp specifications. To avoid the problem, write 3(let ((y x))* 3 (let-closed ((x y))* 3 (function ...)))* or simply change the name of the variable outside the 2let-closed* to something other than 2x*. =Node: Entities =Text: 3ENTITIES* An entity is almost the same thing as a closure; an entity behaves just like a closure when applied, but it has a recognizably different data type which allows certain parts of the system such as the printer and 2describe* to treat it differently. A closure is simply a kind of function, but an entity is assumed to be a message-receiving object. Thus, when the Lisp printer (see 4(READPRINT-1)What the Printer Produces*) is given a closure, it prints a simple textual represen- tation, but when it is handed an entity, it sends the entity a 2:print-self* message, which the entity is expected to handle. The 2describe* function (see 4(MISCELL-1)Poking Around in the Lisp World*) also sends entities messages when it is handed them. So when you want to make a message-receiving object out of a closure, as described on 4(FLAVOR-1)Generic Operations in Lisp*, you should use an entity instead. To a large degree, entities are made obsolete by flavors (see 4(FLAVOR-0)Objects, Message Passing, and Flavors*). Flavors have had considerably more attention paid to their efficiency and to good tools for using them. If what you are doing is flavor-like, it is better to use flavors. 3entity* 1variable-list* 1function* Returns a newly constructed entity. This function is just like the function 2closure* except that it returns an entity instead of a closure. The 1function* argument should be a symbol which has a function definition and a value. When 2typep* is applied to this entity, it returns the value of that symbol. To test whether an object is an entity, use the 2entityp* predicate (see 4(PRIMOBJTYPE-1)Data Type Predicates*). The functions 2symeval-in-closure*, 2closure-alist*, 2closure-function*, etc. also operate on entities.