当向函数传递类型错误的参数时,Lisp 解释器会生成错误信息。例如,+ 函数要求其参数值为数字。我们可以做个实验,用带引号的符号 hello 代替数字传给它。将光标放在下面表达式后面并输入 C-x C-e:
(+ 2 'hello)
执行后会触发错误信息。原因是 + 尝试将 2 与 'hello 返回的值相加,但 'hello 返回的是符号 hello,并非数字。只有数字可以相加,因此 + 无法完成加法操作。
你会打开并进入 *Backtrace* 缓冲区,内容如下:
---------- Buffer: *Backtrace* ----------
Debugger entered--Lisp error:
(wrong-type-argument number-or-marker-p hello)
+(2 hello)
eval((+ 2 'hello) nil)
elisp--eval-last-sexp(t)
eval-last-sexp(nil)
funcall-interactively(eval-print-last-sexp nil)
call-interactively(eval-print-last-sexp nil nil)
command-execute(eval-print-last-sexp)
---------- Buffer: *Backtrace* ----------
和往常一样,这条错误信息是有帮助的,学会解读后就能理解其含义。4
错误信息的第一部分很直观:‘wrong type argument’(参数类型错误)。接下来是专业术语 ‘number-or-marker-p’,它用于说明 + 期望接收何种类型的参数。
符号 number-or-marker-p 表示 Lisp 解释器正在判断传入的信息(参数值)是否为数字或标记(一种代表缓冲区位置的特殊对象)。它用于检测 + 是否接收到可相加的数字,同时也检测参数是否为标记——这是 Emacs Lisp 的特有类型。(在 Emacs 中,缓冲区中的位置会以标记形式记录。使用 C-@ 或 C-SPC 命令设置标记时,其位置会以标记保存。标记可视为一个数字,即该位置距缓冲区开头的字符数。)在 Emacs Lisp 中,+ 可将标记位置的数值当作普通数字相加。
number-or-marker-p 末尾的 ‘p’ 源自早期 Lisp 编程惯例。‘p’ 代表 谓词(predicate)。在早期 Lisp 研究者的术语中,谓词指用于判断某一属性是否成立的函数。因此 ‘p’ 表明 number-or-marker-p 是一个判断参数是否为数字或标记的函数。其他以 ‘p’ 结尾的 Lisp 符号包括 zerop(判断参数是否为 0)和 listp(判断参数是否为列表)。
最后,错误信息的末尾是符号 hello,即传给 + 的参数值。如果加法运算传入了正确类型的对象,该值应为数字(如 37)而非 hello 这样的符号,自然也不会出现错误。