[Haskell] Better Exception Handling

Ben Rudiak-Gould Benjamin.Rudiak-Gould at cl.cam.ac.uk
Tue Nov 23 12:20:19 EST 2004


John Goerzen wrote:

 >myfunc :: String -> Int
 >
 >This does some sort of string parsing and returns an Int.  Or it may
 >raise an exception if it couldn't parse the string.  But it would do
 >that every time.
 >
 >Now, let's say we have a non-IO catchJust.  Of course, if we never need
 >the value, we never run the function -- or catchJust.  If we do need the
 >value, we run the function in the context of catchJust.  If it raises
 >our exception, catchJust handles it and returns some default.  If it
 >raises no exception, it's the same as having no handler at all.  And if
 >it raises some other exception, it's also the same as having no handler
 >at all.
 >
 >So what am I missing here?

myfunc might raise more than one exception. For example,

    myfunc = error "x" + error "y"

Haskell doesn't specify which exception will actually be thrown, and 
this indeterminism is modeled by putting exception-catching functions in 
the IO monad. There's a paper explaining it [1].

I'm not convinced this is the best solution. I can't think of a 
situation in which there's a piece of code that throws different 
exceptions depending on evaluation order, /and/ I care which one of 
those I catch. If each particular implementation were just consistent 
about which exception it reports in these situations, I think the 
exception-catching functions would be pure. In any case, mapException is 
pure, and it's good enough for most of the cases where one might want to 
catch exceptions outside the IO monad.

The second problem with exceptions in Haskell, which I think is rather 
more serious, is that they can hide inside of data structures. This 
means that you can't, for example, wrap an exception handler around 
(readConfigFile :: FilePath -> IO [ConfigOption]) and be sure that you 
will catch any exceptions that are thrown during the parsing of the 
configuration file. Depending on how readConfigFile is written, those 
exceptions may be hiding inside the returned list, where they won't be 
noticed until some other part of the program inspects that part of the 
list, at which point your exception handler is no longer in scope. The 
only remedy is to use deepSeq (which really ought to be derivable).

A question I don't know the answer to is whether (catchJust :: a -> 
Maybe a), which lumps all exceptions into a Nothing return, is pure. It 
seems like it would be; if so, why don't we have it? Or do we?

-- Ben

[1] http://research.microsoft.com/~simonpj/Papers/imprecise-exn.htm



More information about the Haskell mailing list