One of the main features of a sophisticated Scheme implementation
is support for debugging. Scheme 48/scsh come with a huge set of tools to
ease the daily life of a programmer. This page tries to summarize
these tools. Please note, that this page is still under
construction.
- The inspector
This allows interactive inspection of compound data structures such as lists, records, exceptions and continuations. See the respective section in the Scheme 48 manual for a full description.
- Debugger
After an exception occurred you can use the ,debug
command to inspect the exception continuation associated with the error:
> (define (f a b) (+ a b))
> (f 'c 4)
Error: exception
#f
(+ 'c 4)
1> ,debug
'#{Exception-continuation (pc 16) (+ in scheme-level-0)}
inspect: d
'#{Continuation (pc 25) (evaluate-and-select in command-processor)}
[0] '#{Procedure 5736 (unnamed in evaluate-and-select in command-processor)}
[1] '(f 'c 4)
[2] '#{Package 146 user}
Here, the u
and d
commands from the inspector become particularly useful to walk along the continuation chain
- No backtrace but a preview
The ,preview
command will show the continuation frames lying on the stack.See also in the Scheme 48 Manual
- Breakpoints
The structure big-util
exports the procedure breakpoint
, which can be used to set breakpoints. Its argument are a format string and the corresponding arguments. Simply call breakpoint
somewhere in your code and when evaluation gets to it, a new command level will be pushed and the formatted string produced from the arguments to breakpoint
will be printed. To continue, use the ,proceed
command, which assigns a value to the breakpoint expression and lets it return.
- Expanding macros
To see the result of macro expansion, you can use the ,expand
command:
> ,expand (or 1)
1
> ,expand (or 1 2)
'((lambda (#(>> or temp 1290)) (if #(>> or temp 1290) #(>> or temp 1290) 2)) 1)
Also described in the Scheme 48 manual.
- Record disclosers
The procedure define-record-discloser
from the package define-record-types
lets you specify how records of a certain type are displayed:
,open define-record-types
> (define-record-type foo :foo
(make-foo bar baz)
foo?
(bar foo-bar)
(baz foo-baz))
> (define-record-discloser :foo
(lambda (a-foo)
(list 'foo (foo-bar a-foo) 'entries: (vector-length (foo-baz a-foo)))))
> (define my-foo (make-foo 42 (make-vector 1000 3)))
> my-foo
'#{Foo 42 entries: 1000}
As the example points out, this feature is particularly useful for showing large data structures.
- Spatial
The structure spatial
exports several procedures that print statistics about the heap usage:
(space)
prints a overview according to the types of the objects.
(record-space)
shows the space used by the various record types.
(vector-space)
displays heap usage for vectors.
- Traverse
The structure traverse
contains another utility to detect memory leaks.It will show the accessibility from one object to another.
Call either (traverse-depth-first obj1)
or (traverse-breadth-first obj1)
,where obj1
is the source object. Afterwards, (trail obj2)
will show via what path obj1
points to obj2
.
- Finding objects of a certain type
The structure primitives
exports a procedure (find-all stob)
, which returns a vector of all VM objects of type stob
. The structure architecture
exports the enumeration stob
, which contains the types of all VM objects.
Perhaps even more useful is the procedure (find-all-records record-type)
from the same structure, which returns a vector of all records of a given type.