公共Lisp中的动态绑定

公共Lisp中的动态绑定,lisp,common-lisp,Lisp,Common Lisp,这个问题是问题的延伸 我已经阅读并(希望)理解了CommonLisp(link:)中的作用域和范围的概念,但我无法理解以下三个示例。所有示例都在SBCL/Slime/Emacs中的新lisp会话上运行 示例1:打印5和5 (defvar x 100) (defun fun1 (x) (print x) (fun2)) (defun fun2 () (print x)) (fun1 5) 示例2:打印5和100 (defun fun1 (x) (print

这个问题是问题的延伸

我已经阅读并(希望)理解了CommonLisp(link:)中的作用域和范围的概念,但我无法理解以下三个示例。所有示例都在SBCL/Slime/Emacs中的新lisp会话上运行

示例1:打印5和5

(defvar x 100)
(defun fun1 (x)
   (print x)
   (fun2))

(defun fun2 ()
   (print x))
     
(fun1 5)
示例2:打印5和100

 (defun fun1 (x)
   (print x)
   (fun2))

 (defun fun2 ()
   (print x))
    
 (defvar x 100)
 
 (fun1 5)
示例3:打印5、5和100

(defvar x 100)

(defun fun1 (x)
  (print x)
  (fun2))

(defun fun2 ()
  (print x))

(defvar x 100)
     
(fun1 5)

x
我理解为什么fun1总是打印5(由于词法范围,但如果我错了,请更正)。我不明白的是为什么fun2在示例1中打印5,在示例2中打印100,在示例3中再次打印5

  • 示例1:x是一个范围不确定的变量,在fun1中设置为5,因此fun2访问该值。这是正确的解释吗
  • 示例2:x由defvar设置为100,但为什么在调用fun1时不重新设置为5?我认为绑定是在调用函数时发生的,还是在定义函数时发生的?当fun1被定义时,x似乎还没有被绑定,因此fun1中x的绑定(在词汇范围内)没有被程序的其余部分看到,然后“全局”绑定在随后的defvar中发生。函数调用中的行为x是否是由于fun1中的词法阴影,而fun2中没有动态阴影?也就是说,这里有两个不同的x实例,因为fun1首先定义了它的x,而当时没有看到“全局”x
  • 示例3:此处显示,由于x是先全局设置的,fun1和fun2都引用x的同一实例,因此其值在fun1期间更新,在fun2期间也应用(均为5)?此外,当我在最后询问x的值时,我得到了100(为什么?当fun2返回5时?)
这与盖伊·斯蒂尔(Guy Steel)的《通用Lisp》一书中的以下摘录有关,但我无法理解:

“使用词法作用域的构造有效地为 每次执行时,每个已建立的实体。因此,动态跟踪 无法发生(尽管可能会出现词汇阴影)。这是特别重要的 涉及动态范围时的重要性。”

以下语句是否始终为真(来源:):

Lisp中的绑定规则是:名称的使用绑定到most 该名称的最近声明仍然有效

我开始理解其中的一些部分,但无法全面理解所有三个部分,因此如果您能提供帮助,将非常有帮助

示例1:x是一个范围不确定的变量,在fun1中设置为5,因此fun2访问该值。这是正确的解释吗

主要是,让我进一步说明一下

defvar
声明
x
时,变量被声明为特殊变量,从现在起
x
始终被视为特殊变量,并动态绑定。当你打电话时:

(fun1 5)
fun1
中的绑定是动态完成的,这意味着
fun1
fun2
的返回值都基于当前的
x
动态绑定

例2:[…]即,这里有两个不同的x实例,因为fun1首先定义了它的x,而当时没有看到“全局”x

是的,但并非所有口译员都是如此(见西尔维斯特的答案)。当您定义
fun1
时,
x
并不特殊;这意味着此时参数
x
的范围是词法的。稍后,当计算
defvar
时,
fun1
x
的绑定仍然是词法绑定,因此调用
fun1
不会修改全局变量
x
的动态绑定

示例3:[…]此外,当我在末尾询问x的值时,我得到了100(为什么?当fun2返回5时

特殊变量的作用域是不确定的,它们随处可见,但它们的绑定具有动态范围,这意味着绑定只在建立它的形式存在时才存在

在这里,当您在顶层请求
x
时,您拥有全局绑定到
x
,100的值;在调用
fun1
有效时,值5仅临时绑定到
x

如果您使用
SETF
来变异绑定,那么您可以变异全局绑定,但在函数应用或
let
绑定期间不会发生这种情况

示例1:x是一个范围不确定的变量,在fun1中设置为5,因此fun2访问该值。这是正确的解释吗

主要是,让我进一步说明一下

defvar
声明
x
时,变量被声明为特殊变量,从现在起
x
始终被视为特殊变量,并动态绑定。当调用:

(fun1 5)
fun1
中的绑定是动态完成的,这意味着
fun1
fun2
的返回值都基于当前的
x
动态绑定

例2:[…]即,这里有两个不同的x实例,因为fun1首先定义了它的x,而当时没有看到“全局”x

是的,但并非所有口译员都是如此(见西尔维斯特的回答)。当您定义
fun1
时,
x
并不特殊;这意味着此时参数
x
的范围是词法的。稍后,当计算
defvar
时,
fun1
中的
x
的绑定仍然是词法的,因此调用
fun1
不会修改g的动态绑定大叶变量
x

示例3:[…]此外,当我在末尾询问x的值时,我得到了100(为什么?当fun2返回5时

特殊变量的作用域不确定,它们随处可见,但它们的绑定具有动态ext
(with-output-to-string (*standard-output*)
  (some-function-whose-printed-output-you-want))
; ==> a string with the actual output
(defvar x 100)    ; declares X to be special, globally and locally
                  ; also sets X to 100

(defun fun1 (x)   ; X is a dynamically bound variable
  (print x)       ; lookup of dynamic binding of X
  (fun2))        

(defun fun2 ()
  (print x))      ; lookup of dynamic binding of X
     
(fun1 5)
 (defun fun1 (x)  ; X is a lexical local variable
   (print x)      ; lexical reference to X
   (fun2))

 (defun fun2 ()
   (print x))     ; X is undeclared/undefined
                  ; the exact behaviour is undefined in Common Lisp
                  ; many implementations assume dynamic lookup of X
                  ; most compilers will show a warning
                  ; CMUCL also by default declared X globally to be special
                  ; -> don't use this in your code
    
 (defvar x 100)   ; declares X to be special, globally and locally 
                  ; also sets X to 100     
 (fun1 5)
(defvar x 100)    ; declares X to be special, globally and locally
                  ; also sets X to 100

(defun fun1 (x)   ; X is a dynamically bound variable
  (print x)       ; lookup of dynamic binding of X
  (fun2))

(defun fun2 ()
  (print x))      ; lookup of dynamic binding of X

(defvar x 100)    ; does nothing
                  ;  -> X is already declared special
                  ;  -> X already has a value
                  ;     see also: DEFPARAMETER
     
(fun1 5)

x                 ; lookup of global (or thread local) value of X