Maybe this is noob-ish but I'm losing my mind after this. I discovered with very much surprise that CL's stepper doesn't show the return value of the various forms. What I mean is that the debugger can inspect the frames and the REPL allows to manually inspect the variables, but for instance in a code like
(defun fact (n)
(if (<= n 0)
1
(* n (fact (- n 1)))))
(fact 5)
I cannot instruct the debugger to say "hey, I just stepped over form (<= n 0)
, which returned nil
, then I stepped on (- n 1)
, which returned value 4
". This can be done in Emacs-lisp and in Clojure (I use Emacs, but it's not the interface I'm interested in). I know there exist the form (step)
, but it is implementation-dependent and for what I could see on both SBCL and CMU it doesn't do what I mean. So my question is, can CL's debugger do this (stepping + printing value just evaluated)? If yes, is it just one implementation? Can you provide a MWE?
Thanks!
Common Lisp is a language specification, not an implementation. As such, expressions like 'CL's stepper' or 'CL's debugger' are category errors: languages do not have steppers or debuggers, implementations do. The language specification provides an interface, step
, by which such a thing might be invoked, but says
step
implements a debugging paradigm wherein the programmer is allowed to step through the evaluation of a form. The specific nature of the interaction, including which I/O streams are used and whether the stepping has lexical or dynamic scope, is implementation-defined.
Thus the answer to your question is that no, 'CL's debugger' can't do this because 'CL's debugger' does not exist.
Implementations of the language may provide more-or-less support for this. I know, for instance, that LispWorks does, for instance. I don't know whether other implementations do. CL as a language is also reflective enough that a portable stepper could probably be written: sly-stepper might be such a thing but I am not sure.
Here is an example of LW's non-IDE stepper in use:
CL-USER 7 > (step (let ((x 0)) (/ (sin x) x)))
(let ((x 0)) (/ (sin x) x)) -> :su
Error: Division-by-zero caused by / of (0.0 0.0).
1 (continue) Return a value to use.
2 Supply new arguments to use.
3 (abort) Return to debug level 1.
4 Return to stepper level 1.
5 Quit from stepper.
6 Return to debug level 0.
7 Restart top-level loop.
Type :b for backtrace or :c <option number> to proceed.
Type :bug-form "<subject>" for a bug report template or :? for other options.
CL-USER 9 : 2 > :a
(let ((x 0)) (/ (sin x) x)) -> :sr 0.0
0.0
0.0
CL-USER 8 > (step (let ((x 0)) (/ (sin x) x)))
(let ((x 0)) (/ (sin x) x)) -> :s 2
0
0
(/ (sin x) x)
(sin x) -> :si
0.0
x -> :sr 1
1
0.0
0.0
0.0
In the first interaction I let it run until it got the error, aborted from that back into the stepper, and then told the stepper to return zero. In the second I stepped through until it was about to evaluate x
and then told it the result of that was 1
causing it to return zero.
The non-IDE stepper above is documented here & the IDE stepper is here.