5.2 Issues in multitasking

5.2.2 Lexical variables

A lexical variable is a variable that can only be referenced at the textual location of the code that creates it. However, lexical variables have indefinite extent; that is, the variable continues to exist as long as some form refers to it, even if the construct that created the lexical variable has been exited.

Common Lisp uses function objects called lexical closures to hold the values of lexical variables that are needed beyond their normal lifetime.

For example, consider the following code:

> (setq lexical-closure 
        (let ((a 0)) 
          #'(lambda (key)
              (cond ((eq key :increment)
                     (incf a))
                    ((eq key :value)
                     a)
                    (t (error "Unknown operation ~A" key))))))
#<Interpreted-Function (LAMBDA (KEY) (COND ((EQ KEY :INCREMENT) (INCF A)) 
((EQ KEY :VALUE) A) (T (ERROR "Unknown operation ~A" KEY)))) FB2DA7>

The value oflexical-closure is a function, created usinglambda, that refers to the variablea. Even when thelet form that created the lexical variablea has exited, the variable continues to exist as a location that can be modified.

Thus, you could enter these expressions with the following results:

> (funcall lexical-closure :increment)
1

> (funcall lexical-closure :increment) 2

> (funcall lexical-closure :value) 2

> (setf a 23) 23

> (funcall lexical-closure :value) 2

The special variablea, whose value has been set to 23, has no relationship to the lexical variablea, whose value has been saved in a lexical closure.

Suppose you used a special variable instead of a lexical variable, as follows:

> (defvar *a* 23)
*A*

> (setq not-lexical-closure (let ((*a* 0)) #'(lambda (key) (cond ((eq key :increment) (incf *a*)) ((eq key :value) *a*) (t (error "Unknown operation ~A" key)))))) #<Interpreted-Function (LAMBDA (KEY) (COND ((EQ KEY :INCREMENT) (INCF *A*)) ((EQ KEY :VALUE) *A*) (T (ERROR "Unknown operation ~A" KEY)))) FB3247>

> (funcall not-lexical-closure :increment) 24

Since*a* is a special variable, no lexical closure is created. The value of the variablenot-lexical-closure is a function that accesses and increments the current symbol value of the symbol*a*.

Lexical closures can be used for communication between processes. For example, a process with a lexical variable namedinfo can create the following function:

#'(lambda (new-value) (setf info new-value))
The parent process can pass this function as an argument to any other process it creates. The created process can use the Common Lisp functionfuncall with this argument to set the value of the parent process's lexical variable.


The Advanced User's Guide - 9 SEP 1996

Generated with Harlequin WebMaker