想要在LISP中使用EVAL访问词法定义的函数

时间:2013-06-23 19:02:12

标签: clisp

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

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

2 个答案:

答案 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)

因为常见的lisp没有特殊功能。

检查EVAL的说明:

  

评估当前dynamic environmentnull lexical environment中的表单

由于词汇环境为空,因此无法访问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程序员从不这样做,您可能需要重新审视为什么要尝试这样做。