Bayley, Alistair writes:
data SqliteException = SqliteException Int String deriving (Typeable)
catchSqlite :: IO a -> (SqliteException -> IO a) -> IO a catchSqlite = catchDyn
throwSqlite :: SqliteException -> a throwSqlite = throwDyn
I, too, think that's a good way to do it. And in the cases where a custom data type seems to be overhead, I simply use (fail "Foo.Bar: buffer overflow") and catch it with: isBufferOverflow :: IOError -> Bool isBufferOverflow e = (isUserError e) && (ioeGetErrorString e == "FooBar: buffer overflow") Once you have attributes for individual exceptions, defining them for arbitrary groups of exceptions is trivial. And the fact that I _use_ the message internally encourages me to use clear and consistent error messages which also make sense in case someone just 'show's them.
Python can work that way, but also adds another feature:
try: blah moreblah finally: foo
And in Haskell we have catch(Dyn), bracket, and finally. Are these not enough?
We also have Control.Exception.try. :-) Peter