
G'day all.
Quoting Donald Bruce Stewart
This article on the 8 different error handling strategies various common Haskell libs use:
http://www.randomhacks.net/articles/2007/03/10/haskell-8-ways-to-report-erro...
got me thinking:
we need to standardise/recommend a small set of methods for library error handling.
For the record, here are the eight ways: 1. Call error 2. Return Maybe 3. Return Either 4. Return a generic Monad, a.k.a. NotJustMaybe. 5. Use MonadError and a custom error type. 6. throwDyn 7. ioError and catch 8. Monad transformers, implementing some combination of the above. Note: NotJustMaybe is claimed to be a generalisation of 1-3; in fact that's not quite true, since using this idiom to call Error does require a wrapper call. Perhaps this wrapper should be given a shorter and snappier name than runIdentity? One other one has been left out, and that's continuation-based error handling. Some general comments: 1. I've never seen some of these (8 in particular) used in any general- purpose library. 2. If it doesn't cross an API boundary, it's none of my business what error handling scheme you use. 3. Prolog, sadly, encourages failure-driven loops. Java, even more sadly, seems to encourage loops where normal termination is achieved by throwing an exception. Haskell, by contrast, never encourages a compromise like that. 4. There are clearly different kinds of error/exception, and we shouldn't expect one size to fit all. As some examples: - Failure to meet a precondition includes division by zero, head of an empty list, array bounds checking etc. Anything which the client could trivially ensure but hasn't must be due to a bug in the client code. Calling "error" is appropriate. - True absence of a return value, such as looking up a value in a Data.Map which isn't there, calls for Maybe or generic Monad. In the absence of a short-and-snappy version of runIdentity, there is an argument for also providing an "error" version. We need a good naming convention for this. - Exceptions are _undesired_ conditions which would otherwise break the logical flow of control. These come in two varieties: Some you want the client to intercept and deal with (e.g. Parsec parse errors) and some you want to leave it up to the client to decide (e.g. most I/O exceptions).
* what role does MonadError play here, as a generic error handler?
I think this is a perfect fit for any exception which the client MUST deal with. It's the Haskell equivalent of Java's checked exceptions, which are a right royal pain when they're mandatory, but occasionally a godsend when they're not.
* can we make precise recommendations about which error strategies to use?
No, but I think we can state some general principles. Cheers, Andrew Bromage