什么是lisp中set的非破坏性版本?

什么是lisp中set的非破坏性版本?,lisp,common-lisp,Lisp,Common Lisp,我希望能够说(defvar x y)并将它绑定到绑定到x的符号,而不是x,但是defvar只会将它绑定到符号x,这太糟糕了。如何在不默认将其添加为符号属性的情况下执行此操作?您可以使用符号值访问器: CL-USER> (defvar *sym* 'abc) *SYM* CL-USER> (setf (symbol-value *sym*) 100) 100 CL-USER> abc ;non-ANSI-portable, since ABC is undeclared 1

我希望能够说(defvar x y)并将它绑定到绑定到x的符号,而不是x,但是defvar只会将它绑定到符号x,这太糟糕了。如何在不默认将其添加为符号属性的情况下执行此操作?

您可以使用
符号值
访问器:

CL-USER> (defvar *sym* 'abc)
*SYM*
CL-USER> (setf (symbol-value *sym*) 100)
100
CL-USER> abc    ;non-ANSI-portable, since ABC is undeclared
100
请注意,这将设置符号的,这与其动态绑定相同,因此为了便于移植访问它,您需要始终使用
符号值
,或者(本地或全局)声明变量
特殊
。您可以在本地这样做:

CL-USER> (locally (declare (special abc))
           (+ abc 3))
103
或者通过使用
defvar
(不建议对非耳罩符号使用此选项)全局使用:


(不过,我知道没有任何CL实现需要这样做。您通常可以安全地假设未声明的变量在默认情况下是特殊的。)

除了Matthias的答案之外:

你也可以使用

由于
(set symbol value)==(setf(symbol value symbol)value)
,即与
setq
setf
相反,
set
计算其第一个参数。(
setq
可以理解为“set quoted”)
set
在Hyperspec中被标记为不推荐使用,但由于我并不期望下一个CL标准很快就会出现,所以应该可以安全使用


此外,我认为您不必使用
symbol-value
或任何特殊声明来可移植地访问它——至少在所有实际用途上是这样。(虽然有人可能会争辩说,从技术上讲,即使是局部特殊的符号,也不能依赖修改后的符号,但变量可能不会通过
符号值
进行评估,但请参见下面引用的Naggum帖子和Matthias的最后一句话。)

诚然,
setq
setf
set
等仅保证修改一致性实现的绑定。在顶级使用时,
符号值
将被修改,但您不能依赖任何正在发生的全局特殊声明(或任何其他内容)(参见)。但通常,实现至少会使用
符号值
槽来评估新变量。这并不意味着必须使用
符号值
或本地/全局特殊声明才能访问
符号值
,但这确实意味着,同一符号的新绑定不会自动特殊,就像通过
defparameter
和friends引入变量一样

因此,通常情况下,对于全局特殊变量:

T1> (let ((*symbol* 'bar))
      (symbol-value '*symbol*))
BAR
非全局特殊的新绑定本身并不特殊:

T1> (let ((foo 101))       ; this new binding is lexical
      (symbol-value 'foo)) ; so symbol-value refers to the outer special
100
T1> (let ((foo 101))
      foo)                 ; evaluation of foo's new lexical binding
101                        ; doesn't look at the `symbol-value`. lexical
                           ; bindings are mere addresses at runtime.
这也是本地特殊声明可以用来引用
foo
的外部(而非全局)特殊绑定的地方:

T1> (let ((foo 101))
      foo)              ; our new lexical binding
101
T1> (let ((foo 101))
      (locally (declare (special foo))
        foo))           ; the outer special binding
100
T1> (let ((foo 101))
      (setq foo 102)    ; modify the new lexical binding
      foo)
102
T1> foo                 ; doesn't modify the outer special binding
100
T1> (let ((foo 101))
      (locally (declare (special foo))
        (setq foo 102)  ; modify the outer special binding
        foo))
102
T1> foo
102
据我所知,未定义的部分,或者至少是您应该预期的可移植性问题,是这样的顶级修改是否会声明(全局)特殊的东西。我期望的行为就是我在这里展示的,但是如果变量将被声明为全局特殊的或不特殊的(或者甚至可能引入顶级词汇变量?),只要它至少是局部特殊的,就不需要局部声明或
符号值
来访问它


你也应该考虑一下你是否真的需要你所要求的。很可能您想要做的事情可以用一种更惯用的方式解决(至少对于现代的Lispers来说是这样),并且大多数人认为依赖未定义的行为除了REPL使用之外,不会是一种好的风格。

CMU CL实际上全局声明了一个由
setq
special创建的变量。(当然,对于
(setf symbol value)
,这是不正确的。也许你的意思是;我只是想澄清一下。)马蒂亚斯:我的意思是,我希望顶级
setq
要么是全局特殊的,要么是本地顶级的(我认为后者更常见)。在这两种情况下,不必使用
符号值
。但是(我就是这样理解你的答案的)甚至不能保证这一点,所以理论上,我们必须使用
符号值
来实现绝对的可移植性。(但这正是我所不期望的。)也许我的答案的第二部分不够清晰,但这些例子可能仍然有用。要点是人们可以使用
set
,通常不需要
symbol value
(“通常,不需要
symbol value
”只指这个问题。当然,也有使用它的情况。)我说的是这些句子:“
setq
setf
set
等。仅修改绑定。在顶层使用时,
符号值将被修改,但不会进行全局特殊声明。”我同意所有其他要求。:)
T1> (let ((foo 101))       ; this new binding is lexical
      (symbol-value 'foo)) ; so symbol-value refers to the outer special
100
T1> (let ((foo 101))
      foo)                 ; evaluation of foo's new lexical binding
101                        ; doesn't look at the `symbol-value`. lexical
                           ; bindings are mere addresses at runtime.
T1> (let ((foo 101))
      foo)              ; our new lexical binding
101
T1> (let ((foo 101))
      (locally (declare (special foo))
        foo))           ; the outer special binding
100
T1> (let ((foo 101))
      (setq foo 102)    ; modify the new lexical binding
      foo)
102
T1> foo                 ; doesn't modify the outer special binding
100
T1> (let ((foo 101))
      (locally (declare (special foo))
        (setq foo 102)  ; modify the outer special binding
        foo))
102
T1> foo
102