Control.Exception

Simon Marlow marlowsd at gmail.com
Mon Nov 3 08:24:32 EST 2008


Jason Dagit wrote:
> On Wed, Oct 8, 2008 at 1:19 AM, Simon Marlow <marlowsd at gmail.com> wrote:
>> Johannes Waldmann wrote:
>>> with 6.10, the following does not typecheck:
>>>
>>> foo `Control.Exception.catch` \ _ -> return bar
>>>
>>> Ambiguous type variable `e' in the constraint:
>>>      `Control.Exception.Exception e'
>>>
>>> It is probably bad programming style anyway but what is the workaround?
>> As long as you're aware that it is bad programming style.  We deliberately
>> didn't include an easy way to do this, because we want people to think about
>> why they need to catch *all* exceptions (most of the time it's a bug).
> 
> Since the above is bad form, what should I be doing?  Could someone
> please provide some examples or point me at the list of exceptions
> that I can catch?  What about catching multiple types of exceptions?

Let's distinguish two kinds of exception handling:

1. Cleaning up.  If you want to catch errors in order to clean up - release 
resources, remove temporary files, that sort of thing - then use bracket or 
finally.  Behind the scenes, these catch all exceptions, but crucially they 
re-throw the exception after cleaning up, and they do the right 
block/unblock stuff for asynchronous exceptions.

2. Recovery.  You want to catch certain kinds of exception in order to 
recover and do something else, e.g. when calling getEnv.  In that case, I 
recommend using try or tryJust.

    tryJust (guard . isDoesNotExistError) $ getEnv "HOME"

it's good practice to separate the filter (the kinds of exception you're 
catching) from the code to handle them, and that's what tryJust does. 
There's some subtelty here to do with whether you need to be in "blocked" 
mode to handle the exception or not: if you're handling an exception you 
expect to be thrown asynchronously, then you probably want to use catch 
instead of try, because then the handler will run in blocked mode.  But be 
careful not to tail-call out of the handler, because then the thread will 
stay in blocked mode, which will lead to strange problems later.  A bit 
more background is here:

http://hackage.haskell.org/trac/ghc/ticket/2558

(hmm, perhaps exception handlers should be STM transactions.  Then you 
wouldn't be able to accidentally tail-call out of the exception handler 
back into IO code, but you would be able to re-throw exceptions.  Just a 
thought.)

As for the kinds of exception you can catch, nowadays you can catch any 
type that is an instance of Exception.  A good place to start is the list 
of instances of Exception in the docs:

http://www.haskell.org/ghc/dist/stable/docs/libraries/base/Control-Exception.html#t%3AException

although that only contains types defined by the base package.

Others have commented on the backwards-compat issues, I don't have anything 
to add there.

Cheers,
	Simon


More information about the Glasgow-haskell-users mailing list