Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Tracking down errors in Haskell

Tags:

haskell

How can I get more information about where a Haskell error has occurred? For example, yesterday I was working on a Haskell program that parses an input file, transforms the data and then prints out reporting information.

At one point, I ran "main" and got back

*** Prelude.read: parse error

with no other information. Fortunately, I knew I was calling read in only one place and was able to fix it, but for the future:

  • Is it possible to get a backtrace or a line number for errors like these?
  • Is it possible to get the actual data that triggered the error, i.e. the string that caused the parse error?

Thanks!

Edit Using GHC.

like image 960
Bill Avatar asked Jan 26 '10 13:01

Bill


2 Answers

If you can run the code in ghci, then the debugger can do everything you want. Here's a program that raises an exception

foo s i
  | i == 57 = read s
  | otherwise = i
main = mapM_ (print . foo "") [1..100]

Now load it into ghci and use the debugger, as documented here: http://www.haskell.org/ghc/docs/latest/html/users_guide/ghci-debugger.html#ghci-debugger-exceptions

> ghci test.hs
*Main> :set -fbreak-on-error
*Main> :trace main
1
2
... snipped 3 through 55 ...
56
Stopped at <exception thrown>
_exception :: e = _
[<exception thrown>] *Main> :back
Logged breakpoint at test.hs:2:15-20
_result :: a
s :: String
[-1: test.hs:2:15-20] *Main> :list
1  foo s i
2    | i == 57 = **read s**
3    | otherwise = i
[-1: test.hs:2:15-20] *Main> s
""
[-1: test.hs:2:15-20] *Main> 

It lets you step around in the evaluation history, highlights the actual expression that raised the exception (bold rather than starred on a terminal), and lets you inspect the local variables.

Another option is to recompile with profiling and some flags to tag appropriate cost centers, and run with the -xc profiling option which prints the cost center stack on uncaught exceptions http://www.haskell.org/ghc/docs/latest/html/users_guide/prof-time-options.html

> ghc -prof -auto-all test.hs
> ./test +RTS -cs
1
2
... snipped 3 through 55 ...
56
*** Exception (reporting due to +RTS -xc): (THUNK_2_0), stack trace: 
  Main.foo,
  called from Main.main,
  called from Main.CAF
  --> evaluated by: Main.main,
  called from Main.CAF
test: Prelude.read: no parse

The reason this is a bit difficult is described a bit earlier on the debugger page http://www.haskell.org/ghc/docs/latest/html/users_guide/ghci-debugger.html#tracing Basically, efficient Haskell execution doesn't use anything resembling a normal call stack, so to get that kind of information on an exception you have to be running in some special mode (debugging or profiling) which does keep that sort of information.

like image 69
Brandon Avatar answered Oct 31 '22 16:10

Brandon


you can get the string that caused the parse error by importing Debug.Trace and changing your call

import Debug.Trace (trace)

--change
myRead s = read s
--to 
myRead s = trace s (read s)
--or 
myRead s = trace (take 100 s) (read s)
like image 7
ja. Avatar answered Oct 31 '22 18:10

ja.