
Yitzchak Gale wrote:
Alexander Dunlap wrote:
For instances where an exception would be too intrusive, I don't see how it would be too hard to write a wrapper function
I wrote:
In a library that does not have direct access to the IO monad, it would be not just hard - it would be impossible. That is because of type restrictions in the current versions of catch, block, and friends.
Judah Jacobson wrote:
You haven't said why something like the following would not be sufficient:
readHistoryM :: MonadIO m => String -> m Bool readHistoryM file = liftIO $ do result <- try (readHistory file) return (result == Right ())
Because a library - other than readline itself - can't force its users to do that.
OK. Here's a simplified real-world example. Say you want to write a simple library that interfaces the text-to-speech facilities available on multiple platforms. To play nicely with programs written in a monadic style, the interface might be something like:
class MonadIO m => Speech m where sayText :: String -> m () runSpeech :: m a -> IO a
Here's my (slightly provocative) take on this: a MonadIO instance is not a complete wrapper around the IO monad, because it doesn't provide catch. It is not the responsibility of a library that provides IO functions to account for defficient wrappers of IO with no way to catch exceptions. The problem is in the IO wrapper, not the library that throws exceptions. However, I do agree that exceptions should generally be used for exceptional conditions, rather than for general control-flow. This is an example of a *good* reason to avoid an exception: because to use an exception for a non-exceptional condition is poor style. Avoiding exceptions because MonadIO has trouble with them is not a good enough reason, IMO. We should fix MonadIO instead. Cheers, Simon