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:
(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
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:
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.
More information about the Glasgow-haskell-users