Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ghci displaying execution stack

Tags:

haskell

ghci

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.

like image 795
Archit Baweja Avatar asked Jul 12 '10 02:07

Archit Baweja


2 Answers

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.

like image 196
Daniel Avatar answered Oct 22 '22 10:10

Daniel


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.

like image 34
jrockway Avatar answered Oct 22 '22 10:10

jrockway