17.1 debug

假设你写了一个函数,用于计算从 1 到指定数字的累加和。(即之前讲过的 triangle 函数。See Example with Decrementing Counter。)

但函数定义存在错误:你把 ‘1-’ 误写成了 ‘1=’。错误定义如下:

(defun triangle-bugged (number)
  "返回数字 1 到 NUMBER 的累加和。"
  (let ((total 0))
    (while (> number 0)
      (setq total (+ total number))
      (setq number (1= number)))      ; Error here.
    total))

如果你在 Info 中阅读本文,可以按常规方式执行该定义,回显区会出现 triangle-bugged

现在以 4 为参数执行 triangle-bugged 函数:

(triangle-bugged 4)

会创建并进入 *Backtrace* 缓冲区,内容如下:

---------- Buffer: *Backtrace* ----------
Debugger entered--Lisp error: (void-function 1=)
  (1= number)
  (setq number (1= number))
  (while (> number 0) (setq total (+ total number))
        (setq number (1= number)))
  (let ((total 0)) (while (> number 0) (setq total ...)
    (setq number ...)) total)
  triangle-bugged(4)
  eval((triangle-bugged 4) nil)
  eval-expression((triangle-bugged 4) nil nil 127)
  funcall-interactively(eval-expression (triangle-bugged 4) nil nil 127)
  call-interactively(eval-expression nil nil)
  command-execute(eval-expression)
---------- Buffer: *Backtrace* ----------

(我对格式做了轻微调整;调试器不会自动折行。和往常一样,在 *Backtrace* 缓冲区按 q 可退出调试器。)

对于如此简单的错误,Lisp 错误行本身就足以告诉你如何修复:函数 1= 未定义。

但如果你不确定具体问题,可以阅读完整回溯信息。

Emacs 会自动启动调试器并进入 *Backtrace* 缓冲区。你也可以按下面说明手动启动调试器。

*Backtrace* 缓冲区应从下往上阅读,它记录了导致错误的 Emacs 执行步骤。Emacs 交互式调用了 C-x C-eeval-last-sexp),进而执行了 triangle-bugged 表达式。往上每一行都记录了 Lisp 解释器下一步执行的内容。

缓冲区顶部第三行是:

(setq number (1= number))

Emacs 尝试执行该表达式,为此需要先执行顶部第二行的内层表达式:

(1= number)

错误就发生在这里,正如第一行所示:

Debugger entered--Lisp error: (void-function 1=)

你可以修正错误,重新执行函数定义,再进行测试。