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

时间:2011-10-03 08:34:33

标签: lisp common-lisp

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

2 个答案:

答案 0 :(得分:2)

您可以使用symbol-value访问者:

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

请注意,这会设置符号的 value cell ,这与其动态绑定相同,因此为了便于访问它,您需要使用symbol-value全部时间或(本地或全局)声明变量special。您可以在本地执行此操作:

CL-USER> (locally (declare (special abc))
           (+ abc 3))
103

或全球使用defvar(不推荐用于非耳罩符号):

CL-USER> (defvar abc)
ABC

(我知道没有CL实现实际上需要这个。你通常可以安全地假设默认情况下假定未声明的变量是特殊的。)

答案 1 :(得分:1)

除了马蒂亚斯的回答:

您也可以使用set

T1> (defparameter *symbol* 'foo)
*SYMBOL*
T1> (set *symbol* 100)
100

(set symbol value) == (setf (symbol-value symbol) value)起,即与setqsetf相比,set评估其第一个参数。 (setq可以被读作“set quoted”)在Hyperspec中标记为set已被弃用,但由于我不希望很快就会出现下一个CL标准,因此使用它应该是安全的。 / p>


此外,我认为您不必使用symbol-value或任何特殊声明来便携式访问它 - 至少在所有实际用途中都是如此。 (虽然人们可能会争辩说,从技术上讲,因为人们不能依赖修改后的符号,即使是本地特殊的,也许变量不会通过symbol-value进行评估,但请参阅下面引用的Naggum帖子,以及Matthias的最后一篇句。)

确实如此setqsetfset等。只保证修改绑定以符合实现。在顶层使用时,symbol-value将被修改,但您不能依赖任何全局特殊声明(或其他任何声明)(参见Naggum)。但通常情况下,实现至少会使用symbol-value槽来评估新变量。这并不意味着必须使用symbol-value或本地/全局特殊声明来访问symbol-value,但 意味着 new 相同符号的绑定不会自动特殊,因为通过defparameter和朋友引入的变量就是这种情况。

所以,通常情况下,使用全局特殊变量:

T1> (let ((*symbol* 'bar))
      (symbol-value '*symbol*))
BAR

new 绑定到全局特殊内容本身并不特别:

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

据我了解,未定义的部分,或者至少是您应该预期可移植性问题的部分,是这样的顶级修改是否可以声明某些(全局)特殊的。我希望期望的行为是我在这里展示的,但是如果变量将被声明为全局特殊或者不是(或者甚至可能引入一个顶级词法变量?),只要它至少在本地生成特殊的,不需要本地声明或symbol-value来访问它。

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