What if you wanted to get a trace of everything that the Guile
evaluator does within a given procedure, but without Guile stopping
and waiting for your input at every step? For this requirement you
can install a trap on the procedure, as in the previous example, but
instead of debug-trap or gds-debug-trap, use the
trace-trap and trace-until-exit behaviours provided by
the (ice-9 debugging trace) module.
guile> (use-modules (ice-9 debugging traps) (ice-9 debugging trace))
guile> (load "matrix.scm")
guile> (install-trap (make <procedure-trap>
#:procedure mkmatrix
#:behaviour (list trace-trap trace-until-exit)))
guile> (do-main 4)
| 2: [mkmatrix]
| 3: [#<procedure #f (a sym definep)> #<autoload # b7c93870> define #f]
| 3: [#<procedure #f (a sym definep)> #<autoload # b7c93870> define #f]
| 4: (and (memq sym bindings) (let ...))
| 5: (memq sym bindings)
| 5: [memq define (debug)]
| 5: =>#f
| 3: [#<procedure #f (a sym definep)> #<autoload # b7c93870> define #f]
| 3: [#<procedure #f (a sym definep)> #<autoload # b7c93870> define #f]
| 4: (and (memq sym bindings) (let ...))
| 5: (memq sym bindings)
| 5: [memq define (debug)]
| 5: =>#f
| 3: [#<procedure #f (a sym definep)> #<autoload # b7c93870> let #f]
| 3: [#<procedure #f (a sym definep)> #<autoload # b7c93870> let #f]
| 4: (and (memq sym bindings) (let ...))
| 5: (memq sym bindings)
| 5: [memq let (debug)]
| 5: =>#f
| 3: [#<procedure #f (a sym definep)> #<autoload # b7c93870> let #f]
| 3: [#<procedure #f (a sym definep)> #<autoload # b7c93870> let #f]
| 4: (and (memq sym bindings) (let ...))
| 5: (memq sym bindings)
| 5: [memq let (debug)]
| 5: =>#f
| 3: [#<procedure #f (a sym definep)> #<autoload # b7c93870> let #f]
| 3: [#<procedure #f (a sym definep)> #<autoload # b7c93870> let #f]
| 4: (and (memq sym bindings) (let ...))
| 5: (memq sym bindings)
| 5: [memq let (debug)]
| 5: =>#f
| 2: (letrec ((yy 23)) (let ((x 1)) (quote this-is-a-matric)))
| 3: [#<procedure #f (a sym definep)> #<autoload # b7c93870> let #f]
| 3: [#<procedure #f (a sym definep)> #<autoload # b7c93870> let #f]
| 4: (and (memq sym bindings) (let ...))
| 5: (memq sym bindings)
| 5: [memq let (debug)]
| 5: =>#f
| 3: [#<procedure #f (a sym definep)> #<autoload # b7c93870> let #f]
| 3: [#<procedure #f (a sym definep)> #<autoload # b7c93870> let #f]
| 4: (and (memq sym bindings) (let ...))
| 5: (memq sym bindings)
| 5: [memq let (debug)]
| 5: =>#f
| 3: [#<procedure #f (a sym definep)> #<autoload # b7c93870> let #f]
| 3: [#<procedure #f (a sym definep)> #<autoload # b7c93870> let #f]
| 4: (and (memq sym bindings) (let ...))
| 5: (memq sym bindings)
| 5: [memq let (debug)]
| 5: =>#f
| 2: (let ((x 1)) (quote this-is-a-matric))
| 3: [#<procedure #f (a sym definep)> #<autoload # b7c93870> let #f]
| 3: [#<procedure #f (a sym definep)> #<autoload # b7c93870> let #f]
| 4: (and (memq sym bindings) (let ...))
| 5: (memq sym bindings)
| 5: [memq let (debug)]
| 5: =>#f
| 2: [let (let # #) (# # #)]
| 2: [let (let # #) (# # #)]
| 2: =>(#@let* (x 1) #@let (quote this-is-a-matric))
this-is-a-matric
guile> (do-main 4)
| 2: [mkmatrix]
| 2: (letrec ((yy 23)) (let* ((x 1)) (quote this-is-a-matric)))
| 2: (let* ((x 1)) (quote this-is-a-matric))
| 2: (quote this-is-a-matric)
| 2: =>this-is-a-matric
this-is-a-matric
guile>
This example shows the default configuration for how each line of trace output is formatted, which is:
|, a visual clue that the line is a line of trace
output, followed by
(...)), the
procedure being called ([...]), or the value being returned
from an evaluation or procedure call (=>...).
You can customize (ice-9 debugging trace) to show different
information in each trace line using the set-trace-layout
procedure. The next example shows how to get the source location in
each trace line instead of the stack depth.
guile> (set-trace-layout "|~16@a: ~a\n" trace/source trace/info)
guile> (do-main 4)
| matrix.scm:7:2: [mkmatrix]
| : (letrec ((yy 23)) (let* ((x 1)) (quote this-is-a-matric)))
| matrix.scm:3:2: (let* ((x 1)) (quote this-is-a-matric))
| matrix.scm:4:4: (quote this-is-a-matric)
| matrix.scm:4:4: =>this-is-a-matric
this-is-a-matric
guile>
(For anyone wondering why the first (do-main 4) call above
generates lots more trace lines than the subsequent calls: these
examples also demonstrate how the Guile evaluator “memoizes” code.
When Guile evaluates a source code expression for the first time, it
changes some parts of the expression so that they will be quicker to
evaluate when that expression is evaluated again; this is called
memoization. The trace output from the first (do-main 4) call
shows memoization steps, such as an internal define being transformed to
a letrec.)