A closure is a type of Lisp functional object useful for implementing certain advanced access and control structures. Closures give the programmer more explicit control over the environment, by allowing him to "save up" the environment created by the entering of a dynamic contour (i.e. a lambda , do , prog , progv , let , or any of several other special forms), and then use that environment elsewhere, even after the contour has been exited.
(setq a 3) ((lambda (a) (print (+ a 6))) 10) (print a)Initially there is a value cell for a , and the setq form makes the contents of that value cell be 3 . Then the lambda -combination is evaluated. a is bound to 10 : the old value cell, which still contains a 3 , is saved away, and a new value cell is created with 10 as its contents. The reference to a inside the lambda expression evaluates to the current binding of a , which is the contents of its current value cell, namely 10 . So 16 is printed. Then the binding is undone, discarding the new value cell, and restoring the old value cell which still contains a 3 . The final print prints out a 3 . The form (closure var-list function) , where var-list is a list of variables and function is any function, creates and returns a closure. When this closure is applied to some arguments, all of the value cells of the variables on var-list are saved away, and the value cells that those variables had at the time closure was called are made to be the value cells of the symbols. Then function is applied to the argument. (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.) Here is another, lower level explanation. The closure object stores several things inside of it. First, it saves the function . Secondly, for each variable in var-list , it remembers what that variable's value cell was when the closure was created. Then when the closure is called as a function, it first temporarily restores the value cells it has remembered, and then applies function to the same arguments to which the closure itself was applied. Now, if we evaluate the form
(setq a ((lambda (x) (closure '(x) (function car))) 3))what happens is that a new value cell is created for x , and its contents is a fixnum 3 . Then a closure is created, which remembers the function car , the symbol x , and that value cell. Finally the old value cell of x is restored, and the closure is returned. Notice that the new value cell is still around, because it is still known about by the closure. When the closure is applied, this value cell will be restored and the value of x will be 3 . Because of the way closures are implemented, the variables to be closed over must not get turned into "local variables" by the compiler. Therefore, all such variables should be declared special. In the Lisp Machine's implementation of closures, lambda-binding never really allocates any storage to create new value cells. Value cells are only created (sometimes) by the closure function itself. Thus, implementors of large systems need not worry about storage allocation overhead from this mechanism if they are not using closures. See the section on internal formats. Lisp Machine closures are not closures in the true sense, as they do not save the whole variable-binding environment; however, most of that environment is irrelevant, and the explicit declaration of which variables are to be closed allows the implementation to have high efficiency. They also allow the programmer to explicitly choose for each variable whether it is to be bound at the point of call or bound at the point of definition (e.g., creation of the closure), a choice which is not conveniently available in other languages. In addition the program is clearer because the intended effect of the closure is made manifest by listing the variables to be affected.
(defun make-list-closure (l) (closure '(l) (function (lambda () (prog1 (car l) (setq l (cdr l)))))))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 value cell for l . Each of these value cells was created when the make-list-closure function was entered, and the value cells are remembered by the closures.
(let-closed ((a 5) b (c 'x)) (function (lambda () ...))) expands into (local-declare ((special a b c)) (let ((a 5) b (c 'x)) (closure '(a b c) (function (lambda () ...)))))