Common Lisp:在函数中使用未定义的变量

时间:2014-04-02 14:40:47

标签: lisp common-lisp

我想在Common Lisp中做类似的事情:

(defparameter *fun* 
  (lambda () x))

(let ((x 0))
  (funcall *fun*)) ;should return 0

我想在定义函数时访问未定义的函数中的本地绑定。

如果我使用x作为参数,它会起作用,但我不能改变变量的值:

(defparameter *fun* 
  (lambda (x) (setf x (+ x 1))))

(let ((x 0))
  (funcall *fun* x)) ;should return 1, would return 0

我怎样才能做我想做的事?

2 个答案:

答案 0 :(得分:6)

您可以在绑定站点和参考站点声明变量special(dynamic):

(defparameter *fun* 
  (lambda () (declare (special x)) x))

(let ((x 0))
  (declare (special x))
  (funcall *fun*))

或全球:

(defvar *x*)  ;; makes *x* special

(defparameter *fun* 
  (lambda () *x*))

(let ((*x* 0))
  (funcall *fun*))

延迟编辑:

在这种情况下,宏可能会更好地为您服务。函数可以访问的唯一词法绑定是在创建时存在的那些。例如,您描述的行为由宏incf中的标准给出。 Define-modify-macro是一个帮助器,用于定义类似于incf的宏。 http://www.lispworks.com/documentation/HyperSpec/Body/m_defi_2.htm

答案 1 :(得分:2)

您可以在嵌套范围中定义函数:

[2]> (defparameter *fun* (let ((x 0)) (lambda () (setf x (+ x 1)))))
*FUN*
[3]> (funcall *fun*)
1
[4]> (funcall *fun*)
2

如果您的函数是在词法变量的范围之外定义的,则根据词法范围的定义,它无法访问该变量。为了能够做到这一点,它必须范围内。

解决这个问题的另一个方法是使变量特殊,给它动态范围:

[5]> (defparameter *x* 1)
*X*
[11]> (defun fun () (setf *x* (+ *x* 1)))
FUN
[12]> *x*
1
[13]> (fun)
2
[16]> *x*
2