a library for reifying values in GHC
Bernard James POPE
bjpop@cs.mu.OZ.AU
Fri, 15 Aug 2003 17:31:27 +1000 (EST)
Hi all,
During my work on buddha (haskell debugger) I've had the need
to print arbitrary values from a running program.
Along the way I've written some code that works with GHC
to do this.
Just in case there are others who might benefit from this,
I've ripped some code out of buddha and made it into somewhat of
a library.
You can download it from here:
http://www.cs.mu.oz.au/~bjpop/code.html
The main parts are:
reify :: a -> IO Graph
data Graph = ...
prettyGraph :: Graph -> String
The graph type is an ordinary data type:
type Unique = Int -- a unique label for each node
type Tag = Int -- what kind of node it is
type NumKids = Int -- how many children it has
data Graph
= AppNode Unique String Tag NumKids [Graph]
| CharNode Char
| IntNode Int
| IntegerNode Integer
| FloatNode Float
| DoubleNode Double
| NullNode
deriving Show
The main features are:
- it is conservative wrt to evaluation (lazy). It does not
make its argument evaluate any further,
- it detects cycles in the heap representation and makes them
visible in the Graph representation (though the current
pretty printer does not take advantage of this),
- it knows about some "special" things like exceptions and
some other oddities,
- it ought to work on GHC 5 and 6, though I haven't tested it
extensively on the latter
Functions are a sore point (they all get mapped to the one thing, sigh).
It makes use of the FFI and the nice API that GHC provides for the
RTS (is that enough TLAs in one sentence?)
Unfortunately to use the library you must compile with -prof. The reason
is to trick GHC into keeping names of data constructors on the heap.
I'd rather avoid this, and perhaps with the new HsDebug stuff in GHC there
is a better way to get such names, but I haven't looked too hard.
(Any ideas?)
An example is below.
Ooroo,
Bernie.
--------------------------------------------------------------------------------
Here's an example:
{- demonstrating the use of ReifyHs.reify -}
module Main where
import ReifyHs (reify)
import PrettyGraph (prettyGraph)
import Data.Char (toUpper)
main :: IO ()
main
= do putStrLn $ "GHC version: " ++ show __GLASGOW_HASKELL__
let listTups = zip "abcdefghij" [1..]
putStr "\n\nForce the list to be evaluated a bit:\n\n"
print $ take 3 listTups
graph <- reify listTups
putStr "\n\nhere's the graph representation: \n\n"
print graph
putStr "\n\nhere's a pretty print of the above: \n\n"
putStrLn $ prettyGraph graph
putStr "\n\nForce the list to be evaluated a bit more:\n\n"
print $ take 5 listTups
graph <- reify listTups
putStr "\n\nthe graph pretty printed again: \n\n"
putStrLn $ prettyGraph graph
--------------------------------------------------------------------------------
Running the example after "make"
bjpop@bjpop2:/tmp/reify$ ./test
GHC version: 504
Force the list to be evaluated a bit:
[('a',1),('b',2),('c',3)]
here's the graph representation:
AppNode 1076636796 ":" 1 2 [AppNode 1076636776 "(,)" 1 2 [CharNode 'a',
IntNode 1],AppNode 1076637368 ":" 1 2 [AppNode 1076637348 "(,)" 1 2
[CharNode 'b',IntNode 2],AppNode 1076637932 ":" 1 2 [AppNode 1076637912
"(,)" 1 2 [CharNode 'c',IntNode 3],AppNode (-1) "" 3 0 []]]]
here's a pretty print of the above:
[('a',1),('b',2),('c',3) .. ?
Force the list to be evaluated a bit more:
[('a',1),('b',2),('c',3),('d',4),('e',5)]
the graph pretty printed again:
[('a',1),('b',2),('c',3),('d',4),('e',5) .. ?