How would one debug this (obviously) flawed program using GHC's profiling tools? The program enters an infinite recursion within the second clause of frobnicate
.
-- Foo.hs
frobnicate :: Show a => Maybe a -> String
frobnicate Nothing = ""
frobnicate x = case frobnicate x of
"" -> "X"
_ -> show x
main :: IO ()
main = print (frobnicate (Just "" :: Maybe String))
The example might look contrived, but it's actually stripped down version of a real bug I encountered today.
In an imperative language one the mistake would be obvious as the stack trace would say something like frobnicate -> frobnicate -> frobnicate -> ...
. But how would one discover this in Haskell? How would one narrow down the blame to this one particular function?
I tried something akin to the following:
ghc -fforce-recomp -rtsopts -prof -fprof-auto Foo.hs
./Foo +RTS -M250M -i0.001 -h
hp2ps -c Foo.hp
where the -M250M
flag is added to ensure it doesn't kill the machine, -i0.001
increases the profiling frequency in an attempt to catch the overflow in action (which happens very fast).
This produces this rather unhelpful plot:
There is no obvious overflow in this plot. The y-axis doesn't go past even a single megabyte! What am I doing wrong here?