Why won't this piece of code work?
(setf x '(foo bar (baz)))
(labels
((baz () (print "baz here")))
(baz) ;works
(eval (third x))) ;fails with the below message
*** - EVAL: undefined function BAZ
I'm using GNU CLISP.
In Common Lisp, eval
evaluates its argument in a null lexical environment, so your lexically bound function baz
can't be found.
While the Common Lisp standard doesn't provide a portable way to access the lexical environment and invoke eval with it, your implementation might have this functionality. For example, in CLISP:
cs-user> (setf x '(foo bar (baz)))
(foo bar (baz))
cs-user> (labels ((baz () (print "baz here")))
(eval-env (third x) (the-environment)))
"baz here"
"baz here"
cs-user>
See geocar's answer for other approaches.
Check the description of EVAL
:
Evaluates form in the current dynamic environment and the null lexical environment.
Since the lexical environment is empty, your baz
function (defined by labels
) isn't accessible. You'd think you could fix this by putting baz
in the dynamic environment (you might want something like (declare (special baz))
or (declare (special (function baz)))
or something like this) but alas: there's no way to do this.
(defvar baz* nil)
(defun baz (&rest args) (apply baz* args))
You then need to dynamically set baz*
instead of using labels
:
(setf x '(foo bar (baz)))
(let ((baz* (lambda () (print "baz here"))))
(eval (third x)))
The reason why is just some hard bits about optimisation leaking into the spec. Basically, every function-call would need some stubbing unless the compiler could prove that the function would never get defined dynamically swizzleable. That's hard to do efficiently, and it's not something most CL programmers ever did, so the spec-writers simply forbade it.
As you can see, and as with most things in CL, you can easily get it yourself if you need it. However. Given that most CL programmers never do this, you may want to re-examine why you're trying to do things this way.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With