使用 "setf" 创建特殊变量是否有效?
Is it valid to use "setf" to create special variables?
看来我可以使用 setf
创建特殊变量。例如,如果我启动 REPL 并输入 (setf x 123)
,则会创建一个特殊变量 x
。 CLISP 和 ECL 没有错误。 SBCL 发出警告 (undefined variable: COMMON-LISP-USER::X
),但无论如何都会创建特殊变量。 setf
是创建特殊变量的有效方法吗?
使用setf
创建新变量无效。 HyperSpec 很清楚 setf
是 only intended to update existing variables:
setf
changes the value of place
to be newvalue
.
(setf place newvalue)
expands into an update form that stores the result of evaluating newvalue
into the location referred to by place
.
setf
用于更新地点。没有为尝试使用 setf
更新尚不存在的地点的值指定行为。
在讨论赋值的部分,CLTL2说得更多:
Such alteration is different from establishing a new binding. Constructs for establishing new bindings of variables are described in section 7.5.
虽然这看起来可行,但您不能依赖它。它通常在 REPL 中有效,如果你想在 REPL 中使用这种方式 setf
很好,但你不应该在任何程序中这样做。
其实有点棘手
这是 Common Lisp 中未指定的内容之一。不幸的是。
LispWorks:
CL-USER 61 > (setf foo 1)
1
CL-USER 62 > (defun bar () foo)
BAR
CL-USER 63 > (bar)
1
CL-USER 64 > (let ((foo 2))
(bar))
1
let
中的最后一个 foo
使用词法绑定,因此不认为它是特殊的。
在形式 (setf foo 1)
和 (defun bar () foo)
中,变量 foo
被特定的 Lisp 实现 假定 是特殊的,它甚至可以被 setf
声明为特殊的(-> 大多数实现都没有)。
以上let
形式returns1
还是2
在Common Lisp语言标准中未指定。不过,大多数实现将 return 1
。
下一个:
CL-USER 65 > (let ((foo 2))
(declare (special foo))
(bar))
2
上面我们看到在bar
里面使用foo
其实就是在let
.
里面使用了foo
的动态绑定
基本上,设置未定义变量的确切效果是未指定的。可以假定该变量是否特殊。大多数实现更喜欢 NOT declare it special,这样变量的进一步使用必须是特殊的。
但是变量是否特殊,以及使用它的确切效果,在Common Lisp语言标准中实际上是未定义的。
大多数实施都同意
setf
设置一个未定义的变量只会改变符号的符号值
设置和检索变量假设一个特殊变量
通过let
(或类似)重新绑定变量不会创建一个特殊变量
编译器(如果使用)将警告未定义的变量and/or关于假定特殊变量。
默认不同意的一个实现是 CMUCL -> setf
也将变量声明为特殊变量,类似于 defparameter
所做的。
有关一般样式规则,请参阅 荒谬 的回答的最后一段。
看来我可以使用 setf
创建特殊变量。例如,如果我启动 REPL 并输入 (setf x 123)
,则会创建一个特殊变量 x
。 CLISP 和 ECL 没有错误。 SBCL 发出警告 (undefined variable: COMMON-LISP-USER::X
),但无论如何都会创建特殊变量。 setf
是创建特殊变量的有效方法吗?
使用setf
创建新变量无效。 HyperSpec 很清楚 setf
是 only intended to update existing variables:
setf
changes the value ofplace
to benewvalue
.
(setf place newvalue)
expands into an update form that stores the result of evaluatingnewvalue
into the location referred to byplace
.
setf
用于更新地点。没有为尝试使用 setf
更新尚不存在的地点的值指定行为。
在讨论赋值的部分,CLTL2说得更多:
Such alteration is different from establishing a new binding. Constructs for establishing new bindings of variables are described in section 7.5.
虽然这看起来可行,但您不能依赖它。它通常在 REPL 中有效,如果你想在 REPL 中使用这种方式 setf
很好,但你不应该在任何程序中这样做。
其实有点棘手
这是 Common Lisp 中未指定的内容之一。不幸的是。
LispWorks:
CL-USER 61 > (setf foo 1)
1
CL-USER 62 > (defun bar () foo)
BAR
CL-USER 63 > (bar)
1
CL-USER 64 > (let ((foo 2))
(bar))
1
let
中的最后一个 foo
使用词法绑定,因此不认为它是特殊的。
在形式 (setf foo 1)
和 (defun bar () foo)
中,变量 foo
被特定的 Lisp 实现 假定 是特殊的,它甚至可以被 setf
声明为特殊的(-> 大多数实现都没有)。
以上let
形式returns1
还是2
在Common Lisp语言标准中未指定。不过,大多数实现将 return 1
。
下一个:
CL-USER 65 > (let ((foo 2))
(declare (special foo))
(bar))
2
上面我们看到在bar
里面使用foo
其实就是在let
.
foo
的动态绑定
基本上,设置未定义变量的确切效果是未指定的。可以假定该变量是否特殊。大多数实现更喜欢 NOT declare it special,这样变量的进一步使用必须是特殊的。
但是变量是否特殊,以及使用它的确切效果,在Common Lisp语言标准中实际上是未定义的。
大多数实施都同意
setf
设置一个未定义的变量只会改变符号的符号值设置和检索变量假设一个特殊变量
通过
let
(或类似)重新绑定变量不会创建一个特殊变量编译器(如果使用)将警告未定义的变量and/or关于假定特殊变量。
默认不同意的一个实现是 CMUCL -> setf
也将变量声明为特殊变量,类似于 defparameter
所做的。
有关一般样式规则,请参阅 荒谬 的回答的最后一段。