17.1 debug

假设你已经编写了一个函数定义,该函数旨在返回给定数字范围内数字的总和。 (这是先前讨论的 triangle 函数。See 具有递减计数器的示例, 进行讨论。)

然而,你的函数定义中存在一个错误。你误将 ‘1=’ 写成了 ‘1-’。以下是有问题的定义:

(defun triangle-bugged (number)
  "返回1到NUMBER(含)的数字之和。"
  (let ((total 0))
    (while (> number 0)
      (setq total (+ total number))
      (setq number (1= number)))      ; 这里有错误。
    total))

如果你在Info中阅读这个,可以以正常方式评估这个定义。你将在回显区域看到 triangle-bugged

现在用参数4评估 triangle-bugged 函数:

(triangle-bugged 4)

这将创建并进入一个 *Backtrace* 缓冲区,显示:

---------- 缓冲区: *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)
---------- 缓冲区: *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=)

你可以纠正错误,重新评估函数定义,然后再次运行你的测试。