SBCL错误:"当前帧没有调试变量:使用EVAL而不是EVAL-IN-FRAME。"

时间:2018-05-17 20:28:37

标签: terminal lisp common-lisp sbcl

我是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)

我不应该看到评论,是吗? 非常感谢你!

1 个答案:

答案 0 :(得分:0)

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

这里有两个问题:

  • 您正在做一些不合法的Common Lisp(不过通常会这样做);
  • SBCL以一种略微没有信息的方式对此发出警告。

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

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

有两个构造系列处理绑定:

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

这两个东西在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现在有一个非本地的'构建以及。那么如何在编译时(或者甚至是在运行时)判断变量是否被绑定以提供良好的警告?

看起来好主意的伎俩实际上在许多情况下使事情变得更复杂:对于快速而肮脏的脚本语言来说它是合理的,但对于大规模系统语言而言则不太合理,我认为