RE: bracket, (un)block and MonadIO

However, the definition of bracket relies on block and unblock, which have the following types:
bracket :: IO a -> (a -> IO b) -> (a -> IO c) -> IO c block :: IO a -> IO a unblock :: IO a -> IO a
This forces f to be an IO action in the above withQuery function. If bracket, block, and unblock had these types, my helper function would be well typed:
bracket :: MonadIO m => m a -> (a -> m b) -> (a -> m c) -> m c block :: MonadIO m => m a -> m a unblock :: MonadIO m => m a -> m a
Would anything prevent block, unblock, bracket (and other similar functions working on IO actions) from being generalized to all intances of MonadIO?
I'm afraid I can't see a way to generalise the types of block and unblock, since they are based on underlying primitives that really do have type (IO a -> IO a). Perhaps if your monad is isomorphic to IO, it could be done, but otherwise I don't think it's possible. Unless I'm missing something. Cheers, Simon

Hi, On Thu, Sep 04, 2003 at 10:45:17AM +0100, Simon Marlow wrote:
Would anything prevent block, unblock, bracket (and other similar functions working on IO actions) from being generalized to all intances of MonadIO?
I'm afraid I can't see a way to generalise the types of block and unblock, since they are based on underlying primitives that really do have type (IO a -> IO a). Perhaps if your monad is isomorphic to IO, it could be done, but otherwise I don't think it's possible. Unless I'm missing something.
It can be done by adding the right methods to the MonadIO class, with these rank-2 types:
liftIO' :: (forall a. IO a -> IO a) -> m a -> m a liftIO'' :: (forall a. IO a -> (b -> IO a) -> IO a) -> m a -> (b -> m a) -> m a
See the attached patch for the details. This solution is maybe a bit ugly, since these methods are fairly specific (liftIO' is needed to generalize block and unblock, and liftIO'' is needed to generalize catchException). But it does allow one to use catch/bracket/etc with monads built on top of IO with monad transformers, which is quite nice:
import Control.Monad.Reader
type M = ReaderT Int IO
main' :: M () main' = catch (do n <- ask liftIO (putStrLn (show n))) (\ e -> return ())
main :: IO () main = runReaderT main' 1
-- Sebastien P.S.: The patch moves the MonadIO class to GHC.IOBase, which already contains a function called ``liftIO'', but which does not appear to be used anywhere; I just commented it out...

On Thu, Sep 04, 2003 at 10:45:17AM +0100, Simon Marlow wrote:
However, the definition of bracket relies on block and unblock, which have the following types:
bracket :: IO a -> (a -> IO b) -> (a -> IO c) -> IO c block :: IO a -> IO a unblock :: IO a -> IO a
This forces f to be an IO action in the above withQuery function. If bracket, block, and unblock had these types, my helper function would be well typed:
bracket :: MonadIO m => m a -> (a -> m b) -> (a -> m c) -> m c block :: MonadIO m => m a -> m a unblock :: MonadIO m => m a -> m a
Would anything prevent block, unblock, bracket (and other similar functions working on IO actions) from being generalized to all intances of MonadIO?
I'm afraid I can't see a way to generalise the types of block and unblock, since they are based on underlying primitives that really do have type (IO a -> IO a). Perhaps if your monad is isomorphic to IO, it could be done, but otherwise I don't think it's possible. Unless I'm missing something.
this is a problem I have noticed too. I posted something to the libraries list asking for 'catch' to be added to MonadIO. however it was unclear how to best go about it, although a suitable catch can be written for most all mondads it was not certain whether there were some for which it couldn't be. http://haskell.org/pipermail/libraries/2003-February/000774.html -- --------------------------------------------------------------------------- John Meacham - California Institute of Technology, Alum. - john@foo.net ---------------------------------------------------------------------------
participants (3)
-
John Meacham
-
sebc@macs.hw.ac.uk
-
Simon Marlow