defvar、defparameter、setf 和 setq 之间有什么区别

发布于 2024-12-28 00:25:49 字数 589 浏览 1 评论 0原文

我发现了一个类似问题

但我不太明白这个解释。

所以我尝试使用以下示例运行 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]> 

我发现的是完全相同的。

我不明白他们有什么不同?

I found a Similar question.

But I don't quite understand that explanation.

So I'm trying to run clisp with the following example:

  [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]> 

What I found is totally the same.

I can't figure out what's different with them?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

迷爱 2025-01-04 00:25:50

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

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

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

* (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) 中,它们仅具有相同的名称,但不是相同的变量,因为它们是在两个不同的词法闭包中定义的。

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

Both defvar and defparameter will declare a variable as a "dynamically scoped variable". In addition, defparameter will always set the value of the variable to the value you pass in as the second argument. This is different from defvar, it will only set the value of the variable if it previously hasn't been set.

Defining a variable with setf or setq in the global lexical scope is undefined. Some implementations will create a dynamically scoped variable for you, some will not. You may see diagnostic messages when you do it for the first time.

To understand the difference between lexically-scoped and dynamically-scoped variables, try the following code snippet:

* (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

Here we create a dynamically-scoped variable and a function that return the value (defined inside a binding where it has a different value during the function creation, this is not necessary and done only to look similar to the lexical closure over b). We then define a new variable and define a function return its value.

After that, we call both functions, inside closures binding a value to a variable of the same name. In the dynamic scoping case, it is the same variable. In the lexical closure case (b), they merely have the same name, but are not the same variable, since they're defined in two different lexical closures.

As far as the difference between setf and setq, try to always use setf (I cannot think of any example where (setq blah blahblah) would work and (setf blah blahblah) wouldn't do the same thing).

雨落□心尘 2025-01-04 00:25:49

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

DEFPARAMETER always assigns a value. So:

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

while DEFVAR does it only once, so:

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

SETF is a macro which uses SETQ internally, but has more possibilities. In a way it's a more general assignment operator. E.g. with SETF you can do:

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

but you can't do that with 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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文