
Isaac Dupree wrote:
therefore mapException is equally buggy!
mapException :: (Exception e1, Exception e2) => (e1 -> e2) -> a -> a mapException f v = unsafePerformIO (catch (evaluate v) (\x -> throw (f x)))
If it maps an asynchronous exception.. and it's re-thrown as synchronous... the same non-resumability happens! mapException is a particular culprit because of the unsafePerformIO (so you had a good reason to expect resumability, since it's for a pure computation, not in IO)
- does anyone use mapException?
- is there some reason that we don't have all "throw"s (synch. or asynch.) "patch up" the thunks? (memory leaks or serious inefficiency or something?)
In theory you could get a nasty space leak, but it's quite unlikely. When an exception is thrown, instead of just updating each thunk with "raise# DivByZero" for example, we would save the current computation in the heap to be restarted if the thunk was ever evaluated again. If the current computation refers to a large amount of heap data, technically that's a space leak. So one way to work around this would be to do all rethrows using throwTo. In most cases this will have no effect, because the rethrows happen in IO code which normally has no enclosing thunks, but in the case of mapException and unsafePerformIO it will fix (or work around) the problems we have with re-throwing async exceptions. Cheers, Simon