普通 lisp 中的本地动态绑定

Local dynamic binding in common lisp

老实说,我不确定我是否完全理解绑定 "dynamic" 与 "lexical" 的含义。但是我明白,当我使用 defvardefparameter 来定义绑定时,1. 它声明了一个全局变量 2. 绑定被声明为 "special",这样它就可以被一个新的本地绑定,例如

(defvar *x* 3)
(defun f () *x*)
(f) ;=>3
(let ((*x* 2)) (f));=>2

现在,我的问题是,是否可以有一个本地绑定(即不污染全球环境的绑定)具有相同的 属性(即可以被 "outer"/"newer" 绑定)?

示例:

(special-binding ((x 1)) (defun f () x))
(f);=>1
x;=>error, no binding in the global environment
(let ((x 2)) (f));=>2

我尝试在 let 块或 (locally (declare (special x)) ...) 中使用 (special x) 声明,但它似乎没有创建闭包(从定义的函数中请求变量的值这样会触发 "Unbound-Variable" 错误)。

您不能在闭包中捕获动态绑定,只能捕获词法绑定。

你需要在函数中声明变量特殊,所以它会使用动态绑定:

(defun f () 
  (declare (special x))
  x)

然后你需要在调用周围动态绑定变量,使用:

(let ((x 1))
  (declare (special x))
  (f))

首先,动态变量仅从动态绑定中获取其值,而不是词法:

(defun f ()
  (declare (special x))
  x)

(let ((x 1))
  ;; without this declaration, we would get an unbound variable error
  (declare (special x))
  (f))
;; => 1

您可以使用 progv:

实现本地动态绑定的默认值
(defun b ()
  (progv (if (boundp 'x) () '(x))
      (if (boundp 'x) () '(1))
    (locally (declare (special x))
      x)))

(let ((x 2))
  (declare (special x))
  (b))
;; -> 2

(b)
;; -> 1