Lisp 什么';s defvar、defparameter、setf和setq之间的差异

Lisp 什么';s defvar、defparameter、setf和setq之间的差异,lisp,common-lisp,clisp,Lisp,Common Lisp,Clisp,我找到了一个新的 但我不太明白这种解释 因此,我尝试使用以下示例运行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]> (

我找到了一个新的

但我不太明白这种解释

因此,我尝试使用以下示例运行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]> 
我的发现完全一样


我不知道它们有什么不同?

这两个
defvar
defparameter
都将变量声明为“动态范围变量”。此外,
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)中,它们只是具有相同的名称,但不是相同的变量,因为它们是在两个不同的词法闭包中定义的


至于
setf
setq
之间的区别,试着总是使用
setf
(我想不出任何一个例子,
(setq blah blahblah)
会起作用,而
(setf blah blahblah)
不会做同样的事情)。

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

现在我知道了defvar和defparameter之间的区别。但是什么时候我们应该使用setf或setq呢?谢谢~@sam:使用
defvar
defparameter
let
引入新变量。使用
setf
setq
变异现有变量。使用它们引入新变量是未定义的行为shown@AndreasRöhler如果是的话,您可能已经在前面执行了顶级
(setq b…)
,这将导致多个lisp环境将变量转换为动态范围。如果您在新启动的Common Lisp中尝试,会发生什么情况?@Vatine Ahh,对不起,在Emacs Lisp中动态地定义了范围。如果是我用defvar定义的变量,我可以用defparameter更改值吗?这是正确的方法吗?或者只有在defparameter中定义的变量才能由defparameter更改?谢谢~正确的方法是在文件中使用DEFVAR和DEFPARAMETER进行值初始化,在侦听器中使用一个或另一个来声明动态变量,并始终使用SETF在非顶级代码中更改值。然后,DEFVAR和DEFPARAMETER之间的差异变为“是否每次加载此文件时都要重置该值?”(使用DEFPARAMETER)、“是否?”(使用DEFVAR)。