符号名称未定义变量

时间:2018-05-24 14:28:14

标签: common-lisp

我对符号和全局变量之间的关系有疑问。

超标准表示符号的value属性:

“如果符号具有值属性,则称其为绑定,并且该事实可以由函数boundp检测。绑定符号的值单元格中包含的对象是由以下命名的全局变量的值:该符号,可以通过函数symbol-value访问。“

如果我执行以下步骤:

CL-USER> (intern "*X*")
*X*
NIL
CL-USER> (boundp '*x*)
NIL
CL-USER> (setf (symbol-value '*x*) 1)
1
CL-USER> (boundp '*x*)
T

据我了解,上述条件已得到满足。应该有一个由符号命名的全局变量,变量的值是符号值。但这是错误的。

CL-USER> (describe '*x*)
COMMON-LISP-USER::*X*
  [symbol]

*X* names an undefined variable:
  Value: 1
; No value
CL-USER> 

必须宣布特别。

CL-USER> (proclaim '(special *x*))
; No value
CL-USER> (describe '*x*)
COMMON-LISP-USER::*X*
  [symbol]

*X* names a special variable:
  Value: 1
; No value
CL-USER> 

你能解释一下这种行为吗?什么意思是“未定义的变量”,我没有在超标准中找到这个术语。

(我使用SBCL 1.3.15。)

感谢您的回答。

编辑:

(由于此评论适用于以下两个答案(用户Svante和coredump),我将其写为编辑,而不是对两个答案的评论)。

我同意* x *是全局变量的答案。

全局变量的超标准状态:

“全局变量,动态变量或常量变量。”

因此我认为,现在,SBCL说“未定义”的原因不在于它是否特殊,而在于它是动态(特殊)变量还是常量变量(hyperspec:“常量变量n。变量,价值永远不会改变“)。

以下答案中提到的第三个定义(也许我理解错误的答案),根据超级规范,它是一个不特殊的全局变量(而不是常量)。

你能同意吗?

编辑2:

好的,总的来说,我认为,由于超级规范没有定义未定义的全局变量,因此它们不存在。

但正确的答案是,它们确实存在并且未定义,这意味着它依赖于实现,如何处理它们。

感谢您的回答,我接受了他们三个,但我只能标记一个。

3 个答案:

答案 0 :(得分:4)

由符号命名的全局变量,其值符号值。这就是输出告诉你的。 undefined 的东西是变量的状态:它是否特殊。我同意输出的措辞有点特殊。

如果你设置一个变量的值而不先创建它(这也是裸setq也会这样做的话),那么它是否变得特殊是未定义的。

传统上,人们不使用非特殊的全局变量。这就是为什么你应该使用defvardefparameter等等。

答案 1 :(得分:4)

如其他答案中所述,*X*未声明特殊(动态)。如果你的词汇绑定符号,SBCL也会给你一个警告:

FUN> (let ((*X* 30)) (list *X* (symbol-value '*X*)))
; in: LET ((*X* 30))
;     (LET ((FUN::*X* 30))
;       (LIST FUN::*X* (SYMBOL-VALUE 'FUN::*X*)))
; 
; caught STYLE-WARNING:
;   using the lexical binding of the symbol (FUN::*X*), not the
;   dynamic binding, even though the name follows
;   the usual naming convention (names like *FOO*) for special variables
; 
; compilation unit finished
;   caught 1 STYLE-WARNING condition
(30 10)

另请注意,如果*X*在本地声明为特殊情况,会发生什么:

FUN> (let ((*X* 30)) (declare (special *X*)) (list *X* (symbol-value '*X*)))
(30 30)

symbol-value访问器从动态环境中检索绑定。

答案 2 :(得分:3)

  

根据超级规范,不存在非特殊(而非常数)的全局变量。

标准中未定义实际行为,但在实现中它可能以某种方式工作。

LispWorks中的这个例子:

CL-USER 46 > (boundp 'foo)
NIL

所以FOO是未绑定的。

CL-USER 47 > (defun baz (bar) (* foo bar)) 
BAZ

上面在LispWorks 解释器中定义了一个函数baz - 它没有被编译。没有警告。

现在我们设置此符号foo

CL-USER 48 > (setq foo 20)
20

CL-USER 49 > (baz 22)
440

我们已成功调用它,即使FOO未被声明为全局函数。

让我们检查,如果它被声明为特殊:

CL-USER 50 > (SYSTEM:DECLARED-SPECIAL-P 'foo)
NIL

现在我们从上面编译函数:

CL-USER 51 > (compile 'baz)
;;;*** Warning in BAZ: FOO assumed special
BAZ

编译器说它不知道FOO并假设它是特殊的。

此行为未定义且实现不同:

  • 解释器可能只使用全局符号值而不是抱怨 - 请参阅上面的LispWorks示例。这在实施中相对常见。

  • 编译器可能会假定未定义的变量是一个特殊变量并发出警告。这在实现中也相对常见。

  • 编译器可能会假定未定义的变量是一个特殊变量,并且声明该变量是特殊的。这不常见 - 默认情况下CMUCL(确实如此)。此行为并不常见且不受欢迎,因为没有标准方法来撤消声明。