我希望能够说(defvar x y)并将它绑定到绑定到x而不是x的符号,但是defvar只会将它绑定到符号x,这太糟糕了。如何在没有默认添加符号属性的情况下执行此操作?
答案 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)
起,即与setq
和setf
相比,set
评估其第一个参数。 (setq
可以被读作“set quoted”)在Hyperspec中标记为set
已被弃用,但由于我不希望很快就会出现下一个CL标准,因此使用它应该是安全的。 / p>
此外,我认为您不必使用symbol-value
或任何特殊声明来便携式访问它 - 至少在所有实际用途中都是如此。 (虽然人们可能会争辩说,从技术上讲,因为人们不能依赖修改后的符号,即使是本地特殊的,也许变量不会通过symbol-value
进行评估,但请参阅下面引用的Naggum帖子,以及Matthias的最后一篇句。)
确实如此setq
,setf
,set
等。只保证修改绑定以符合实现。在顶层使用时,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之外,大多数情况都不会被认为是好的风格。