tags:

views:

95

answers:

3

So I'm working through some initial chapter exercise of Real World Haskell and I wanted to know if there is an option in GHCi to make it show function evaluation with parameters on each recursive call. So for example I wrote a simple version of 'map', and when I apply it, I would like GHCi to display each recursive call with actual arguments (and hopefully expression results). Something which allows me to follow whats going on behind the scenes.

P.S. As I write this I have a feeling it may be limited by the laziness of haskell's execution model, correct me if I'm wrong.

A: 

I would recommend looking at the question How do I get a callstack in Haskell?, and Don Stewart's answer with linked guides on how to use ghci for debugging

rampion
+2  A: 

You can use hood for this:

import Debug.Hood.Observe

map2 f [] = []
map2 f (x:xs) = f x : (observe "map2" $ map2) f xs

main = runO $ print $ map2 (+1) ([1..10] :: [Int])

When you run it, it will print each call to map2 with the corresponding arguments and the result that was returned. You'll see something like:

.
.
.
-- map2
{ \ { \ 10  -> 11
    , \ 9  -> 10
    } (9 : 10 : []) 
    -> 10 : 11 : []
}
-- map2
{ \ { \ 10  -> 11
    } (10 : []) 
    -> 11 : []
}
-- map2
{ \ _ []  -> []
}

For more check the examples.

Daniel Velkov
+1  A: 

I typically use Debug.Trace:

import Debug.Trace

buggy acc xs | traceShow (acc,xs) False = undefined
buggy acc []     = acc
buggy acc (x:xs) = buggy (acc + x) xs

main = print $ buggy 0 [1..10]

This lets me see how the buggy function works:

(0,[1,2,3,4,5,6,7,8,9,10])
(1,[2,3,4,5,6,7,8,9,10])
(3,[3,4,5,6,7,8,9,10])
(6,[4,5,6,7,8,9,10])
(10,[5,6,7,8,9,10])
(15,[6,7,8,9,10])
(21,[7,8,9,10])
(28,[8,9,10])
(36,[9,10])
(45,[10])
(55,[])
55

The key is having a pattern that never matches, but prints something while it's not matching. That way it always gets evaluated (and hence prints the debugging information), and it's easy to tack on to any function. But you can also make it match if you only want to see certain cases, like:

buggy acc [] = acc
buggy acc (x:xs) | traceShow (acc, x, xs) True = buggy (acc + x) xs

Then you only get debugging output at the non-base-case:

(0,1,[2,3,4,5,6,7,8,9,10])
(1,2,[3,4,5,6,7,8,9,10])
(3,3,[4,5,6,7,8,9,10])
(6,4,[5,6,7,8,9,10])
(10,5,[6,7,8,9,10])
(15,6,[7,8,9,10])
(21,7,[8,9,10])
(28,8,[9,10])
(36,9,[10])
(45,10,[])
55

YMMV.

jrockway