Common Lisp the Language, 2nd Edition


next up previous contents index
Next: The Top-Level Loop Up: The Evaluator Previous: The Evaluator

20.1. Run-Time Evaluation of Forms

The function eval is the main user interface to the evaluator. Hooks are provided for user-supplied debugging routines to obtain control during the execution of an interpretive evaluator. The functions evalhook and applyhook provide alternative interfaces to the evaluator mechanism for use by these debugging routines.


[Function]
eval form

The form is evaluated in the current dynamic environment and a null lexical environment. Whatever results from the evaluation is returned from the call to eval.

Note that when you write a call to eval two levels of evaluation occur on the argument form you write. First the argument form is evaluated, as for arguments to any function, by the usual argument evaluation mechanism (which involves an implicit use of eval). Then the argument is passed to the eval function, where another evaluation occurs. For example:

(eval (list 'cdr (car '((quote (a . b)) c)))) => b

The argument form (list 'cdr (car '((quote (a . b)) c))) is evaluated in the usual way to produce the argument (cdr (quote (a . b))); this is then given to eval because eval is being called explicitly, and eval evaluates its argument (cdr (quote (a . b))) to produce b.

If all that is required for some application is to obtain the current dynamic value of a given symbol, the function symbol-value may be more efficient than eval.

change_begin
X3J13 voted in January 1989 (MAPPING-DESTRUCTIVE-INTERACTION)   to restrict user side effects; see section 7.9.
change_end


[Variable]
*evalhook*
*applyhook*

If the value of *evalhook* is not nil, then eval behaves in a special way. The non-nil value of *evalhook* should be a function that takes two arguments, a form and an environment; this is called the eval hook function. When a form is to be evaluated (any form at all, even a number or a symbol), whether implicitly or via an explicit call to eval, no attempt is made to evaluate the form. Instead, the hook function is invoked and is passed the form to be evaluated as its first argument. The hook function is then responsible for evaluating the form; whatever is returned by the hook function is assumed to be the result of evaluating the form.

The variable *applyhook* is similar to *evalhook* but is used when a function is about to be applied to arguments. If the value of *applyhook* is not nil, then eval behaves in a special way.

old_change_begin
The non-nil value of *applyhook* should be a function that takes three arguments: a function, a list of arguments, and an environment; this is called the apply hook function.
old_change_end

change_begin
X3J13 voted in January 1989 (APPLYHOOK-ENVIROMENT)   to revise the definition of *applyhook*. Its value should be a function of two arguments, a function and a list of arguments; no environment information is passed to an apply hook function.
change_end

This was simply a flaw in the first edition. Sorry about that.

When a function is about to be applied to a list of arguments, no attempt is made to apply the function. Instead, the hook function is invoked and is passed the function and the list of arguments as its first and second arguments. The hook function is then responsible for evaluating the form; whatever is returned by the hook function is assumed to be the result of evaluating the form. The apply hook function is used only for application of ordinary functions within eval. It is not used for applications via apply or funcall, for applications by such functions as map or reduce, or for invocation of macro-expansion functions by either eval or macroexpand.

change_begin
X3J13 voted in June 1988 (FUNCTION-TYPE)   to specify that the value of *macroexpand-hook* is first coerced to a function before being called as the expansion interface hook. This vote made no mention of *evalhook* or *applyhook*, but this may have been an oversight.

A proposal was submitted to X3J13 in September 1989 to specify that the value of *evalhook* or *applyhook* is first coerced to a function before being called. If this proposal is accepted, the value of either variable may be nil, any other symbol, a lambda-expression, or any object of type function.
change_end

The last argument passed to either kind of hook function contains information about the lexical environment in an implementation-dependent format. These arguments are suitable for the functions evalhook, applyhook, and macroexpand.

When either kind of hook function is invoked, both of the variables *evalhook* and *applyhook* are rebound to the value nil around the invocation of the hook function. This is so that the hook function will not be invoked recursively on evaluations and applications that occur in the course of executing the code of the hook function. The functions evalhook and applyhook are useful for performing recursive evaluations and applications within the hook function.

The hook feature is provided as an aid to debugging. The step facility is implemented using this hook.

If a non-local exit causes a throw back to the top level of Lisp, perhaps because an error could not be corrected, then *evalhook* and *applyhook* are automatically reset to nil as a safety feature.


[Function]

evalhook form evalhookfn applyhookfn &optional env 
applyhook function args evalhookfn applyhookfn &optional env

The functions evalhook and applyhook are provided to make it easier to exploit the hook feature.

In the case of evalhook, the form is evaluated. In the case of applyhook, the function is applied to the list of arguments args. In either case, for the duration of the operation the variable *evalhook* is bound to evalhookfn, and *applyhook* is bound to applyhookfn. Furthermore, the env argument is used as the lexical environment for the operation; env defaults to the null environment. The check for a hook function is bypassed for the evaluation of the form itself (for evalhook) or for the application of the function to the args itself (for applyhook), but not for subsidiary evaluations and applications such as evaluations of subforms. It is this one-shot bypass that makes evalhook and applyhook so useful.

change_begin
X3J13 voted in January 1989 (APPLYHOOK-ENVIROMENT)   to eliminate the optional env parameter to applyhook, because it is not (and cannot) be useful. Any function that can be applied carries its own environment and does not need another environment to be specified separately. This was a flaw in the first edition.
change_end

Here is an example of a very simple tracing routine that uses just the evalhook feature.

(defvar *hooklevel* 0) 

(defun hook (x) 
  (let ((*evalhook* 'eval-hook-function)) 
    (eval x))) 

(defun eval-hook-function (form &rest env) 
  (let ((*hooklevel* (+ *hooklevel* 1))) 
    (format *trace-output* "~%[email protected]:  ~S" 
            (* *hooklevel* 2) form) 
    (let ((values (multiple-value-list 
                     (evalhook form 
                               #'eval-hook-function 
                               nil 
                               env)))) 
      (format *trace-output* "~%[email protected]:~{ ~S~}" 
              (* *hooklevel* 2) values) 
      (values-list values))))

Using these routines, one might see the following interaction:

(hook '(cons (floor *print-base* 2) 'b)) 
  Form:  (CONS (FLOOR *PRINT-BASE* 2) (QUOTE B)) 
    Form:  (FLOOR *PRINT-BASE* 3) 
      Form:  *PRINT-BASE* 
      Value: 10 
      Form:  3 
      Value: 3 
    Value: 3 1 
    Form:  (QUOTE B) 
    Value: B 
  Value: (3 . B) 
(3 . B)


[Function]
constantp object

If the predicate constantp is true of an object, then that object, when considered as a form to be evaluated, always evaluates to the same thing; it is a constant. This includes self-evaluating objects such as numbers, characters, strings, bit-vectors, and keywords, as well as all constant symbols declared by defconstant, such as nil, t, and pi. In addition, a list whose car is quote, such as (quote foo), is considered to be a constant.

If constantp is false of an object, then that object, considered as a form, might or might not always evaluate to the same thing.



next up previous contents index
Next: The Top-Level Loop Up: The Evaluator Previous: The Evaluator


[email protected]