为什么 Slime 的调试器不评估所选帧中的这个特定表达式?

Ped*_*ino 4 debugging common-lisp break stack-frame

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

在第 10 章结束时,作者讨论了有用的 break 函数。为了提供背景上下文,他提出了这个有问题的函数:


(defun analyze-profit (price commission-rate)
  (let* ((commission (* price commission-rate))
         (result
           (cond ((> commission 100) 'rich)
                 ((< commission 100) 'poor))))
    (format t "~&I predict you will be: ~S"
            result)
    result))

Run Code Online (Sandbox Code Playgroud)

该函数按预期工作,在 REPL 中使用以下参数调用:

> (analyze-profit 1600 0.15)
I predict you will be: RICH
RICH

> (analyze-profit 3100 0.02)
I predict you will be: POOR
POOR

Run Code Online (Sandbox Code Playgroud)

但是,当commission正好是 100时,它会显示错误的结果:

> (analyze-profit 2000 0.05)
I predict you will be: NIL
NIL
Run Code Online (Sandbox Code Playgroud)

为了调试,作者break在定义上插入了函数:


(defun analyze-profit-debugging (price commission-rate)
  (let* ((commission (* price commission-rate))
         (result
           (cond ((> commission 100) 'rich)
                 ((< commission 100) 'poor))))
    (break "Value of RESULT is ~S" result)
    (format t "~&I predict you will be: ~S"
            result)
    result))
Run Code Online (Sandbox Code Playgroud)

然后他在检查局部变量的值的同时检查控制堆栈

在此处输入图片说明

我知道调试器是出了名的依赖于实现。

在我的环境(emacs、slime、sbcl)中,我能够在@Vindarel 编写的这个很棒的教程之后重现类似的东西。

将点(光标)放在堆栈上0:并按下后e

Backtrace:
  0: (ANALYZE-PROFIT-DEBUGGING 2000 0.05)
  1: (SB-INT:SIMPLE-EVAL-IN-LEXENV (ANALYZE-PROFIT-DEBUGGING 2000 0.05) #<NULL-LEXENV>)
  2: (EVAL (ANALYZE-PROFIT-DEBUGGING 2000 0.05))
Run Code Online (Sandbox Code Playgroud)

我能够评估堆栈帧中的表达式。因此,我在迷你缓冲区上收到此消息:

Eval in frame (COMMON-LISP-USER)> price
=> 2000 (11 bits, #x7D0, #o3720, #b11111010000)
Run Code Online (Sandbox Code Playgroud)

和:

Eval in frame (COMMON-LISP-USER)> commission-rate
=> 0.05
Run Code Online (Sandbox Code Playgroud)

不幸的是,我无法访问local variable命名的主要问题commission

Eval in frame (COMMON-LISP-USER)> commission
Run Code Online (Sandbox Code Playgroud)

我期待:

100.0
Run Code Online (Sandbox Code Playgroud)

但我收到一条错误消息:

变量 COMMISSION 未绑定。[UNBOUND-VARIABLE 类型的条件]

我仔细检查了拼写。此外,我还尝试使用p代替e和移动光标。然而,没有任何效果。

如何检查有问题的变量的值commission

ex *_*ilo 6

如果您导航到调试器中的顶部框架并在该框架上按 Enter,您将看到commission调试器不知道它作为局部变量:

Value of RESULT is NIL
   [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 "new-repl-thread" RUNNING {1002D65C93}>)

Backtrace:
  0: (ANALYZE-PROFIT-DEBUGGING 2000 0.05)
      Locals:
        COMMISSION-RATE = 0.05
        PRICE = 2000
        RESULT = NIL
  1: (SB-INT:SIMPLE-EVAL-IN-LEXENV (ANALYZE-PROFIT-DEBUGGING 2000 0.05) #<NULL-LEXENV>)
  2: (EVAL (ANALYZE-PROFIT-DEBUGGING 2000 0.05))
 --more--
Run Code Online (Sandbox Code Playgroud)

这里的问题是编译器优化掉了一些调试信息。您可以告诉编译器declaim在文件开头或declare函数定义中包含更多调试信息:

(defun analyze-profit-debugging (price commission-rate)
  (declare (optimize (debug 3)))
  (let* ((commission (* price commission-rate))
         (result
           (cond ((> commission 100) 'rich)
                 ((< commission 100) 'poor))))
    (break "Value of RESULT is ~S" result)
    (format t "~&I predict you will be: ~S"
            result)
    result))
Run Code Online (Sandbox Code Playgroud)

给出的数字debug可以是 0、1、2 或 3;更大的数字意味着应该更加重视保留调试信息。

现在在调试器中,在顶部堆栈帧上按回车commission直接显示的值:

Backtrace:
  0: (ANALYZE-PROFIT-DEBUGGING 2000 0.05)
      Locals:
        COMMISSION = 100.0
        COMMISSION-RATE = 0.05
        PRICE = 2000
        RESULT = NIL
  1: (SB-INT:SIMPLE-EVAL-IN-LEXENV (ANALYZE-PROFIT-DEBUGGING 2000 0.05) #<NULL-LEXENV>)
  2: (EVAL (ANALYZE-PROFIT-DEBUGGING 2000 0.05))
 --more--
Run Code Online (Sandbox Code Playgroud)

并且,e在顶部堆栈帧上使用命令现在可以按您最初的预期工作:

Eval in frame (COMMON-LISP-USER)> commission
=> 100.0
Run Code Online (Sandbox Code Playgroud)