【问题标题】:SBCL error: "No debug variables for current frame: using EVAL instead of EVAL-IN-FRAME."SBCL 错误:“当前帧没有调试变量:使用 EVAL 而不是 EVAL-IN-FRAME。”
【发布时间】:2018-05-17 20:28:36
【问题描述】:

我是 Lisp 的新手,在终端使用 SBCL 1.2.11。

谁能帮我弄清楚我应该从哪里开始寻找摆脱上述错误?我认为这导致我出现以下错误:

(setf x (list 'a 'b 'c)) 
; No debug variables for current frame: using EVAL instead of EVAL-IN-FRAME.
; (SETF X (LIST 'A 'B 'C)) ; ==> ; (SETQ X (LIST 'A 'B 'C)) 
; ; caught WARNING: ; undefined variable: X ; ; compilation unit finished 
; Undefined variable: ; X ; caught 1 WARNING condition (A B C)

我不应该看到 cmets,对吗? 非常感谢!

【问题讨论】:

  • 要记住的一点:变量不是由 SETF 定义的。 SETF 设置一个现有变量。通过 LET、DEFVAR、DEFPARAMETER、通过 DEFUN / DEFMETHOD / FLET /LABELS... 中的 arglists 定义变量。
  • 为了澄清上述评论,您应该尝试以下操作之一:(defvar x) 在您的 SETF 之前(如果您在顶层有它。请注意,这对于全球来说是一个糟糕的名称多变的); (let ((x (list 'a 'b 'c))) ... do things with x ...),或(defun foo (x) ... do things with x ...),然后调用FOO

标签: terminal lisp common-lisp sbcl


【解决方案1】:

[我添加了这个答案,因为似乎没有其他答案,希望它可能会有所帮助。]

这里有两个问题:

  • 您正在做一些不合法的 Common Lisp 的事情(但通常这样做);
  • SBCL 以一种略显缺乏信息的方式对此发出警告。

有一个重要的术语在 Lisp 中很常见,但我认为在其他语言中不太常见。该术语是binding:绑定是,松散的,某种名称和值之间的关联。与绑定相关的是 范围 -- 在哪里可见 -- 和 extent, when可见的。 (我不打算谈论范围和程度,因为这是一个很大的主题,这个答案已经太长了。)几乎所有的编程语言都有这三个概念,但他们经常以令人困惑的方式称它们不同的东西。

通常称为变量的东西是与值相关联的名称:实际上,它是一个绑定。当然,“绑定”一词源于“变量绑定”。但并不是所有的绑定都是变量——这个术语现在更通用、更精确(尽管我在这里没有给出任何精确的定义)。

处理绑定的构造有两个家族:

  • 建立绑定的结构;
  • 修改绑定的构造。

这两件事在 CL 中是不同的。 与许多编程语言一样,存在创建绑定的特殊构造,以及修改(变异)它们的其他构造。修改绑定的构造要求绑定存在以便可以修改它们。

建立绑定的构造

在 CL 中,这些内容类似于 let(let ((x 1) y) ...)xy 建立在其词法范围内可见的本地绑定(通常)。 defvar 和朋友建立全局绑定。 defun和朋友在CL中不同的命名空间(函数命名空间,相对于变量命名空间)建立全局绑定,flet/labels建立局部函数绑定。还有其他构造,特别是构造集可以以通常的 Lisp 方式有效地进行用户扩展。

修改绑定的构造

修改变量绑定的传统构造是setqsetf 是一个宏,它允许您更一般地修改绑定(以及它称为“位置”的其他事物,例如数组元素),并且用户- 可扩展的方式。所以(setf x 2)修改了x的绑定。

错误

您犯的错误是您不能只说(setf a ...),除非存在a 的现有绑定。此代码是非法的 CL:

(defun foo ()
  (setf a 1)
  ...)

相反,您需要为a 建立绑定:

(defun foo ()
  (let ((a ...))
    ...
    (setf a 1)
    ...))

嗯,在顶层也是如此:你不能只说:

> (setf x (list 'a 'b 'c))

因为*您正在尝试修改不存在的 x 绑定。

这就是 SBCL 以一种相当不具信息性(我认为)的方式告诉你的:它告诉你 x 不存在现有绑定。

解决方案和非解决方案

不幸的是,CL 并没有真正为这个问题提供很好的解决方案。 “解决”它的一种方法是这样做:

> (defvar x ...)
[...]
> (setf x (list 'a 'b 'c))

但这是一个不受欢迎的解决方案:(defvar x ...)x 变成一个全局特殊变量——一个动态范围的变量。这会以意想不到的方式改变任何 x 绑定的语义,例如在后面的函数中。这是不可取的。如果你想这样做,至少确保你的特殊变量遵循*star* 约定,这样它们是什么是显而易见的。

CL,开箱即用不提供您可能想要的,即“顶级词法变量”——您可以在顶级声明的变量绑定 不 做这件不幸的全球特殊事情。然而,Lisp 非常灵活,您可以根据需要将其添加到其中。

但这仍然是一种笨拙的解决方案:拥有会话语言的全部意义在于,当您与实现交谈时,您无需花费一生痛苦地声明所有内容:您只想能够说(setf x 1) 并完成这项工作。

而且在许多实现中它确实有效:顶级交互环境让您只说该说,就做正确的事,而当您例如编译一个文件时,您会收到一个编译时警告和如果您执行相同的操作,则会出现运行时错误(可能是警告)。然而,这种在交互环境中的轻松行为显然超出了标准。

SBCL 没有这样做,因为我认为它实际上并没有顶级交互式解释器,而是编译所有内容。所以你会收到这些警告。 SBCL 的人可能想纠正我,但我认为当您在系统上键入时忽略它们是相当安全的(但在编译文件时不是)并将 SBCL 视为其他实现。


不解决问题的方法

解决这个问题的一种方法似乎是明智的,就是不要使用特殊的构造来创建绑定:绑定是由第一个赋值创建的。例如,这就是 Python 所做的。从表面上看,这似乎是一个聪明的把戏:打字和大惊小怪。

但是这些隐式创建的绑定的范围是什么? (Python 说“整个函数,包括它在第一次赋值之前运行的部分”,这很有趣。)而且,更糟糕的是,你如何区分对外部定义的变量的赋值作用域和在内部作用域中创建绑定的相同构造:好吧,您可以使用特殊的“全局”构造来做到这一点……这实际上不起作用:Python现在也具有“非本地”构造 /em>。以及如何判断一个变量是否在编译时(甚至,实际上是在运行时)被绑定以给出良好的警告?

这个看似好主意的技巧实际上在许多情况下使事情变得更加复杂:我认为这对于快速而肮脏的脚本语言是合理的,但对于大规模系统语言来说就不那么合理了。

【讨论】:

    猜你喜欢
    • 2012-08-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-11-01
    相关资源
    最近更新 更多