Eval and lexical variables

2019-05-29 02:42发布

问题:

I'm doing a small project just for fun, and I added eval support for it to make debug easier. But later I found a problem:

(let ((x 1))
    (eval (1+ x)))

(defun foo (x form)
    (eval form))
(foo 1 '(1+ x))

Code above won't work. Could someone please explain why and how to work it around? Thanks very much.

回答1:

First, though

(let ((x 1))
  (eval (1+ x)))

may look like it does work (it certainly does something), it is likely not doing, what you intend it to do. eval is a regular function, so it receives its arguments evaluated by the caller. Effectively, you are calling eval with an integer value of 2 -- which is then "evaluated" (since integers are self-quoting) to a result value of 2.

In

(defun foo (x form)
  (eval form))

it's easier to diagnose the failure. Run-time lexical bindings are not first-class objects, but something maintained by the interpreter/compiler behind the scenes. Regular functions (like eval) cannot access lexical variables defined at their call-sites.

One work-around would be to use special variables:

(defun foo (x form)
  (declare (special x))
  (eval form))

The declaration tells your lisp implementation, that x should be dynamically bound within its scope.