在编译期间声明特殊变量时会发生什么

ccQ*_*ein 2 lisp common-lisp dynamic-binding

我只是在我的Common Lisp代码遇到异常情况时,我想测试locallydeclare

(defvar test-out 2) ;; make a dynamic variable

;; function below just simply re-write from locally doc
(defun test (out)
  (declare (special out))
  (let ((out 1))
    (print out) ;; => 1
    (print (locally (declare (special out)) out)))) ;; => 2

;; when argument has same name as outside dynamic variable
(defun test1 (test-out)
  (declare (special test-out))
  (let ((test-out 1))
    (print test-out) ;; => 1
    (print (locally (declare (special test-out)) test-out)))) ;; => also 1
Run Code Online (Sandbox Code Playgroud)

我知道动态变量的正确名称应该是*test-out*,但我认为这只是为了程序员方便地告诉动态变量。

我对test1函数有点困惑,看起来好像locally declare没有指向test-out外部的动态变量。

谁能向我解释test1函数的行为?谢谢

更新:

  1. 我给一个新的动态变量(defvar test-out-1 3),像这样调用(test1 test-out-1),仍然得到打印结果11
  2. 我改变test1从的说法名字test-outtest-out1,重新编译test1和问题就消失了,打印出来的结果12我打电话(test1 test-out)
  3. 我更改(defvar test-out 2)(defvar test-out-1 2)(更改动态变量名称)。然后重新编译整个文件(test-out这次没有调用任何动态变量,并且test1参数的名称为test-out),问题消失了。
  4. 3点后,我打电话(defvar test-out 2)(test1 test-out)。这次,它打印出正确的答案:12
  5. 4之后,我重新编译test1一遍,然后再运行(test1 test-out),它打印出来1,并1再次,问题再次出现。

如果我猜对了,则test1出于某种原因,在编译时,其参数名称会连接到dynamic变量test-out。这就是为什么我什至在调用不同值时都会收到错误结果的原因,但是,当我在重新编译测试之前test1使用不同的参数名称或干净的动态变量test-out重新编译时,问题会自行解决。

如果是这样,我仍然不明白为什么编译功能会在环境中受到动态变量的影响。

Rai*_*wig 6

DEFVAR声明一个特殊的变量-这意味着它们在绑定时将使用动态绑定,访问此类变量将寻找动态绑定。在全球和所有绑定级别。现在和将来。

从那时起,新代码中该变量的所有使用和绑定将自动声明为特殊。甚至是本地LET绑定。在所有级别上。没有办法将其声明为非特殊。因此,test1现在不再需要函数中的局部特殊声明,因为它已经被声明为特殊。现在,即使没有显式声明,它的每次使用或绑定都在使用动态绑定。

这也是为什么将任何变量DEFVARDEFPARAMETER变量写为的原因*variablename*,以防止意外地将所有具有相同名称的变量声明为特殊变量。

避免:

(defvar x 10)         ; here X is explicitly declared special

(defun foo (x)        ; here X is implicitly declared special
  (let ((x ...))      ; here X is implicitly declared special
    ...))   
Run Code Online (Sandbox Code Playgroud)

做:

(defvar *x* 10)       ; here *X* is declared special

(defun foo (x)        ; here X is lexical
  (let ((x ...))      ; here X is lexical
    ...))   
Run Code Online (Sandbox Code Playgroud)