There are two debuggers available with MIT/GNU Scheme. One of them runs under Edwin, and is described in that section of this document (see The Edwin Debugger). The other is command-line oriented, does not require Edwin, and is described here.
The command-line debugger, called
debug, is the tool you
should use when Scheme signals an error and you want to find out what
caused the error. When Scheme signals an error, it records all the
information necessary to continue running the Scheme program that caused
the error; the debugger provides you with the means to inspect this
information. For this reason, the debugger is sometimes called a
Here is the transcript of a typical Scheme session, showing a user
evaluating the expression ‘(fib 10)’, Scheme responding with an
unbound variable error for the variable
fob, and the user
starting the debugger:
1 ]=> (fib 10) ;Unbound variable: fob ;To continue, call RESTART with an option number: ; (RESTART 3) => Specify a value to use instead of fob. ; (RESTART 2) => Define fob to a given value. ; (RESTART 1) => Return to read-eval-print level 1. 2 error> (debug) There are 6 subproblems on the stack. Subproblem level: 0 (this is the lowest subproblem level) Expression (from stack): fob Environment created by the procedure: FIB applied to: (10) The execution history for this subproblem contains 1 reduction. You are now in the debugger. Type q to quit, ? for commands. 3 debug>
This tells us that the error occurred while trying to evaluate the expression ‘fob’ while running ‘(fib 10)’. It also tells us this is subproblem level 0, the first of 6 subproblems that are available for us to examine. The expression shown is marked ‘(from stack)’, which tells us that this expression was reconstructed from the interpreter’s internal data structures. Another source of information is the execution history, which keeps a record of expressions evaluated by the interpreter. The debugger informs us that the execution history has recorded some information for this subproblem, specifically a description of one reduction.
What follows is a description of the commands available in the debugger. To understand how the debugger works, you need to understand that the debugger has an implicit state that is examined and modified by commands. The state consists of three pieces of information: a subproblem, a reduction, and an environment frame. Each of these parts of the implicit state is said to be selected; thus one refers to the selected subproblem, and so forth. The debugger provides commands that examine the selected state, and allow you to select different states.
Here are the debugger commands. Each of these commands consists of a single letter, which is to be typed by itself at the debugger prompt. It is not necessary to type RET after these commands.
The debugger has several commands for traversing the structure of the
continuation. It is useful to think of the continuation as a
two-dimensional structure: a backbone consisting of subproblems, and
associated ribs consisting of reductions. The bottom of the backbone is
the most recent point in time; that is where the debugger is positioned
when it starts. Each subproblem is numbered, with
the most recent time point, and ascending integers numbering older time
points. The u command moves up to older points in time, and the
d command moves down to newer points in time. The g
command allows you to select a subproblem by number, and the h
command will show you a brief summary of all of the subproblems.
If the subproblem description says that ‘The execution history for this subproblem contains N reductions’, then there is a “rib” of reductions for this subproblem. You can see a summary of the reductions for this subproblem using the r command. You can move to the next reduction using the b command; this moves you to the next older reduction. The f command moves in the opposite direction, to newer reductions. If you are at the oldest reduction for a given subproblem and use the b command, you will move to the next older subproblem. Likewise, if you are at the newest reduction and use f, you’ll move to the next newer subproblem.
The following commands will show you additional information about the
currently selected subproblem or reduction. The t command will
reprint the standard description (in case it has scrolled off the
screen). The l command will pretty-print (using
Nearly all subproblems and all reductions have associated environments.
Selecting a subproblem or reduction also selects the associated
environment. However, environments are structured as a sequence of
frames, where each frame corresponds to a block of environment
variables, as bound by
let. These frames
collectively represent the block structure of a given environment.
Once an environment frame is selected by the debugger, it is possible to select the parent frame of that frame (in other words, the enclosing block) using the p command. You can subsequently return to the original child frame using the s command. The s command works because the p command keeps track of the frames that you step through as you move up the environment hierarchy; the s command just retraces the path of saved frames. Note that selecting a frame using p or s will print the bindings of the newly selected frame.
The following commands allow you to examine the contents of the selected
frame. The c command prints the bindings of the current frame.
The a command prints the bindings of the current frame and each of
its ancestor frames. The e command enters a read-eval-print loop
in the selected environment frame; expressions typed at that
REPL will be evaluated in the selected environment. To exit
the REPL and return to the debugger, evaluate
‘(abort->previous)’ or use
restart. The v command
prompts for a single expression and evaluates it in the selected
environment. The w command invokes the environment inspector
where); quitting the environment inspector returns to the
debugger. Finally, the o command pretty-prints the procedure that
was called to create the selected environment frame.
There are three commands that can be used to restart the computation that you are examining. The first is the k command, which shows the currently active restarts, prompts you to select one, and passes control to the it. It is very similar to evaluating ‘(restart)’.
The other two commands allow you to invoke internal continuations. This should not be done lightly; invoking an internal continuation can violate assumptions that the programmer made and cause unexpected results. Each of these commands works in the same way: it prompts you for an expression, which is evaluated in the selected environment to produce a value. The appropriate internal continuation is then invoked with that value as its sole argument. The two commands differ only in which internal continuation is to be invoked.
The j command invokes the continuation associated with the selected subproblem. What this means is as follows: when the description of a subproblem is printed, it consists of two parts, and “expression” and a “subproblem being executed”. The latter is usually marked in the former by the specific character sequence ‘###’. The internal continuation of the subproblem is the code that is waiting for the “subproblem being executed” to return a value. So, in effect, you are telling the program what the “subproblem being executed” will evaluate to, and bypassing further execution of that code.
The z command is slightly different. It instead invokes the continuation that is waiting for the outer “expression” to finish. In other words, it is the same as invoking the j command in the next frame up. So you can think of this as an abbreviation for the u command followed by the j command.
The m, x, and y commands are for Scheme wizards. They are used to debug the MIT/GNU Scheme implementation. If you want to find out what they do, read the source code.
The i command will reprint the error message for the error that was in effect immediately before the debugger started. The q command quits the debugger, returning to the caller. And the ? command prints a brief summary of the debugger’s commands.