Section 2 - Basics : HOOD Overview

Home ] Up ] Next ]

Section 2: A short tutorial on HOOD

Summary:

In order to use HOOD, you need to got through a number of steps.

Caveat: If you want to look at your own data structures, you need to write some instances. We explain this later, in Section 6.

We now introduce our debugging combinator, and explain how to run a program inside HOOD.


Annotating your Haskell program

The basic idea behind HOOD is to have a combinator that allows the Haskell user to observe data structures in a transparent way. As a way of achieving this, consider the Haskell fragment:

consumer . producer

We provide a combinator for debugging that both passing an argument transparently, and observes and remembers the argument. To facilitate multiple observations in one program, we use a string argument, which is a label used only for identification purposes. The type of our principal debugging combinator is

observe :: (Observable a) => String -> a -> a

In the above point-free example, we could write:

consumer . observe "intermediate" . producer

This has identical semantics to "consumer . producer", but the observe squirrels away the data structure that gets drawn through it, putting it into some persistent structure for later perusal. As far as the execution of Haskell program is concerned, observe (with a label) is just a version of id

observe sees intermediate structures! Here is a table illustrating two ways to use observe. Note that the type and strictness properties of the expression before and after inserting observe is the same (modulo the Observe class restriction).

  Original Expression New Expression  Intermediate Type
Data structure
observation
<consumer> · <producer> <consumer> · observe "intermediate list" · <producer> <producer> :: ... -> A 
map f · map g map f  · observe "between map f and map g" · map g A
<consumer> <producer> <consumer> (observe "intermediate list" <producer>) <producer> :: A
map f (map g xs) map f (observe "between map f and map g" (map g xs)) A

observe has a type class restriction on the object being observed. This does not turn out to be as big a problem as might be thought.  HOOD provides instances for all the Haskell98 base types (Int, Bool, Float, etc), as well as many containers (List, Array, Maybe, Tuples, etc) so the member restriction should not be a problem in practice.

Base Types Int, Bool, Float, Double, Integer, Char,()
Constructors (Observe a) => [a]  and (Maybe a)
(Observe a,Observe b) => (a,b) and (Array a b) and Either a b 
(Observe a,Observe b,...) => 3-tuple, 4-tuple, 5-tuple.
Functions (Observe a,Observe b) => (a -> b)
IO Monad (Observe a) => IO a
"Extended" Haskell Exceptions (calls to error, etc)

You can also add your instances for your own data structures. (The support for observations on Exceptions, which is useful for finding bottoms in your structures, is only supported on some compilers).


Running HOOD

Lets construct a trivial example.

example :: IO ()
example = print (sum [1..10::Int])

We want to observe the list inside this program. So we write

example :: IO ()
example = print (observe "list" (sum [1..10::Int]))

(we've underlined the inserted code). We run this short program using the function runO.

runO :: IO a -> IO ()

So, our main would be

main :: IO ()
main = runO example

(Alternatively, in Hugs, you could just type "runO example"). Running this program give

prompt% ./main
55

-- list
( 1 : 2 : 3 : 4 : 5 : 6 : 7 : 8 : 9 : 10 : [])

In summary

Home ] Up ] Next ]