【问题标题】:Is it valid to use "setf" to create special variables?使用“setf”创建特殊变量是否有效?
【发布时间】:2021-09-24 23:40:09
【问题描述】:

看来我可以使用setf 来创建特殊变量。例如,如果我启动 REPL 并输入(setf x 123),则会创建一个特殊变量x。 CLISP 和 ECL 没有错误。 SBCL 发出警告 (undefined variable: COMMON-LISP-USER::X),但无论如何都会创建特殊变量。 setf 是创建特殊变量的有效方法吗?

【问题讨论】:

  • 你怎么知道它创建了一个特殊的变量?
  • 在CLISP中,(describe 'a)表示'a是否特殊。

标签: common-lisp


【解决方案1】:

使用setf 创建新变量无效。 HyperSpec 非常清楚setfonly intended to update existing variables

setfplace 的值更改为newvalue

(setf place newvalue) 扩展为一个更新表单,将评估newvalue 的结果存储到place 引用的位置。

setf 用于更新地点。没有指定尝试使用 setf 更新不存在的地点的值的行为。

在讨论分配的部分,CLTL2 说了更多:

这种更改不同于建立新的绑定。用于建立新的变量绑定的构造在第 7.5 节中描述。​​

虽然这似乎可行,但您不能依赖它。它通常在 REPL 中有效,如果您想在 REPL 中使用setf 这种方式也可以,但您不应该在任何程序中这样做。

【讨论】:

    【解决方案2】:

    其实有点棘手。

    这是 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 形式返回1 还是2 在Common Lisp 语言标准中未指定。不过,大多数实现都会返回 1

    下一步:

    CL-USER 65 > (let ((foo 2))
                   (declare (special foo))
                   (bar))
    2
    

    上面我们看到foo里面bar的使用其实是在let里面使用foo的动态绑定。

    基本上未指定设置未定义变量的确切效果。可以假设变量是否特殊。大多数实现都喜欢NOT 声明特殊,这样变量的进一步使用必须是特殊的。

    但变量是否特殊,以及使用它的确切效果,实际上在 Common Lisp 语言标准中是未定义的。

    大多数实现都同意

    1. setf 设置一个未定义的变量只会改变符号的符号值

    2. 设置和检索变量是假设一个特殊变量

    3. 通过let(或类似方法)重新绑定变量不会创建特殊变量

    4. 编译器(如果使用)将警告未定义变量和/或假设特殊变量。

    默认不同意的一个实现是 CMUCL -> setf 也将变量声明为特殊的,类似于 defparameter 所做的。

    有关一般样式规则,请参阅ad absurdum 答案的最后一段。

    【讨论】:

    • 我听不懂你的回答。对我来说,您的代码 sn-p 表明 foos 都是词法的。不是动态的/特殊的。
    • @WillNess 抱歉,我还没有完成编辑。请再检查一遍,是不是更清楚了?
    • 这仍然有点难以理解。也许要涵盖的材料太多,而且本质上太混乱了。
    • 这是一个很好的例子。
    • 所以在第一个 let 中,全局 foo 的行为就像是词法,不受局部词法 foo 的影响(与全局词法无关)。在第二个let 中,使用special 声明,相同的全局foo 表现得好像它很特别!这太奇怪了。 (我确认在 CLISP 中也发生了同样的行为)。
    猜你喜欢
    • 2011-10-12
    • 2020-03-15
    • 2016-05-08
    • 1970-01-01
    • 1970-01-01
    • 2014-05-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多