{- | This module redefines some of the functions in "Control.Exception.Extensible" to work for more general monads than only 'IO'. -} module System.Console.Haskeline.MonadException( MonadException(..), handle, finally, throwIO, throwTo, bracket, throwDynIO, handleDyn, Exception, SomeException(..), E.IOException()) where import qualified Control.Exception.Extensible as E import Control.Exception.Extensible(Exception,SomeException) import Prelude hiding (catch) import Control.Monad.Reader import Control.Monad.State import Control.Concurrent(ThreadId) class MonadIO m => MonadException m where catch :: Exception e => m a -> (e -> m a) -> m a block :: m a -> m a unblock :: m a -> m a handle :: (MonadException m, Exception e) => (e -> m a) -> m a -> m a handle = flip catch finally :: MonadException m => m a -> m b -> m a finally f ender = block (do r <- catch (unblock f) (\(e::SomeException) -> do {ender; throwIO e}) ender return r) throwIO :: (MonadIO m, Exception e) => e -> m a throwIO = liftIO . E.throwIO throwTo :: (MonadIO m, Exception e) => ThreadId -> e -> m () throwTo tid = liftIO . E.throwTo tid bracket :: MonadException m => m a -> (a -> m b) -> (a -> m c) -> m c bracket before after thing = block (do a <- before r <- catch (unblock (thing a)) (\(e::SomeException) -> do { after a; throwIO e }) after a return r ) throwDynIO :: (Exception exception, MonadIO m) => exception -> m a throwDynIO = throwIO handleDyn :: (Exception exception, MonadException m) => (exception -> m a) -> m a -> m a handleDyn = handle instance MonadException IO where catch = E.catch block = E.block unblock = E.unblock instance MonadException m => MonadException (ReaderT r m) where catch f h = ReaderT $ \r -> catch (runReaderT f r) (\e -> runReaderT (h e) r) block = mapReaderT block unblock = mapReaderT unblock instance MonadException m => MonadException (StateT s m) where catch f h = StateT $ \s -> catch (runStateT f s) (\e -> runStateT (h e) s) block = mapStateT block unblock = mapStateT unblock