普通 lisp 中的本地动态绑定
Local dynamic binding in common lisp
老实说,我不确定我是否完全理解绑定 "dynamic" 与 "lexical" 的含义。但是我明白,当我使用 defvar
或 defparameter
来定义绑定时,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
老实说,我不确定我是否完全理解绑定 "dynamic" 与 "lexical" 的含义。但是我明白,当我使用 defvar
或 defparameter
来定义绑定时,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