THE LISP IDE
I've already introduced some essential functions and keybindings for coding Lisp in Emacs. Now that you have a basic knowledge of both Lisp and Emacs commands for coding in Lisp, it will be useful to gain a deeper knowledge of the Lisp IDE in Emacs.
Common Lisp includes debugging functions like trace, break, etc. that allow
you to do debugging directly in the REPL.
However, there are Common Lisp IDEs that help improve the ergonomics of using
the debugger. One of those IDEs is Sly, which was installed when we configured
the init.el file to include common-lisp language support.
TRACING
Beyond simple navigation within the debugger is actual debugging methods and tools.
Tracing is a debugging method that shows a form as it is called and then what it returns. Tracing is typically used for recursive functions.
Let's say you have this function:
(defun factorial (n)
"Compute factorial using linear recursion."
(if (= n 1)
1
(* n (factorial (- n 1)))))
You can run trace on a function in Emacs like this:
(trace factorial)
…or by highlighting a function name symbol and typing C-c M-t for
sly-fancy-trace.
If you use fancy tracing on factorial above, you will get output like this in
the REPL:
0: (FACTORIAL 5)
1: (FACTORIAL 4)
2: (FACTORIAL 3)
3: (FACTORIAL 2)
4: (FACTORIAL 1)
4: FACTORIAL returned 1
3: FACTORIAL returned 2
2: FACTORIAL returned 6
1: FACTORIAL returned 24
0: FACTORIAL returned 120
Alternatively, you can trace using sly-trace-dialog-toggle-trace via C-c C-t
or SPC m T T. The difference is that fancy trace will show the trace in the
REPL, whereas the trace dialog toggle requires you to open the trace dialog with
C-c T.
If you use the trace dialog, you get output like this:
0 - factorial
> 5 (3 bits, #x5, #o5, #b101)< 120 (7 bits, #x78, #o170, #b1111000)1 `-- factorial
> 4 (3 bits, #x4, #o4, #b100)< 24 (5 bits, #x18, #o30, #b11000)2 `-- factorial
> 3 (2 bits, #x3, #o3, #b11)< 6 (3 bits, #x6, #o6, #b110)3 `-- factorial
> 2 (2 bits, #x2, #o2, #b10)< 2 (2 bits, #x2, #o2, #b10)4 `-- factorial
> 1 (1 bit, #x1, #o1, #b1)
< 1 (1 bit, #x1, #o1, #b1)
You can untrace the function when you're done either with the Lisp function or
by using the same commands above in Emacs.
STICKERS
Where Sly's debugging capabilities really shine is with stickers. Stickers are
basically a replacement for print and break functions
Let's say we have the following code:
(defun do-some-math (num)
(/ (+ num (* num num num) (- num 10 num)) 7))
(do-some-math 9)
And you're thinking, "Hmm, I wonder what the result of that addition was?"
You could wrap it in print. Or you could use a sticker. Highlight the opening
parenthesis of the addition form then use sly-stickers-dwim via C-c C-s C-s
or SPC m s s to place a sticker on it. After placing the sticker, you need to
recompile the function (C-c C-c) to "arm" the sticker.
With the sticker armed, when you run the function, the return value of the form
you placed the sticker on will be recorded. You can view the recording with
sly-stickers-replay using C-c C-s C-r or SPC m s r.
You can also configure Sly to break when computation reaches the sticker using
sly-stickers-toggle-break-on-stickers via SPC m s b. During computation,
when a sticker is reached, the debugger will open with a message like this:
#<JUST BEFORE #<STICKER id=145 hit-count=1>>
[Condition of type SLYNK-STICKERS::JUST-BEFORE-STICKER]
The sticker will also flash in the source code file window. Useful for when you have multiple stickers and need to know which one you're looking at.
If you choose the CONTINUE restart (either via c or 0 or navigating to
[CONTINUE] and typing Enter) or you use sly-db-step via s in the
debugger window, you will see a message like this:
#<RIGHT-AFTER #<STICKER id=255 hit-count=2> (recorded #<RECORDING 1 values>)>
[Condition of type SLYNK-STICKERS::RIGHT-AFTER-STICKER]
…and the return value of the form where the sticker is placed.
If you are having trouble tracking down the exact location of your error, you
can perform a comprehensive sweep using sly-stepper with C-c C-s P. That
will apply stickers to every form inside a function. After running
sly-stepper, compile the function to arm the stickers.
sly-stickers-replay is especially useful because, like with the breaking
option, it will open the source code file and flash the exact sticker whose
value it's displaying. You can also navigate to the next sticker with n, or
the previous one with p. Every time you move forward or backward in the
replay, the stickers will flash. This makes a bit easier to follow the control
flow of the code.

