5

为什么这段代码不起作用?

(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。

4

2 回答 2

3

在 Common Lisp 中,eval在空词法环境中评估其参数,因此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 的答案。

于 2013-06-23T19:41:13.640 回答
2

因为 common lisp 没有特殊功能。

检查描述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 程序员从不这样做,您可能需要重新检查为什么要尝试以这种方式做事。

于 2013-06-23T19:44:28.267 回答