【问题标题】:How come (let ((x 'huh?)) (cons (boundp 'x) x)) evaluates to (NIL . HUH?)?为什么 (let ((x 'huh?)) (cons (boundp 'x) x)) 评估为 (NIL . HUH?)?
【发布时间】:2021-12-26 17:42:34
【问题描述】:

我不明白这个:

CL-USER> (let ((x 'huh?)) (cons (boundp 'x) x))
(NIL . HUH?)

我曾预计,在上面的 let 表达式中,x 将被绑定,因此整个表达式将计算为 (t . huh?)。否则,如果(与我的预期相反)x 未绑定在let 的主体中,那么至少上面表达式的评估会导致错误(因为我已经通过了一个未绑定的变量作为cons 的第二个参数)。

为了让我更加困惑,Common Lisp HyperSpec 对 boundp says 的描述:

如果符号被绑定则返回真;否则,返回 false。

...“绑定”一词超链接到此glossary definition(我的重点)1

bound adj., v.t. 1. 形容词。在绑定中具有相关的表示。 ``let 命名的变量绑定在它的主体内。'' 参见未绑定。 2. 形容词。具有阴影[2]另一个的本地绑定。 ``变量 print-escape 在 princ 函数中被绑定。'' 3. v.t. bind 的过去式。

此外,let 的 CLHS 文档说明了以下内容(我的重点):

...所有变量 varj绑定到相应的值; ...

当然,boundp(我之前已经链接到)的 HyperSpec 页面有以下示例:

(let ((x 2)) (boundp 'x)) =>  false

...这确实可以证明我所观察到的实际上是“官方记录的行为”的断言是正确的,但是鉴于我上面引用的所有其他内容,这种狭隘正确的理由并不能让人感到安慰。

有人可以为我解决这个巨大的(希望只是明显的)矛盾吗?


1 我意识到上面突出显示的短语只是一个示例,说明如何在句子中使用“绑定”一词,但如果它是一个真正的反常示例声明与 Common Lisp 的实际情况完全相反。

【问题讨论】:

    标签: common-lisp


    【解决方案1】:

    这可能有点令人困惑,但 BOUNDP 的规范确实这么说:

    函数bound[原文如此(应该是boundp)]只判断一个符号在全局环境中是否有值; 任何词法绑定都会被忽略

    所以它只通知你一个给定的符号是否绑定在全局环境中,如果变量的值单元格设置为一个值,就会发生这种情况(参见SYMBOL-VALUE), 或者变量被声明为 special 并且之前被let 形式绑定。第二种情况主要发生在使用 defvardefparameter 声明的变量上,但也适用于您声明为特殊的任何变量:

    (let ((%my-var% 0))
      (declare (special %my-var%))
      ...)
    

    请注意,每次您想使用 %my-var% 时都需要使用该声明,除非您在全局范围内声明它。

    (defun use-my-var (input)
      (declare (special %my-var%))
      (print `(:my-var ,%my-var% :input ,input)))
    

    当您编写use-my-var 函数时,您通常可以毫无问题地识别input 已绑定,实际上如果不是这种情况,编译器会警告您。对于词法作用域,(boundp x) 将编译为一个常量值,T 或 NIL。检查符号的symbol-value 是全局绑定还是动态绑定更有趣。

    这里,由于%my-var%是一个特殊的变量,它可以在不同的调用上下文中绑定或不绑定:

    (let ((%my-var% 0))
      (declare (special %my-var%))
      (use-my-var 1))
    => (:my-var 0 :input 1)
    
    (use-my-var 0)
    ;; ERROR: The variable %MY-VAR% is unbound.
    

    【讨论】:

      【解决方案2】:

      boundp 用于确定符号是否绑定在 global 环境中。请注意HyperSpec 中的以下两个示例:

      (let ((x 2)) (boundp 'x)) ;=>  false  
      (let ((x 2)) (declare (special x)) (boundp 'x)) ;=>  true
      

      页面底部的注释说:

      函数bound只判断一个符号在全局环境中是否有值;任何词法绑定都会被忽略。

      注释中出现bound 而不是boundp 似乎是一个错字。无论如何,CLTL2 对此更具体一点:

      如果 symbol 命名的动态(特殊)变量有值,则

      boundp 为真;否则,它返回nil

      注意fboundp也有类似的限制;这是HyperSpec的一个例子:

      (flet ((my-function (x) x))  
        (fboundp 'my-function)) ;=>  false
      

      boundp 处理词法变量没有多大意义。来自 HyperSpec 3.1.2.1.1.1 Lexical Variables

      一个词法变量总是有一个值。没有任何运算符可以在不给它一个初始值的情况下为词法变量引入绑定,也没有任何运算符可以使词法变量解除绑定。

      也就是说,词法变量总是绑定在它们的词法环境中。但是动态变量可能bound or unbound,而这两者中的哪一个取决于提出问题的环境:

      动态变量绑定的值部分可能为空;在这种情况下,动态变量被称为没有值,或者是未绑定的。动态变量可以使用makunbound....解除绑定。

      除非和直到显式赋值,否则动态变量是未绑定的,但初始值在本规范或实现中定义的那些变量除外。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-03-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-07-02
        • 2022-01-22
        相关资源
        最近更新 更多