Move MonadIO to base

On Sun, Apr 11, 2010 at 5:35 PM, Yitzchak Gale <gale at sefer.org> wrote:
> Twan van Laarhoven wrote:
>> If MonadIO were in base, then the base library itself could also use it. For
>> example the functions in System.IO could be lifted to work on any MonadIO
>> monad. Whether that is a good idea is completely orthogonal to this
>> discussion, however.
>> The main problem is that exceptions don't work well with
> MonadIO in GHC. So really MonadIO is currently only a toy and
> cannot be used in production code.
>> The reason for this is that just about any operation involving exceptions
> ultimately depends (via the source code of base library functions)
> on the function
>> block :: IO a -> IO a
>> and that type is hard-wired in a GHC primitive.
Can you explain why this is a problem?
Do note we have the packages MonadCatchIO-transformers[1] and
MonadCatchIO-mtl[2] that both provide:
class MonadIO m => MonadCatchIO m where
catch :: Exception e => m a -> (e -> m a) -> m a
block :: m a -> m a
unblock :: m a -> m a
> Additional primitives to support things like
>> startBlocking :: IO ()
> stopBlocking :: IO ()
>> which would play well with MonadIO, could be added to
> GHC, but they would lose important optimizations.
> I'm not sure about the order of magnitude of the cost - whether
> it would just make things run more slowly, or render them
> completely unusable. If the former, I am in favor of this
> proposal, but only combined with the addition of GHC support
> for startBlocking and stopBlocking. If the latter, then
> there is no point to this proposal.
Note that currently a discussion[3] is going on about hiding 'block'
and 'unblock' and replacing them with:
mask :: ((IO a -> IO a) -> IO b) -> IO b
mask io = do
b <- blocked
if b
then io id
else block $ io unblock
to be used like this:
a `finally` b =
mask $ \restore -> do
r <- restore a `onException` b
b
return r
Of course when this change is made the MonadCatchIO class has to be
adapted to something like:
class MonadIO m => MonadCatchIO m where
catch :: Exception e => m a -> (e -> m a) -> m a
mask :: ((m b -> m b) -> m a) -> m a
instance MonadCatchIO IO where
catch = Control.Exception.catch
mask io = do
b <- blocked
if b
then io id
else block $ io unblock
instance MonadCatchIO m => MonadCatchIO (ReaderT r m) where
m `catch` f = ReaderT $ \r -> runReaderT m r `catch`
\e -> runReaderT (f e) r
mask io = ReaderT inner
where
inner r = mask innerIO
where
innerIO innerRestore = runReaderT (io restore) r
where
restore reader = ReaderT $ innerRestore .
runReaderT reader
Note I'm +1 for separating MonadIO from transformers and mtl. I'm not
sure yet about putting it in base.
regards,
Bas
[1] http://hackage.haskell.org/package/MonadCatchIO-transformers
[2] http://hackage.haskell.org/package/MonadCatchIO-mtl
[3] http://thread.gmane.org/gmane.comp.lang.haskell.cafe/72145/focus=72182