如何在我的控制堆栈中解释这个堆栈帧?

Ped*_*ino 3 debugging sbcl common-lisp slime

我正在尝试通过《Common Lisp:符号计算的温和介绍》一书来学习 Common Lisp 。此外,我正在使用 SBCL、Emacs 和 Slime。

在第 8 章的结尾,作者将调试器介绍为 lisp 编程的重要工具之一。然后,为了展示它,他break在类似阶乘的函数定义中使用了命令:

(defun fact-debugging (n)
  (cond ((zerop n) (break "N is zero."))
        (t (* n (fact-debugging (- n 1))))))
Run Code Online (Sandbox Code Playgroud)

在 REPL 中调用函数后:

CL-USER> (fact-debugging 4)
Run Code Online (Sandbox Code Playgroud)

我得到了控制堆栈。. 我特别好奇回溯部分:

N is zero.
   [Condition of type SIMPLE-CONDITION]

Restarts:
 0: [CONTINUE] Return from BREAK.
 1: [RETRY] Retry SLIME REPL evaluation request.
 2: [*ABORT] Return to SLIME's top level.
 3: [ABORT] abort thread (#<THREAD "repl-thread" RUNNING {10024B9BC3}>)

Backtrace:
  0: (FACT-DEBUGGING 1)
  1: (FACT-DEBUGGING 2)
  2: (FACT-DEBUGGING 3)
  3: (FACT-DEBUGGING 4)
  4: (SB-INT:SIMPLE-EVAL-IN-LEXENV (FACT-DEBUGGING 4) #<NULL-LEXENV>)
  5: (EVAL (FACT-DEBUGGING 4))
Run Code Online (Sandbox Code Playgroud)

我可以理解除数字之外的所有堆栈帧 4: (SB-INT...

有趣的是,作者并没有收到这样的消息。他得到了一些更轻的东西:

在此处输入图片说明

因此,我想问:

1 - 为什么会发生该堆栈帧?

2 - 为什么它发生eval在 的堆栈帧之后和之前(fact-debugging 4)

3 - 它实际上是什么意思?它充满了诸如LEXENV或之类的看不见的术语#<NULL LEXENV>

ex *_*ilo 5

当您(fact-debugging 4)在 REPL 中输入表单时,将使用 评估该表单eval,因此:5: (EVAL (FACT-DEBUGGING 4))

如果您将 emacs 指向EVAL5 并按下M-.(使用 Slime),您会发现它eval正在调用eval-in-lexenv,它本身也在调用simple-eval-in-lexenv,因此:4: (SB-INT:SIMPLE-EVAL-IN-LEXENV (FACT-DEBUGGING 4) #<NULL-LEXENV>)

如果您将点移动到第 4 帧并按 ENTER,您将看到如下内容:

4: (SB-INT:SIMPLE-EVAL-IN-LEXENV (FACT-DEBUGGING 4) #<NULL-LEXENV>)
    Locals:
      SB-KERNEL:LEXENV = #<NULL-LEXENV>
      SB-IMPL::ORIGINAL-EXP = (FACT-DEBUGGING 4)
Run Code Online (Sandbox Code Playgroud)

将点移动到SB-KERNEL:LEXENV = #<NULL-LEXENV>显示并按 ENTER 显示的行:

#<SB-KERNEL:LEXENV {1003FD12E3}>
--------------------
The object is a STRUCTURE-OBJECT of type SB-KERNEL:LEXENV.
Run Code Online (Sandbox Code Playgroud)

所以,最初的调用eval是由 REPL 进行的,并且eval调用了eval-in-lexenv,它调用simple-eval-in-lexenv了一个lexenv结构。该lexenv结构只是eval应在其中运行的词汇环境的表示。您也可以移动 emacs 指向SB-KERNEL:LEXENV以查看该定义。这个定义很长,但这是开始:

;;; The LEXENV represents the lexical environment used for IR1 conversion.
;;; (This is also what shows up as an ENVIRONMENT value in macroexpansion.)
(declaim (inline internal-make-lexenv))
(defstruct (lexenv
            (:include abstract-lexenv)
;;;
;;; and so on....
;;;
Run Code Online (Sandbox Code Playgroud)

一旦eval有了词法环境,就(FACT-DEBUGGING 4)可以进行评价了。当然,所有这些细节都是特定于 SBCL 的。在这种特殊情况下,词法环境#<NULL-LEXENV>空词法环境,即全局环境。