
My confusion surrounding exceptions in the IO monad comes from the fact that IO failures and "bottom" are not cleanly separated. I had always assumed the IO monad looked something like this: newtype IO a = IO (RealWorldState -> Either IOFailure (RealWorldState,a)) return a = IO (\r -> Right (r,a)) fail s = IO (\r -> Left (userFailure s)) This would make sense, I think, because it's so easy this way for Prelude.catch to catch all IOFailures but leave pure "bottom" exceptions alone, just as the report says. But in fact IO looks more like this: newtype IO a = IO (RealWorldState -> (RealWorldState,a)) return a = IO (\r -> (r,a)) fail s = IO (\r -> throw (userError s)) ...which means Prelude.catch has to separate out exceptions caused by "fail" from those caused by error, etc. and there's confusion between "bottom" and exceptions that happen entirely in IO. -- Ashley Yakeley, Seattle WA