18.5 Debugging
Racket’s built-in debugging support is limited to context (i.e., “stack trace”) information that is printed with an exception. In some cases, disabling the JIT compiler can affect context information. The errortrace library supports more consistent (independent of the JIT compiler) and precise context information. The racket/trace library provides simple tracing support. Finally, the DrRacket programming environment provides much more debugging support.
18.5.1 Tracing
(require racket/trace) | package: base |
The racket/trace library mimics the tracing facility available in Chez Scheme.
syntax
(trace id ...)
When traced procedures invoke each other, nested invocations are shown by printing a nesting prefix. If the nesting depth grows to ten and beyond, a number is printed to show the actual nesting depth.
The trace form can be used on an identifier that is already traced. In this case, assuming that the variable’s value has not been changed, trace has no effect. If the variable has been changed to a different procedure, then a new trace is installed.
Tracing respects tail calls to preserve loops, but its effect may be visible through continuation marks. When a call to a traced procedure occurs in tail position with respect to a previous traced call, then the tailness of the call is preserved (and the result of the call is not printed for the tail call, because the same result will be printed for an enclosing call). Otherwise, however, the body of a traced procedure is not evaluated in tail position with respect to a call to the procedure.
The result of a trace expression is #<void>.
> (define (f x) (if (zero? x) 0 (add1 (f (sub1 x)))))
> (trace f)
> (f 10)
>(f 10)
> (f 9)
> >(f 8)
> > (f 7)
> > >(f 6)
> > > (f 5)
> > > >(f 4)
> > > > (f 3)
> > > > >(f 2)
> > > > > (f 1)
> > > >[10] (f 0)
< < < <[10] 0
< < < < < 1
< < < < <2
< < < < 3
< < < <4
< < < 5
< < <6
< < 7
< <8
< 9
<10
10
syntax
(trace-define id expr)
(trace-define (head args) body ...+)
> (trace-define (f x) (if (zero? x) 0 (add1 (f (sub1 x)))))
> (f 5)
>(f 5)
> (f 4)
> >(f 3)
> > (f 2)
> > >(f 1)
> > > (f 0)
< < < 0
< < <1
< < 2
< <3
< 4
<5
5
> (trace-define ((+n n) x) (+ n x))
> (map (+n 5) (list 1 3 4))
>(+n 5)
<#<procedure>
'(6 8 9)
syntax
(trace-define-syntax id expr)
(trace-define-syntax (head args) body ...+)
For example:
> (trace-define-syntax fact (syntax-rules () [(_ x) 120]))
> (fact 5)
>(fact #<syntax:11:0 (fact 5)>)
<#<syntax:11:0 120>
120
By default, trace prints out syntax objects when tracing a macro. This can result in too much output if you do not need to see, e.g., source information. To get more readable output, try this:
> (require (for-syntax racket/trace))
> (begin-for-syntax (current-trace-print-args (let ([ctpa (current-trace-print-args)]) (lambda (s l kw l2 n) (ctpa s (map syntax->datum l) kw l2 n)))) (current-trace-print-results (let ([ctpr (current-trace-print-results)]) (lambda (s l n) (ctpr s (map syntax->datum l) n)))))
> (trace-define-syntax fact (syntax-rules () [(_ x) #'120]))
> (fact 5)
>(fact '(fact 5))
<'#'120
#<syntax:14:0 120>
syntax
(trace-lambda [#:name id] args expr)
> ((trace-lambda (x) 120) 5)
>(eval:16:0 5)
<120
120
syntax
(trace-let id ([arg expr] ...+) body ...+)
> (trace-let f ([x 5]) (if (zero? x) 1 (* x (f (sub1 x)))))
>(f 5)
> (f 4)
> >(f 3)
> > (f 2)
> > >(f 1)
> > > (f 0)
< < < 1
< < <1
< < 2
< <6
< 24
<120
120
syntax
(untrace id ...)
The result of an untrace expression is #<void>.
parameter
(current-trace-notify) → (string? . -> . any)
(current-trace-notify proc) → void? proc : (string? . -> . any)
procedure
(trace-call id proc #:<kw> kw-arg ...) → any/c
id : symbol? proc : procedure? kw-arg : any/c
parameter
(current-trace-print-args) →
(-> symbol? list? (listof keyword?) list? number? void?) (current-trace-print-args trace-print-args) → void?
trace-print-args :
(-> symbol? list? (listof keyword?) list? number? void?)
parameter
(current-trace-print-results) →
(-> symbol? list? number? any) (current-trace-print-results trace-print-results) → void?
trace-print-results :
(-> symbol? list? number? any)
parameter
(current-prefix-in prefix) → void? prefix : string?
It defaults to ">".
parameter
(current-prefix-out prefix) → void? prefix : string?
It defaults to "<".