Hat - a Haskell tracer for nhc98
Hat, the nhc98 tracer, is applicable to a wide class of Haskell
computations, including those that:
- run to completion producing output, though perhaps not the
output expected; or
- halt with a run-time error, such as a pattern-matching
failure or a black hole; or
- appear to be stuck in an a recursive loop, whether or not
output is being produced.
To obtain a trace of a computation:
-
Compile all modules of the program with the -T option;
also specify -T at link-time. Using hmake -T does
all the necessary compiling and linking automatically.
-
Run the program.
If the program halts, any normal output from the program will
be followed by a summary line indicating whether it terminated
correctly or if there was an error. The trace is
now available in a file called <program>.hat.
If it seems the program is stuck in an unproductive loop
force it to halt by keying an interrupt (usually ctrl-C).
-
This is now a variety of tools you can use to explore this trace.
To explore a trace using the hat-trail browser
-
If there is not already a trace browser running, start
one by giving the shell command hat-trail, optionally
adding the name of the program whose trail you wish to browse.
-
****
Wrong here ****
With a traced Haskell program in the trace-available
state, click over the `connect' button in the upper part
of the trace-browser window.
Any program output is shown in the lower panel of the
trace browser. Clicking over a section of the output causes a
parent expression for that output to be displayed in the upper trace
panel. There is one section of output for each monadic output
operation performed by the program, and any currently selected
section is shown in blue.
If a run-time error has occurred, or the computation has been interrupted,
the initial trace panel displays the expression under
evaluation at the time.
-
Moving the mouse over expressions in the trace panel causes
the display of various forms of highlighting. The most important
ones are:
- a red box highlights any currently-selected subexpression S;
- expressions with the same parent as S (siblings) are shown in blue; however, subexpressions of these siblings which have a different parent are not shown in blue;
- if the parent redex of S is already on display it is shown
with a background highlight in yellow.
-
Beyond the normal syntax for Haskell expressions, five special
symbols may occur in trace expressions:
bottom |
the undefined value, as usual; |
empty box |
a placeholder for a subexpression suppressed for
the time-being (eg. to avoid over-wide displays); |
slant box |
a placeholder for an expression that
is not available because it is part of a
trusted computation not recorded in
the trace -- however, the parent redex
is available; |
cross box |
a placeholder for an expression that
is not available -- nor are its ancestral
redexes, as they have been
pruned from the trace; |
within |
shown between the values of case
subjects, conditions or guards and those of
the expressions they belong to. |
Mouse clicks in the trace panel have the following effects:
left: |
show the parent redex of S, if any;
(or, if the parent is already on
display, remove it along with any of its
ancestors also on display) |
middle: |
if S is a place-holder, expand it;
(or, if not, contract S to a
place-holder) |
right: |
show where S originates in the
source program, displayed in lower panel.
(If S is a name, a plain right-click
requests the corresponding point of use,
but shift-right-click requests the
definition.) |
Partial traces (avoiding detail and saving space)
There are two ways to specify a partial trace:
-
Trusting: details of computation within specified modules or
functions are omitted from the trace. The choice of which
components to trust and which to suspect can be made at
compile-time but can also be altered at run-time.
At compile-time, use -T -trusted to compile a trusted module.
At run-time, after +RTS alter the compile-time specification
of trusted modules or functions by -dt name, or suspected
ones by -ds name. Name functions in full with the
module name as prefix: for example, -ds BinaryTree.Delete.
The flags -dtr and -dsr can be used to trust or suspect
not only the
named module but also all other modules that it (recursively)
depends on.
By default only the Prelude is trusted.
-
Pruning:at each garbage collection, trace structure more
than a specified distance k from all continuing evaluation points
is discarded. Any pruning is specified at run-time: for example,
+RTS -dk2 -RTS.
Just using +RTS -dk -RTS prunes the trace structure to free just
enough space to continue computation.
By default there is no pruning.
Four limiting factors
-
The tracer does not currently handle programs involving
I/O other than to standard input and/or standard output.
-
List comprehensions are traced in terms of their explicit
translations to higher-order function applications.
-
Traced execution can take 10-30 times longer than normal.
-
Traced execution without pruning requires heap memory in
rough proportion to the length of the computation.
(As a rough rule of thumb, 100 bytes of heap memory are
required for each traced reduction.)
We plan to address all four of these limitations in future versions.
The latest updates to these pages are available on the WWW from
http://www.haskell.org/nhc98/
27th April 2001
York Functional Programming Group
Colin.Runciman@cs.york.ac.uk
|