如何像这样介入SBCL?
How to step in SBCL like this?
我是 Common Lisp 的新手,我正在使用 SBCL、Slime 和 Emacs 来学习。
在阅读Common Lisp: A Gentle Introduction to Symbolic Computation一书时,作者提到了有助于调试并能够做到这一点的STEP工具:
斜体文字是来自作者还是工具本身,还不是100%清楚。可能,只是作者的评论。
然而,即使我不考虑斜体,我无法生成这样的描述信息。
如果我只使用 SBCL 的 REPL,我得到:
* (step (if (oddp 5) 'yes 'no))
YES
如果我在启用 Slime 的情况下在 Emacs 中使用 REPL,我得到:
CL-USER> (step (if (oddp 5) 'yes 'no))
YES
作者说:
Each implementation of Common Lisp provides its own version of this
tool; only the name has been standardized.
如果我在 Emacs/Slime 中用一个函数尝试同样的事情,我会得到更多信息:
(defun my-abs (x)
(cond ((> x 0) x)
((< x 0) (- x))
(t 0)))
在 REPL 中使用上面的定义和下面的命令:
CL-USER> (step (my-abs 10))
我得到:
Evaluating call:
(MY-ABS 10)
With arguments:
10
[Condition of type STEP-FORM-CONDITION]
Restarts:
0: [STEP-CONTINUE] Resume normal execution
1: [STEP-OUT] Resume stepping after returning from this function
2: [STEP-NEXT] Step over call
3: [STEP-INTO] Step into call
4: [RETRY] Retry SLIME REPL evaluation request.
5: [*ABORT] Return to SLIME's top level.
--more--
Backtrace:
0: ((LAMBDA ()))
1: (SB-INT:SIMPLE-EVAL-IN-LEXENV (LET ((SB-IMPL::*STEP-OUT* :MAYBE)) (UNWIND-PROTECT (SB-IMPL::WITH-STEPPING-ENABLED #))) #S(SB-KERNEL:LEXENV :FUNS NIL :VARS NIL :BLOCKS NIL :TAGS NIL :TYPE-RESTRICTIONS ..
2: (SB-INT:SIMPLE-EVAL-IN-LEXENV (STEP (MY-ABS 10)) #<NULL-LEXENV>)
3: (EVAL (STEP (MY-ABS 10)))
--more--
不幸的是,none 这些选项似乎给了我想要的东西(这可能是我这边的解释错误)。
我想看类似的内容:
SLIME 似乎是一个彻底的工具。我可能遗漏了什么。
有没有办法使用 SLIME 或 SBCL 生成书中描述的相同输出?
正如上面有人建议的那样,SBCL 默认情况下确实进行了很多优化,默认情况下也会编译。这是我创建示例所做的工作:
- 我先给运行ning
的“建议优化”补了个“不好的值”
(declaim (optimize (debug 3) (space 0) (speed 0)))
- 然后,我用 定义了一个函数,而不是
if
条件 ,因为这种东西总是内联的,不幸的是(虽然你可以尝试 (declaim (notinline ...))
,我没有。一种方法是创建一个 调用另一个函数的函数,例如:
(defun foo () "hey!")
(defun bar () (foo))
- 现在,当我 运行
(step (bar))
时,我看到了您在上面的问题中共享的调试器窗格,如果我现在 select 选项 #3,step into,我得到了相同的窗格,但现在正如所希望的那样,专注于对 foo
. 的调用
祝你好运!
一些参考资料:
- 关于“单步执行”的 SBCL 手册:http://www.sbcl.org/manual/#Single-Stepping
- 关于“调试器策略控制”的 SBCL 手册:http://www.sbcl.org/manual/#Debugger-Policy-Control
看来作者使用的是 LispWorks 的步进器。
使用 LispWorks
这是我的步进会话,使用 :s
步进当前表单及其所有子表单。
CL-USER 5 > (step (my-abs -5))
(MY-ABS -5) -> :s
-5 -> :s
-5
(COND ((> X 0) X) ((< X 0) (- X)) (T 0)) <=> (IF (> X 0) (PROGN X) (IF (< X 0) (- X) (PROGN 0)))
(IF (> X 0) (PROGN X) (IF (< X 0) (- X) (PROGN 0))) -> :s
(> X 0) -> :s
X -> :s
-5
0 -> :s
0
NIL
(IF (< X 0) (- X) (PROGN 0)) -> :s
(< X 0) -> :s
X -> :s
-5
0 -> :s
0
T
(- X) -> :s
X -> :s
-5
5
5
5
5
5
正在提供帮助 :?
:
:?
:s Step this form and all of its subforms (optional +ve integer arg)
:st Step this form without stepping its subforms
:si Step this form without stepping its arguments if it is a function call
:su Step up out of this form without stepping its subforms
:sr Return a value to use for this form
:sq Quit from the current stepper level
:bug-form <subject> &key <filename>
Print out a bug report form, optionally to a file.
:get <variable> <command identifier>
Get a previous command (found by its number or a symbol/subform within it) and put it in a variable.
:help Produce this list.
:his &optional <n1> <n2>
List the command history, optionally the last n1 or range n1 to n2.
:redo &optional <command identifier>
Redo a previous command, found by its number or a symbol/subform within it.
:use <new> <old> &optional <command identifier>
Do variant of a previous command, replacing old symbol/subform with new symbol/subform.
对于编译后的代码,它还有一个可视化步进器,您可以在其中按红色按钮设置断点,查看中间变量的变化等。它看起来像这样:
LispWorks 是专有实现,IDE 有免费但受限的版本。我刚刚写了 a review 应该合并到 Cookbook 上。
跟踪和打印
你知道trace
吗? printv,一个外部图书馆,是类固醇的痕迹。它们类似于您欣赏的输出。
(defun factorial (n)
(if (plusp n)
(* n (factorial (1- n)))
1))
(trace factorial)
(factorial 2)
0: (FACTORIAL 3)
1: (FACTORIAL 2)
2: (FACTORIAL 1)
3: (FACTORIAL 0)
3: FACTORIAL returned 1
2: FACTORIAL returned 1
1: FACTORIAL returned 2
0: FACTORIAL returned 6
6
(untrace factorial)
printv
打印代码和返回值。
(printv:printv
(+ 2 3)
*print-case*
*package*
'symbol
(let* ((x 0) (y (1+ x)) (z (1+ y)))
(values x y z)))
;;; (+ 2 3) => 5
;;; *PRINT-CASE* => :UPCASE
;;; *PACKAGE* => #<PACKAGE "ISSR-TEST">
;;; 'SYMBOL => SYMBOL
;;; (LET* ((X 0) (Y (1+ X)) (Z (1+ Y)))
(VALUES X Y Z)) =>
[ [X=0] [Y=1] [Z=2] ]
;;; => 0, 1, 2
我是 Common Lisp 的新手,我正在使用 SBCL、Slime 和 Emacs 来学习。
在阅读Common Lisp: A Gentle Introduction to Symbolic Computation一书时,作者提到了有助于调试并能够做到这一点的STEP工具:
斜体文字是来自作者还是工具本身,还不是100%清楚。可能,只是作者的评论。
然而,即使我不考虑斜体,我无法生成这样的描述信息。
如果我只使用 SBCL 的 REPL,我得到:
* (step (if (oddp 5) 'yes 'no))
YES
如果我在启用 Slime 的情况下在 Emacs 中使用 REPL,我得到:
CL-USER> (step (if (oddp 5) 'yes 'no))
YES
作者说:
Each implementation of Common Lisp provides its own version of this tool; only the name has been standardized.
如果我在 Emacs/Slime 中用一个函数尝试同样的事情,我会得到更多信息:
(defun my-abs (x)
(cond ((> x 0) x)
((< x 0) (- x))
(t 0)))
在 REPL 中使用上面的定义和下面的命令:
CL-USER> (step (my-abs 10))
我得到:
Evaluating call:
(MY-ABS 10)
With arguments:
10
[Condition of type STEP-FORM-CONDITION]
Restarts:
0: [STEP-CONTINUE] Resume normal execution
1: [STEP-OUT] Resume stepping after returning from this function
2: [STEP-NEXT] Step over call
3: [STEP-INTO] Step into call
4: [RETRY] Retry SLIME REPL evaluation request.
5: [*ABORT] Return to SLIME's top level.
--more--
Backtrace:
0: ((LAMBDA ()))
1: (SB-INT:SIMPLE-EVAL-IN-LEXENV (LET ((SB-IMPL::*STEP-OUT* :MAYBE)) (UNWIND-PROTECT (SB-IMPL::WITH-STEPPING-ENABLED #))) #S(SB-KERNEL:LEXENV :FUNS NIL :VARS NIL :BLOCKS NIL :TAGS NIL :TYPE-RESTRICTIONS ..
2: (SB-INT:SIMPLE-EVAL-IN-LEXENV (STEP (MY-ABS 10)) #<NULL-LEXENV>)
3: (EVAL (STEP (MY-ABS 10)))
--more--
不幸的是,none 这些选项似乎给了我想要的东西(这可能是我这边的解释错误)。
我想看类似的内容:
SLIME 似乎是一个彻底的工具。我可能遗漏了什么。
有没有办法使用 SLIME 或 SBCL 生成书中描述的相同输出?
正如上面有人建议的那样,SBCL 默认情况下确实进行了很多优化,默认情况下也会编译。这是我创建示例所做的工作:
- 我先给运行ning 的“建议优化”补了个“不好的值”
(declaim (optimize (debug 3) (space 0) (speed 0)))
- 然后,我用 定义了一个函数,而不是
if
条件 ,因为这种东西总是内联的,不幸的是(虽然你可以尝试(declaim (notinline ...))
,我没有。一种方法是创建一个 调用另一个函数的函数,例如:
(defun foo () "hey!")
(defun bar () (foo))
- 现在,当我 运行
(step (bar))
时,我看到了您在上面的问题中共享的调试器窗格,如果我现在 select 选项 #3,step into,我得到了相同的窗格,但现在正如所希望的那样,专注于对foo
. 的调用
祝你好运!
一些参考资料:
- 关于“单步执行”的 SBCL 手册:http://www.sbcl.org/manual/#Single-Stepping
- 关于“调试器策略控制”的 SBCL 手册:http://www.sbcl.org/manual/#Debugger-Policy-Control
看来作者使用的是 LispWorks 的步进器。
使用 LispWorks
这是我的步进会话,使用 :s
步进当前表单及其所有子表单。
CL-USER 5 > (step (my-abs -5))
(MY-ABS -5) -> :s
-5 -> :s
-5
(COND ((> X 0) X) ((< X 0) (- X)) (T 0)) <=> (IF (> X 0) (PROGN X) (IF (< X 0) (- X) (PROGN 0)))
(IF (> X 0) (PROGN X) (IF (< X 0) (- X) (PROGN 0))) -> :s
(> X 0) -> :s
X -> :s
-5
0 -> :s
0
NIL
(IF (< X 0) (- X) (PROGN 0)) -> :s
(< X 0) -> :s
X -> :s
-5
0 -> :s
0
T
(- X) -> :s
X -> :s
-5
5
5
5
5
5
正在提供帮助 :?
:
:?
:s Step this form and all of its subforms (optional +ve integer arg)
:st Step this form without stepping its subforms
:si Step this form without stepping its arguments if it is a function call
:su Step up out of this form without stepping its subforms
:sr Return a value to use for this form
:sq Quit from the current stepper level
:bug-form <subject> &key <filename>
Print out a bug report form, optionally to a file.
:get <variable> <command identifier>
Get a previous command (found by its number or a symbol/subform within it) and put it in a variable.
:help Produce this list.
:his &optional <n1> <n2>
List the command history, optionally the last n1 or range n1 to n2.
:redo &optional <command identifier>
Redo a previous command, found by its number or a symbol/subform within it.
:use <new> <old> &optional <command identifier>
Do variant of a previous command, replacing old symbol/subform with new symbol/subform.
对于编译后的代码,它还有一个可视化步进器,您可以在其中按红色按钮设置断点,查看中间变量的变化等。它看起来像这样:
LispWorks 是专有实现,IDE 有免费但受限的版本。我刚刚写了 a review 应该合并到 Cookbook 上。
跟踪和打印
你知道trace
吗? printv,一个外部图书馆,是类固醇的痕迹。它们类似于您欣赏的输出。
(defun factorial (n)
(if (plusp n)
(* n (factorial (1- n)))
1))
(trace factorial)
(factorial 2)
0: (FACTORIAL 3)
1: (FACTORIAL 2)
2: (FACTORIAL 1)
3: (FACTORIAL 0)
3: FACTORIAL returned 1
2: FACTORIAL returned 1
1: FACTORIAL returned 2
0: FACTORIAL returned 6
6
(untrace factorial)
printv
打印代码和返回值。
(printv:printv
(+ 2 3)
*print-case*
*package*
'symbol
(let* ((x 0) (y (1+ x)) (z (1+ y)))
(values x y z)))
;;; (+ 2 3) => 5
;;; *PRINT-CASE* => :UPCASE
;;; *PACKAGE* => #<PACKAGE "ISSR-TEST">
;;; 'SYMBOL => SYMBOL
;;; (LET* ((X 0) (Y (1+ X)) (Z (1+ Y)))
(VALUES X Y Z)) =>
[ [X=0] [Y=1] [Z=2] ]
;;; => 0, 1, 2