tags:

views:

152

answers:

4

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.

+2  A: 

You didn't tell us which compiler you are using. If you use GHC, then you should take a look at the GHCi Debugger.

Stack tracing in Haskell is not trivial, because of its laziness. Nevertheless, the aforementioned debugger provides some tools (see section 2.5.5. Tracing and history in the above URL).

3lectrologos
+2  A: 

In general it is up to you to handle error in such a fashion that there is enough context for you to debug the cause.

The lazyness of Haskell makes stack traces difficult to implement, because the call stack might not exist any longer by the time the error happens.

A simple way of error handling is to use the Either type which allows your to return a value when things went right, or some context (error message, the input string, ...) in case of an error.

Finally, in you specific case read is throwing an exception so you would have to catch that and then handle the error in the calling code (have a look in the Control.Exception package).

liwp
+1  A: 

You might consider using a monadic read as in "Practical Haskell: shell scripting with error handling and privilege separation" by fellow StackOverflow user dons:

The first step is to replace read with a version lifted into a generic error monad, MonadError:

readM :: (MonadError String m, Read a) => String -> m a
readM s | [x] <- parse = return x
        | otherwise    = throwError $ "Failed parse: " ++ show s
    where
        parse = [x | (x,t) <- reads s]
Greg Bacon
+1  A: 

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

import Debug.Trace

--change
myRead s = read s
--to 
myRead s = trace s (read s)
--or 
myRead s = trace (take 100 s) (read s)
ja