49

我发现了一个类似的问题

但我不太明白这个解释。

因此,我尝试使用以下示例运行 clisp:

  [1]> (defvar a 5)
  A
  [2]> (+ a 1)
  6
  [3]> (defparameter b 5)
  B
  [4]> (+ b 1)
  6
  [5]> (setf c 5)
  5
  [6]> (+ c 1)
  6
  [7]> (setq d 5)
  5
  [8]> (+ d 1)
  6
  [9]> (let ((a 500)) (+ a 1))
  501
  [10]> (let ((b 500)) (+ b 1))
  501
  [11]> (let ((c 500)) (+ c 1))
  501
  [12]> (let ((d 500)) (+ d 1))
  501
  [13]> 

我发现的完全一样。

我想不通他们有什么不同?

4

2 回答 2

74

DEFPARAMETER总是赋值。所以:

[1]> (defparameter a 1)
A
[2]> (defparameter a 2)
A
[3]> a
2

DEFVAR只做一次,所以:

[4]> (defvar b 1)
B
[5]> (defvar b 2)
B
[6]> b
1

SETF是一个SETQ内部使用的宏,但有更多的可能性。在某种程度上,它是一个更通用的赋值运算符。例如,SETF你可以这样做:

[19]> (defparameter c (list 1 2 3))
[21]> (setf (car c) 42)                                              
42
[22]> c
(42 2 3)

但你不能这样做SETQ

[23]> (setq (car c) 42)                                              
*** - SETQ: (CAR C) is not a symbol
The following restarts are available:
USE-VALUE      :R1      Input a value to be used instead.
ABORT          :R2      Abort main loop
Break 1 [24]> abort
于 2012-01-19T14:47:58.360 回答
27

两者都defvardefparameter变量声明为“动态范围变量”。此外,defparameter将始终将变量的值设置为您作为第二个参数传入的值。这与 不同defvar,它只会在之前未设置变量的情况下设置变量的值。

setf在全局词法范围内或setq在全局词法范围内定义变量是未定义的。有些实现会为您创建一个动态范围的变量,有些则不会。第一次执行此操作时,您可能会看到诊断消息。

要了解词法范围变量和动态范围变量之间的区别,请尝试以下代码片段:

* (defvar *a* 1)

*A*
* (let ((*a* 5)) (defun demo-a () *a*))

DEMO-A
* (let ((b 5)) (defun demo-b () b))

DEMO-B
* (let ((*a* 100)) (demo-a))

100
* (let ((b 100)) (demo-b))

5

在这里,我们创建了一个动态范围的变量和一个返回值的函数(定义在一个绑定中,在函数创建期间它具有不同的值,这不是必需的,只是为了看起来类似于 b 上的词法闭包)。然后我们定义一个新变量并定义一个函数返回它的值。

之后,我们调用这两个函数,在闭包内部将一个值绑定到一个同名变量。在动态范围的情况下,它是同一个变量。在词法闭包情况 (b) 中,它们只是具有相同的名称,但不是同一个变量,因为它们是在两个不同的词法闭包中定义的。

至于 and 之间的区别setfsetq请尝试始终使用setf(我想不出任何(setq blah blahblah)可以工作(setf blah blahblah)但不会做同样事情的例子)。

于 2012-01-19T14:44:53.490 回答