【问题标题】:Symbol names undefined variable符号名称未定义变量
【发布时间】:2018-05-24 14:28:13
【问题描述】:

我有一个关于符号和全局变量之间关系的问题。

符号值属性的超规范状态:

"如果一个符号有值属性,就说它是绑定的,这个事实可以通过函数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> 

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

(我使用 SBCL 1.3.15。)

感谢您的回答。

编辑:

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

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

全局变量的超规范状态:

"全局变量 n.动态变量或常量变量。"

所以我现在想,SBCL之所以说它是“未定义的”,不是是否特殊,而是是动态(特殊)变量还是常量变量(hyperspec:"constant variable n.a variable, the的价值永远不会改变”)。

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

你同意吗?

编辑 2:

好吧,总而言之,我想,因为超规范没有定义未定义的全局变量,所以它们不存在。

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

谢谢你的回答,三个我都接受,但我只能标记一个。

【问题讨论】:

    标签: common-lisp


    【解决方案1】:

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

    如果你在没有先创建变量的情况下设置变量的值(这也是赤裸裸的setq 会做的事情),它是否变得特殊是不确定的。

    通常,不使用非特殊的全局变量。这就是为什么你应该使用defvar、defparameter 等。

    【讨论】:

      【解决方案2】:

      如其他答案所述,*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 访问器从动态环境中检索绑定。

      【讨论】:

        【解决方案3】:

        根据超规范不存在非特殊(也不是常量)的全局变量。

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

        LispWorks 中的这个例子:

        CL-USER 46 > (boundp 'foo)
        NIL
        

        所以FOO 是未绑定的。

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

        上面在 LispWorks interpreter 中定义了一个函数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 会这样做(会吗?)。这种行为并不常见,也不受欢迎,因为没有标准的方法来撤消声明。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2019-07-21
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2022-11-21
          • 2021-09-13
          相关资源
          最近更新 更多