{-# LANGUAGE CPP #-}
{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE TypeFamilies #-}
#if defined(__GLASGOW_HASKELL__) && __GLASGOW_HASKELL__ >= 702
{-# LANGUAGE Trustworthy #-}
#endif
#ifndef MIN_VERSION_transformers
#define MIN_VERSION_transformers(x,y,z) 1
#endif
#ifndef MIN_VERSION_mtl
#define MIN_VERSION_mtl(x,y,z) 1
#endif
module Control.Monad.Catch (
MonadThrow(..)
, MonadCatch(..)
, MonadMask(..)
, mask_
, uninterruptibleMask_
, catchAll
, catchIOError
, catchJust
, catchIf
, Handler(..), catches
, handle
, handleAll
, handleIOError
, handleJust
, handleIf
, try
, tryJust
, onException
, bracket
, bracket_
, finally
, bracketOnError
, Exception(..)
, SomeException(..)
) where
#if defined(__GLASGOW_HASKELL__) && (__GLASGOW_HASKELL__ >= 706)
import Prelude hiding (foldr)
#else
import Prelude hiding (catch, foldr)
#endif
import Control.Exception (Exception(..), SomeException(..))
import qualified Control.Exception as ControlException
import qualified Control.Monad.Trans.RWS.Lazy as LazyRWS
import qualified Control.Monad.Trans.RWS.Strict as StrictRWS
import qualified Control.Monad.Trans.State.Lazy as LazyS
import qualified Control.Monad.Trans.State.Strict as StrictS
import qualified Control.Monad.Trans.Writer.Lazy as LazyW
import qualified Control.Monad.Trans.Writer.Strict as StrictW
import Control.Monad.Trans.List (ListT(..), runListT)
import Control.Monad.Trans.Maybe (MaybeT(..), runMaybeT)
import Control.Monad.Trans.Error (ErrorT(..), Error, runErrorT)
#if MIN_VERSION_transformers(0,4,0)
import Control.Monad.Trans.Except (ExceptT(..), runExceptT)
#endif
import Control.Monad.Trans.Cont (ContT)
import Control.Monad.Trans.Identity
import Control.Monad.Reader as Reader
import Control.Monad.Trans.Reader (runReaderT)
import Control.Monad.RWS
import Data.Foldable
class Monad m => MonadThrow m where
throwM :: Exception e => e -> m a
class MonadThrow m => MonadCatch m where
catch :: Exception e => m a -> (e -> m a) -> m a
class MonadCatch m => MonadMask m where
mask :: ((forall a. m a -> m a) -> m b) -> m b
uninterruptibleMask :: ((forall a. m a -> m a) -> m b) -> m b
instance MonadThrow [] where
throwM _ = []
instance MonadThrow Maybe where
throwM _ = Nothing
instance e ~ SomeException => MonadThrow (Either e) where
throwM = Left . toException
instance MonadThrow IO where
throwM = ControlException.throwIO
instance MonadCatch IO where
catch = ControlException.catch
instance MonadMask IO where
mask = ControlException.mask
uninterruptibleMask = ControlException.uninterruptibleMask
instance MonadThrow m => MonadThrow (IdentityT m) where
throwM e = lift $ throwM e
instance MonadCatch m => MonadCatch (IdentityT m) where
catch (IdentityT m) f = IdentityT (catch m (runIdentityT . f))
instance MonadMask m => MonadMask (IdentityT m) where
mask a = IdentityT $ mask $ \u -> runIdentityT (a $ q u)
where q u = IdentityT . u . runIdentityT
uninterruptibleMask a =
IdentityT $ uninterruptibleMask $ \u -> runIdentityT (a $ q u)
where q u = IdentityT . u . runIdentityT
instance MonadThrow m => MonadThrow (LazyS.StateT s m) where
throwM e = lift $ throwM e
instance MonadCatch m => MonadCatch (LazyS.StateT s m) where
catch = LazyS.liftCatch catch
instance MonadMask m => MonadMask (LazyS.StateT s m) where
mask a = LazyS.StateT $ \s -> mask $ \u -> LazyS.runStateT (a $ q u) s
where q u (LazyS.StateT b) = LazyS.StateT (u . b)
uninterruptibleMask a =
LazyS.StateT $ \s -> uninterruptibleMask $ \u -> LazyS.runStateT (a $ q u) s
where q u (LazyS.StateT b) = LazyS.StateT (u . b)
instance MonadThrow m => MonadThrow (StrictS.StateT s m) where
throwM e = lift $ throwM e
instance MonadCatch m => MonadCatch (StrictS.StateT s m) where
catch = StrictS.liftCatch catch
instance MonadMask m => MonadMask (StrictS.StateT s m) where
mask a = StrictS.StateT $ \s -> mask $ \u -> StrictS.runStateT (a $ q u) s
where q u (StrictS.StateT b) = StrictS.StateT (u . b)
uninterruptibleMask a =
StrictS.StateT $ \s -> uninterruptibleMask $ \u -> StrictS.runStateT (a $ q u) s
where q u (StrictS.StateT b) = StrictS.StateT (u . b)
instance MonadThrow m => MonadThrow (ReaderT r m) where
throwM e = lift $ throwM e
instance MonadCatch m => MonadCatch (ReaderT r m) where
catch (ReaderT m) c = ReaderT $ \r -> m r `catch` \e -> runReaderT (c e) r
instance MonadMask m => MonadMask (ReaderT r m) where
mask a = ReaderT $ \e -> mask $ \u -> runReaderT (a $ q u) e
where q u (ReaderT b) = ReaderT (u . b)
uninterruptibleMask a =
ReaderT $ \e -> uninterruptibleMask $ \u -> runReaderT (a $ q u) e
where q u (ReaderT b) = ReaderT (u . b)
instance (MonadThrow m, Monoid w) => MonadThrow (StrictW.WriterT w m) where
throwM e = lift $ throwM e
instance (MonadCatch m, Monoid w) => MonadCatch (StrictW.WriterT w m) where
catch (StrictW.WriterT m) h = StrictW.WriterT $ m `catch ` \e -> StrictW.runWriterT (h e)
instance (MonadMask m, Monoid w) => MonadMask (StrictW.WriterT w m) where
mask a = StrictW.WriterT $ mask $ \u -> StrictW.runWriterT (a $ q u)
where q u b = StrictW.WriterT $ u (StrictW.runWriterT b)
uninterruptibleMask a =
StrictW.WriterT $ uninterruptibleMask $ \u -> StrictW.runWriterT (a $ q u)
where q u b = StrictW.WriterT $ u (StrictW.runWriterT b)
instance (MonadThrow m, Monoid w) => MonadThrow (LazyW.WriterT w m) where
throwM e = lift $ throwM e
instance (MonadCatch m, Monoid w) => MonadCatch (LazyW.WriterT w m) where
catch (LazyW.WriterT m) h = LazyW.WriterT $ m `catch ` \e -> LazyW.runWriterT (h e)
instance (MonadMask m, Monoid w) => MonadMask (LazyW.WriterT w m) where
mask a = LazyW.WriterT $ mask $ \u -> LazyW.runWriterT (a $ q u)
where q u b = LazyW.WriterT $ u (LazyW.runWriterT b)
uninterruptibleMask a =
LazyW.WriterT $ uninterruptibleMask $ \u -> LazyW.runWriterT (a $ q u)
where q u b = LazyW.WriterT $ u (LazyW.runWriterT b)
instance (MonadThrow m, Monoid w) => MonadThrow (LazyRWS.RWST r w s m) where
throwM e = lift $ throwM e
instance (MonadCatch m, Monoid w) => MonadCatch (LazyRWS.RWST r w s m) where
catch (LazyRWS.RWST m) h = LazyRWS.RWST $ \r s -> m r s `catch` \e -> LazyRWS.runRWST (h e) r s
instance (MonadMask m, Monoid w) => MonadMask (LazyRWS.RWST r w s m) where
mask a = LazyRWS.RWST $ \r s -> mask $ \u -> LazyRWS.runRWST (a $ q u) r s
where q u (LazyRWS.RWST b) = LazyRWS.RWST $ \ r s -> u (b r s)
uninterruptibleMask a =
LazyRWS.RWST $ \r s -> uninterruptibleMask $ \u -> LazyRWS.runRWST (a $ q u) r s
where q u (LazyRWS.RWST b) = LazyRWS.RWST $ \ r s -> u (b r s)
instance (MonadThrow m, Monoid w) => MonadThrow (StrictRWS.RWST r w s m) where
throwM e = lift $ throwM e
instance (MonadCatch m, Monoid w) => MonadCatch (StrictRWS.RWST r w s m) where
catch (StrictRWS.RWST m) h = StrictRWS.RWST $ \r s -> m r s `catch` \e -> StrictRWS.runRWST (h e) r s
instance (MonadMask m, Monoid w) => MonadMask (StrictRWS.RWST r w s m) where
mask a = StrictRWS.RWST $ \r s -> mask $ \u -> StrictRWS.runRWST (a $ q u) r s
where q u (StrictRWS.RWST b) = StrictRWS.RWST $ \ r s -> u (b r s)
uninterruptibleMask a =
StrictRWS.RWST $ \r s -> uninterruptibleMask $ \u -> StrictRWS.runRWST (a $ q u) r s
where q u (StrictRWS.RWST b) = StrictRWS.RWST $ \ r s -> u (b r s)
instance MonadThrow m => MonadThrow (ListT m) where
throwM = lift . throwM
instance MonadCatch m => MonadCatch (ListT m) where
catch (ListT m) f = ListT $ catch m (runListT . f)
instance MonadThrow m => MonadThrow (MaybeT m) where
throwM = lift . throwM
instance MonadCatch m => MonadCatch (MaybeT m) where
catch (MaybeT m) f = MaybeT $ catch m (runMaybeT . f)
instance (Error e, MonadThrow m) => MonadThrow (ErrorT e m) where
throwM = lift . throwM
instance (Error e, MonadCatch m) => MonadCatch (ErrorT e m) where
catch (ErrorT m) f = ErrorT $ catch m (runErrorT . f)
#if MIN_VERSION_transformers(0,4,0)
instance MonadThrow m => MonadThrow (ExceptT e m) where
throwM = lift . throwM
instance MonadCatch m => MonadCatch (ExceptT e m) where
catch (ExceptT m) f = ExceptT $ catch m (runExceptT . f)
#endif
instance MonadThrow m => MonadThrow (ContT r m) where
throwM = lift . throwM
mask_ :: MonadMask m => m a -> m a
mask_ io = mask $ \_ -> io
uninterruptibleMask_ :: MonadMask m => m a -> m a
uninterruptibleMask_ io = uninterruptibleMask $ \_ -> io
catchAll :: MonadCatch m => m a -> (SomeException -> m a) -> m a
catchAll = catch
catchIOError :: MonadCatch m => m a -> (IOError -> m a) -> m a
catchIOError = catch
catchIf :: (MonadCatch m, Exception e) =>
(e -> Bool) -> m a -> (e -> m a) -> m a
catchIf f a b = a `catch` \e -> if f e then b e else throwM e
catchJust :: (MonadCatch m, Exception e) =>
(e -> Maybe b) -> m a -> (b -> m a) -> m a
catchJust f a b = a `catch` \e -> maybe (throwM e) b $ f e
handle :: (MonadCatch m, Exception e) => (e -> m a) -> m a -> m a
handle = flip catch
{-# INLINE handle #-}
handleIOError :: MonadCatch m => (IOError -> m a) -> m a -> m a
handleIOError = handle
handleAll :: MonadCatch m => (SomeException -> m a) -> m a -> m a
handleAll = handle
handleIf :: (MonadCatch m, Exception e) => (e -> Bool) -> (e -> m a) -> m a -> m a
handleIf f = flip (catchIf f)
handleJust :: (MonadCatch m, Exception e) => (e -> Maybe b) -> (b -> m a) -> m a -> m a
handleJust f = flip (catchJust f)
{-# INLINE handleJust #-}
try :: (MonadCatch m, Exception e) => m a -> m (Either e a)
try a = catch (Right `liftM` a) (return . Left)
tryJust :: (MonadCatch m, Exception e) =>
(e -> Maybe b) -> m a -> m (Either b a)
tryJust f a = catch (Right `liftM` a) (\e -> maybe (throwM e) (return . Left) (f e))
data Handler m a = forall e . ControlException.Exception e => Handler (e -> m a)
instance Monad m => Functor (Handler m) where
fmap f (Handler h) = Handler (liftM f . h)
catches :: (Foldable f, MonadCatch m) => m a -> f (Handler m a) -> m a
catches a hs = a `catch` handler
where
handler e = foldr probe (throwM e) hs
where
probe (Handler h) xs = maybe xs h (ControlException.fromException e)
onException :: MonadCatch m => m a -> m b -> m a
onException action handler = action `catchAll` \e -> handler >> throwM e
bracket :: MonadMask m => m a -> (a -> m b) -> (a -> m c) -> m c
bracket acquire release use = mask $ \unmasked -> do
resource <- acquire
result <- unmasked (use resource) `onException` release resource
_ <- release resource
return result
bracket_ :: MonadMask m => m a -> m b -> m c -> m c
bracket_ before after action = bracket before (const after) (const action)
finally :: MonadMask m => m a -> m b -> m a
finally action finalizer = bracket_ (return ()) finalizer action
bracketOnError :: MonadMask m => m a -> (a -> m b) -> (a -> m c) -> m c
bracketOnError acquire release use = mask $ \unmasked -> do
resource <- acquire
unmasked (use resource) `onException` release resource