我怎样才能让 Sly 的回溯变得合理?

Cha*_*rJe 0 debugging emacs common-lisp slime

每当我遇到错误时,Sly 都会显示重新启动和回溯。我在互联网上看到有人拥有可读的回溯,这些回溯是合理的函数调用。当我进入(fun duf)repl 时,我最终会得到这样的结果:

Backtrace:
 0: ((LAMBDA ()))
 1: (SB-INT:SIMPLE-EVAL-IN-LEXENV (FUN DUF) #<NULL-LEXENV>)
 2: (EVAL (FUN DUF))
 3: ((LAMBDA NIL :IN SLYNK-MREPL::MREPL-EVAL-1))
 4: (SLYNK::CALL-WITH-RETRY-RESTART "Retry SLY mREPL evaluation request." #<CLOSURE (LAMBDA NIL :IN SLYNK-MREPL::MREPL-EVAL-1) {100308AA1B}>)
 5: ((LAMBDA NIL :IN SLYNK-MREPL::MREPL-EVAL-1))
 6: ((LAMBDA NIL :IN SLYNK::CALL-WITH-LISTENER))
 7: (SLYNK::CALL-WITH-BINDINGS ((*PACKAGE* . #<PACKAGE "COMMON-LISP-USER">) (* . 13) (** . 10) (***) (/ 13) (// 10) ...) #<CLOSURE (LAMBDA NIL :IN SLYNK::CALL-WITH-LISTENER) {100308A68B}>)
 8: (SLYNK-MREPL::MREPL-EVAL-1 #<SLYNK-MREPL::MREPL mrepl-2-2> "(fun duf)")
 9: (SLYNK-MREPL::MREPL-EVAL #<SLYNK-MREPL::MREPL mrepl-2-2> "(fun duf)")
...
Run Code Online (Sandbox Code Playgroud)

还有很多。这使我无法调试我的代码。我试过:(declaim (optimize (debug 3))),但没有区别。此外,即使调用是实际函数,输出也不会更好。我已经尝试过 gnuclisp 和 sbcl。

Sva*_*nte 5

我认为你觉得你看到的很多东西都是“垃圾”,只是因为你还不知道它是什么。

  • 在第 9 行和第 8 行中,您会看到 REPL 用于处理您的输入的函数。在这个阶段,输入是一个字符串,如您所见。
  • 在第 7 行,有一些绑定放在堆栈上,以便使用正确的包,并将*to***绑定到最后的结果(REPL 的一个方便的功能)。
  • 在第 6 行,call-with-listener可能正在确定输出应该转到 Sly。
  • 在第 5 行,这个匿名函数是包含在第 6 行参数的闭包中的函数。换句话说,是一个实现细节。
  • 在第 4 行中,retry重新启动已建立。如果您Retry在调试器中调用重新启动,则此帧将转移控制权。
  • 在第 3 行,您再次看到正在执行的函数参数。注意call-with-…命名约定。
  • 在第 2 行,您会看到您的输入已被读取,即转换为 lisp 数据结构。现在使用标准函数对其进行评估eval
  • 在第 1 行中,您会看到 SBCL 在这种情况下如何做到这一点 — 一个实现细节。
  • 在第 0 行,您会看到一些匿名函数,同样来自evals 实现。

这里没什么可看的,因为首先要做的eval是评估duf,但它失败了。

计算机不知道您正在尝试调试当前堆栈上下文的哪一部分。因此,它必须向您显示整个回溯,否则会遭受那些隐瞒他们感兴趣的信息的人的哀号。

你需要学习的是识别你感兴趣的东西从哪里开始。在这里,所有 Slynk 的东西(显然?)都在你的上下文之下,所以你真的只需要查看第一eval行之前的部分。在这种情况下,这只是第一行,这是有道理的,因为您输入的行在第一次查找时就失败了。对于 Sly 开发人员来说,那些较低的堆栈帧可能会很有趣。

当然,在更现实的场景中,有些实现比其他实现具有更清晰的回溯。这不是 Sly 可以做的事情。它的作用是让您可以选择从回溯中的任何一行跳转到相应的源文件位置(如果可用)(在 SLIME 中,它是v(视图),不知道 Sly)。您还可以做很多事情,例如检查本地绑定/变量/参数,以及调用重新启动。看一下说明书。