为什么这段代码不起作用?
(setf x '(foo bar (baz)))
(labels
((baz () (print "baz here")))
(baz) ;works
(eval (third x))) ;fails with the below message
*** - EVAL: undefined function BAZ
我正在使用GNU CLISP。
答案 0 :(得分:3)
在Common Lisp中,eval
在null词法环境中计算其参数,因此无法找到词法绑定函数baz
。
虽然Common Lisp标准不提供访问词法环境并使用它调用eval的可移植方式,但您的实现可能具有此功能。例如,在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>
请参阅geocar对其他方法的回答。
答案 1 :(得分:2)
检查EVAL
的说明:
由于词汇环境为空,因此无法访问baz
函数(由labels
定义)。您认为可以通过将baz
置于动态环境中来解决此问题(您可能想要(declare (special baz))
或(declare (special (function baz)))
或类似的东西)但是唉:没有办法做到这一点
(defvar baz* nil)
(defun baz (&rest args) (apply baz* args))
然后,您需要动态设置baz*
,而不是使用labels
:
(setf x '(foo bar (baz)))
(let ((baz* (lambda () (print "baz here"))))
(eval (third x)))
之所以只是关于优化泄漏到规范中的一些硬性原因。基本上,每个函数调用都需要一些存根,除非编译器可以证明该函数永远不会动态定义动态。这很难有效地完成,并且它不是大多数CL程序员所做过的,所以规范编写者只是禁止它。
正如您所看到的,就像CL中的大多数事情一样,如果您需要它,您可以轻松地自己获取它。然而。鉴于大多数CL程序员从不这样做,您可能需要重新审视为什么要尝试这样做。