Blame Control/Exception/Lifted.hs

Packit 1d883e
{-# LANGUAGE CPP
Packit 1d883e
           , NoImplicitPrelude
Packit 1d883e
           , ExistentialQuantification
Packit 1d883e
           , FlexibleContexts #-}
Packit 1d883e
Packit 1d883e
#if MIN_VERSION_base(4,3,0)
Packit 1d883e
{-# LANGUAGE RankNTypes #-} -- for mask
Packit 1d883e
#endif
Packit 1d883e
Packit 1d883e
#if __GLASGOW_HASKELL__ >= 702
Packit 1d883e
{-# LANGUAGE Safe #-}
Packit 1d883e
#endif
Packit 1d883e
Packit 1d883e
{- |
Packit 1d883e
Module      :  Control.Exception.Lifted
Packit 1d883e
Copyright   :  Bas van Dijk, Anders Kaseorg
Packit 1d883e
License     :  BSD-style
Packit 1d883e
Packit 1d883e
Maintainer  :  Bas van Dijk <v.dijk.bas@gmail.com>
Packit 1d883e
Stability   :  experimental
Packit 1d883e
Portability :  non-portable (extended exceptions)
Packit 1d883e
Packit 1d883e
This is a wrapped version of "Control.Exception" with types generalized
Packit 1d883e
from 'IO' to all monads in either 'MonadBase' or 'MonadBaseControl'.
Packit 1d883e
-}
Packit 1d883e
Packit 1d883e
module Control.Exception.Lifted
Packit 1d883e
    ( module Control.Exception
Packit 1d883e
Packit 1d883e
      -- * Throwing exceptions
Packit 1d883e
    , throwIO, ioError, throwTo
Packit 1d883e
Packit 1d883e
      -- * Catching exceptions
Packit 1d883e
      -- ** The @catch@ functions
Packit 1d883e
    , catch, catches, Handler(..), catchJust
Packit 1d883e
Packit 1d883e
      -- ** The @handle@ functions
Packit 1d883e
    , handle, handleJust
Packit 1d883e
Packit 1d883e
      -- ** The @try@ functions
Packit 1d883e
    , try, tryJust
Packit 1d883e
Packit 1d883e
      -- ** The @evaluate@ function
Packit 1d883e
    , evaluate
Packit 1d883e
Packit 1d883e
      -- * Asynchronous Exceptions
Packit 1d883e
      -- ** Asynchronous exception control
Packit 1d883e
      -- |The following functions allow a thread to control delivery of
Packit 1d883e
      -- asynchronous exceptions during a critical region.
Packit 1d883e
#if MIN_VERSION_base(4,3,0)
Packit 1d883e
    , mask, mask_
Packit 1d883e
    , uninterruptibleMask, uninterruptibleMask_
Packit 1d883e
    , getMaskingState
Packit 1d883e
#if MIN_VERSION_base(4,4,0)
Packit 1d883e
    , allowInterrupt
Packit 1d883e
#endif
Packit 1d883e
#else
Packit 1d883e
    , block, unblock
Packit 1d883e
#endif
Packit 1d883e
Packit 1d883e
#if !MIN_VERSION_base(4,4,0)
Packit 1d883e
    , blocked
Packit 1d883e
#endif
Packit 1d883e
      -- * Brackets
Packit 1d883e
    , bracket, bracket_, bracketOnError
Packit 1d883e
Packit 1d883e
      -- * Utilities
Packit 1d883e
    , finally, onException
Packit 1d883e
    ) where
Packit 1d883e
Packit 1d883e
Packit 1d883e
--------------------------------------------------------------------------------
Packit 1d883e
-- Imports
Packit 1d883e
--------------------------------------------------------------------------------
Packit 1d883e
Packit 1d883e
-- from base:
Packit 1d883e
import Prelude         ( (.) )
Packit 1d883e
import Data.Function   ( ($) )
Packit 1d883e
import Data.Either     ( Either(Left, Right), either )
Packit 1d883e
import Data.Maybe      ( Maybe )
Packit 1d883e
import Control.Monad   ( (>>=), return, liftM )
Packit 1d883e
import System.IO.Error ( IOError )
Packit 1d883e
import System.IO       ( IO )
Packit 1d883e
Packit 1d883e
#if __GLASGOW_HASKELL__ < 700
Packit 1d883e
import Control.Monad   ( fail )
Packit 1d883e
#endif
Packit 1d883e
Packit 1d883e
import Control.Exception hiding
Packit 1d883e
    ( throwIO, ioError, throwTo
Packit 1d883e
    , catch, catches, Handler(..), catchJust
Packit 1d883e
    , handle, handleJust
Packit 1d883e
    , try, tryJust
Packit 1d883e
    , evaluate
Packit 1d883e
#if MIN_VERSION_base(4,3,0)
Packit 1d883e
    , mask, mask_
Packit 1d883e
    , uninterruptibleMask, uninterruptibleMask_
Packit 1d883e
    , getMaskingState
Packit 1d883e
#if MIN_VERSION_base(4,4,0)
Packit 1d883e
    , allowInterrupt
Packit 1d883e
#endif
Packit 1d883e
#else
Packit 1d883e
    , block, unblock
Packit 1d883e
#endif
Packit 1d883e
#if !MIN_VERSION_base(4,4,0)
Packit 1d883e
    , blocked
Packit 1d883e
#endif
Packit 1d883e
    , bracket, bracket_, bracketOnError
Packit 1d883e
    , finally, onException
Packit 1d883e
    )
Packit 1d883e
import qualified Control.Exception  as E
Packit 1d883e
import qualified Control.Concurrent as C
Packit 1d883e
import           Control.Concurrent ( ThreadId )
Packit 1d883e
Packit 1d883e
#if !MIN_VERSION_base(4,4,0)
Packit 1d883e
import Data.Bool ( Bool )
Packit 1d883e
#endif
Packit 1d883e
Packit 1d883e
-- from transformers-base:
Packit 1d883e
import Control.Monad.Base ( MonadBase, liftBase )
Packit 1d883e
Packit 1d883e
-- from monad-control:
Packit 1d883e
import Control.Monad.Trans.Control ( MonadBaseControl, StM
Packit 1d883e
                                   , liftBaseWith, restoreM
Packit 1d883e
                                   , control, liftBaseOp_
Packit 1d883e
                                   )
Packit 1d883e
#if defined (__HADDOCK__)
Packit 1d883e
import Control.Monad.Trans.Control ( liftBaseOp )
Packit 1d883e
#endif
Packit 1d883e
Packit 1d883e
#include "inlinable.h"
Packit 1d883e
Packit 1d883e
--------------------------------------------------------------------------------
Packit 1d883e
-- * Throwing exceptions
Packit 1d883e
--------------------------------------------------------------------------------
Packit 1d883e
Packit 1d883e
-- |Generalized version of 'E.throwIO'.
Packit 1d883e
throwIO :: (MonadBase IO m, Exception e) => e -> m a
Packit 1d883e
throwIO = liftBase . E.throwIO
Packit 1d883e
{-# INLINABLE throwIO #-}
Packit 1d883e
Packit 1d883e
-- |Generalized version of 'E.ioError'.
Packit 1d883e
ioError :: MonadBase IO m => IOError -> m a
Packit 1d883e
ioError = liftBase . E.ioError
Packit 1d883e
{-# INLINABLE ioError #-}
Packit 1d883e
Packit 1d883e
-- | Generalized version of 'C.throwTo'.
Packit 1d883e
throwTo :: (MonadBase IO m, Exception e) => ThreadId -> e -> m ()
Packit 1d883e
throwTo tid e = liftBase $ C.throwTo tid e
Packit 1d883e
{-# INLINABLE throwTo #-}
Packit 1d883e
Packit 1d883e
--------------------------------------------------------------------------------
Packit 1d883e
-- * Catching exceptions
Packit 1d883e
--------------------------------------------------------------------------------
Packit 1d883e
Packit 1d883e
-- |Generalized version of 'E.catch'.
Packit 1d883e
--
Packit 1d883e
-- Note, when the given computation throws an exception any monadic
Packit 1d883e
-- side effects in @m@ will be discarded.
Packit 1d883e
catch :: (MonadBaseControl IO m, Exception e)
Packit 1d883e
      => m a       -- ^ The computation to run
Packit 1d883e
      -> (e -> m a) -- ^ Handler to invoke if an exception is raised
Packit 1d883e
      -> m a
Packit 1d883e
catch a handler = control $ \runInIO ->
Packit 1d883e
                    E.catch (runInIO a)
Packit 1d883e
                            (\e -> runInIO $ handler e)
Packit 1d883e
{-# INLINABLE catch #-}
Packit 1d883e
Packit 1d883e
-- |Generalized version of 'E.catches'.
Packit 1d883e
--
Packit 1d883e
-- Note, when the given computation throws an exception any monadic
Packit 1d883e
-- side effects in @m@ will be discarded.
Packit 1d883e
catches :: MonadBaseControl IO m => m a -> [Handler m a] -> m a
Packit 1d883e
catches a handlers = control $ \runInIO ->
Packit 1d883e
                       E.catches (runInIO a)
Packit 1d883e
                                 [ E.Handler $ \e -> runInIO $ handler e
Packit 1d883e
                                 | Handler handler <- handlers
Packit 1d883e
                                 ]
Packit 1d883e
{-# INLINABLE catches #-}
Packit 1d883e
Packit 1d883e
-- |Generalized version of 'E.Handler'.
Packit 1d883e
data Handler m a = forall e. Exception e => Handler (e -> m a)
Packit 1d883e
Packit 1d883e
-- |Generalized version of 'E.catchJust'.
Packit 1d883e
--
Packit 1d883e
-- Note, when the given computation throws an exception any monadic
Packit 1d883e
-- side effects in @m@ will be discarded.
Packit 1d883e
catchJust :: (MonadBaseControl IO m, Exception e)
Packit 1d883e
          => (e -> Maybe b) -- ^ Predicate to select exceptions
Packit 1d883e
          -> m a           -- ^ Computation to run
Packit 1d883e
          -> (b -> m a)     -- ^ Handler
Packit 1d883e
          -> m a
Packit 1d883e
catchJust p a handler = control $ \runInIO ->
Packit 1d883e
                          E.catchJust p
Packit 1d883e
                                      (runInIO a)
Packit 1d883e
                                      (\e -> runInIO (handler e))
Packit 1d883e
{-# INLINABLE catchJust #-}
Packit 1d883e
Packit 1d883e
Packit 1d883e
--------------------------------------------------------------------------------
Packit 1d883e
--  ** The @handle@ functions
Packit 1d883e
--------------------------------------------------------------------------------
Packit 1d883e
Packit 1d883e
-- |Generalized version of 'E.handle'.
Packit 1d883e
--
Packit 1d883e
-- Note, when the given computation throws an exception any monadic
Packit 1d883e
-- side effects in @m@ will be discarded.
Packit 1d883e
handle :: (MonadBaseControl IO m, Exception e) => (e -> m a) -> m a -> m a
Packit 1d883e
handle handler a = control $ \runInIO ->
Packit 1d883e
                     E.handle (\e -> runInIO (handler e))
Packit 1d883e
                              (runInIO a)
Packit 1d883e
{-# INLINABLE handle #-}
Packit 1d883e
Packit 1d883e
-- |Generalized version of 'E.handleJust'.
Packit 1d883e
--
Packit 1d883e
-- Note, when the given computation throws an exception any monadic
Packit 1d883e
-- side effects in @m@ will be discarded.
Packit 1d883e
handleJust :: (MonadBaseControl IO m, Exception e)
Packit 1d883e
           => (e -> Maybe b) -> (b -> m a) -> m a -> m a
Packit 1d883e
handleJust p handler a = control $ \runInIO ->
Packit 1d883e
                           E.handleJust p (\e -> runInIO (handler e))
Packit 1d883e
                                          (runInIO a)
Packit 1d883e
{-# INLINABLE handleJust #-}
Packit 1d883e
Packit 1d883e
--------------------------------------------------------------------------------
Packit 1d883e
-- ** The @try@ functions
Packit 1d883e
--------------------------------------------------------------------------------
Packit 1d883e
Packit 1d883e
sequenceEither :: MonadBaseControl IO m => Either e (StM m a) -> m (Either e a)
Packit 1d883e
sequenceEither = either (return . Left) (liftM Right . restoreM)
Packit 1d883e
{-# INLINE sequenceEither #-}
Packit 1d883e
Packit 1d883e
-- |Generalized version of 'E.try'.
Packit 1d883e
--
Packit 1d883e
-- Note, when the given computation throws an exception any monadic
Packit 1d883e
-- side effects in @m@ will be discarded.
Packit 1d883e
try :: (MonadBaseControl IO m, Exception e) => m a -> m (Either e a)
Packit 1d883e
try m = liftBaseWith (\runInIO -> E.try (runInIO m)) >>= sequenceEither
Packit 1d883e
{-# INLINABLE try #-}
Packit 1d883e
Packit 1d883e
-- |Generalized version of 'E.tryJust'.
Packit 1d883e
--
Packit 1d883e
-- Note, when the given computation throws an exception any monadic
Packit 1d883e
-- side effects in @m@ will be discarded.
Packit 1d883e
tryJust :: (MonadBaseControl IO m, Exception e) => (e -> Maybe b) -> m a -> m (Either b a)
Packit 1d883e
tryJust p m = liftBaseWith (\runInIO -> E.tryJust p (runInIO m)) >>= sequenceEither
Packit 1d883e
{-# INLINABLE tryJust #-}
Packit 1d883e
Packit 1d883e
Packit 1d883e
--------------------------------------------------------------------------------
Packit 1d883e
-- ** The @evaluate@ function
Packit 1d883e
--------------------------------------------------------------------------------
Packit 1d883e
Packit 1d883e
-- |Generalized version of 'E.evaluate'.
Packit 1d883e
evaluate :: MonadBase IO m => a -> m a
Packit 1d883e
evaluate = liftBase . E.evaluate
Packit 1d883e
{-# INLINABLE evaluate #-}
Packit 1d883e
Packit 1d883e
Packit 1d883e
--------------------------------------------------------------------------------
Packit 1d883e
-- ** Asynchronous exception control
Packit 1d883e
--------------------------------------------------------------------------------
Packit 1d883e
Packit 1d883e
#if MIN_VERSION_base(4,3,0)
Packit 1d883e
-- |Generalized version of 'E.mask'.
Packit 1d883e
mask :: MonadBaseControl IO m => ((forall a. m a -> m a) -> m b) -> m b
Packit 1d883e
mask f = control $ \runInBase ->
Packit 1d883e
           E.mask $ \g -> runInBase $ f $ liftBaseOp_ g
Packit 1d883e
{-# INLINABLE mask #-}
Packit 1d883e
Packit 1d883e
-- |Generalized version of 'E.mask_'.
Packit 1d883e
mask_ :: MonadBaseControl IO m => m a -> m a
Packit 1d883e
mask_ = liftBaseOp_ E.mask_
Packit 1d883e
{-# INLINABLE mask_ #-}
Packit 1d883e
Packit 1d883e
-- |Generalized version of 'E.uninterruptibleMask'.
Packit 1d883e
uninterruptibleMask
Packit 1d883e
    :: MonadBaseControl IO m => ((forall a. m a -> m a) -> m b) -> m b
Packit 1d883e
uninterruptibleMask f =
Packit 1d883e
    control $ \runInBase ->
Packit 1d883e
        E.uninterruptibleMask $ \g -> runInBase $ f $ liftBaseOp_ g
Packit 1d883e
Packit 1d883e
{-# INLINABLE uninterruptibleMask #-}
Packit 1d883e
Packit 1d883e
-- |Generalized version of 'E.uninterruptibleMask_'.
Packit 1d883e
uninterruptibleMask_ :: MonadBaseControl IO m => m a -> m a
Packit 1d883e
uninterruptibleMask_ = liftBaseOp_ E.uninterruptibleMask_
Packit 1d883e
{-# INLINABLE uninterruptibleMask_ #-}
Packit 1d883e
Packit 1d883e
-- |Generalized version of 'E.getMaskingState'.
Packit 1d883e
getMaskingState :: MonadBase IO m => m MaskingState
Packit 1d883e
getMaskingState = liftBase E.getMaskingState
Packit 1d883e
{-# INLINABLE getMaskingState #-}
Packit 1d883e
Packit 1d883e
#if MIN_VERSION_base(4,4,0)
Packit 1d883e
-- |Generalized version of 'E.allowInterrupt'.
Packit 1d883e
allowInterrupt :: MonadBase IO m => m ()
Packit 1d883e
allowInterrupt = liftBase E.allowInterrupt
Packit 1d883e
{-# INLINABLE allowInterrupt #-}
Packit 1d883e
#endif
Packit 1d883e
#else
Packit 1d883e
-- |Generalized version of 'E.block'.
Packit 1d883e
block :: MonadBaseControl IO m => m a -> m a
Packit 1d883e
block = liftBaseOp_ E.block
Packit 1d883e
{-# INLINABLE block #-}
Packit 1d883e
Packit 1d883e
-- |Generalized version of 'E.unblock'.
Packit 1d883e
unblock :: MonadBaseControl IO m => m a -> m a
Packit 1d883e
unblock = liftBaseOp_ E.unblock
Packit 1d883e
{-# INLINABLE unblock #-}
Packit 1d883e
#endif
Packit 1d883e
Packit 1d883e
#if !MIN_VERSION_base(4,4,0)
Packit 1d883e
-- | Generalized version of 'E.blocked'.
Packit 1d883e
-- returns @True@ if asynchronous exceptions are blocked in the
Packit 1d883e
-- current thread.
Packit 1d883e
blocked :: MonadBase IO m => m Bool
Packit 1d883e
blocked = liftBase E.blocked
Packit 1d883e
{-# INLINABLE blocked #-}
Packit 1d883e
#endif
Packit 1d883e
Packit 1d883e
Packit 1d883e
--------------------------------------------------------------------------------
Packit 1d883e
-- * Brackets
Packit 1d883e
--------------------------------------------------------------------------------
Packit 1d883e
Packit 1d883e
-- |Generalized version of 'E.bracket'.
Packit 1d883e
--
Packit 1d883e
-- Note:
Packit 1d883e
--
Packit 1d883e
-- * When the \"acquire\" or \"release\" computations throw exceptions
Packit 1d883e
--   any monadic side effects in @m@ will be discarded.
Packit 1d883e
--
Packit 1d883e
-- * When the \"in-between\" computation throws an exception any
Packit 1d883e
--   monadic side effects in @m@ produced by that computation will be
Packit 1d883e
--   discarded but the side effects of the \"acquire\" or \"release\"
Packit 1d883e
--   computations will be retained.
Packit 1d883e
--
Packit 1d883e
-- * Also, any monadic side effects in @m@ of the \"release\"
Packit 1d883e
--   computation will be discarded; it is run only for its side
Packit 1d883e
--   effects in @IO@.
Packit 1d883e
--
Packit 1d883e
-- Note that when your @acquire@ and @release@ computations are of type 'IO'
Packit 1d883e
-- it will be more efficient to write:
Packit 1d883e
--
Packit 1d883e
-- @'liftBaseOp' ('E.bracket' acquire release)@
Packit 1d883e
bracket :: MonadBaseControl IO m
Packit 1d883e
        => m a       -- ^ computation to run first (\"acquire resource\")
Packit 1d883e
        -> (a -> m b) -- ^ computation to run last (\"release resource\")
Packit 1d883e
        -> (a -> m c) -- ^ computation to run in-between
Packit 1d883e
        -> m c
Packit 1d883e
bracket before after thing = control $ \runInIO ->
Packit 1d883e
                               E.bracket (runInIO before)
Packit 1d883e
                                         (\st -> runInIO $ restoreM st >>= after)
Packit 1d883e
                                         (\st -> runInIO $ restoreM st >>= thing)
Packit 1d883e
{-# INLINABLE bracket #-}
Packit 1d883e
Packit 1d883e
-- |Generalized version of 'E.bracket_'.
Packit 1d883e
--
Packit 1d883e
-- Note any monadic side effects in @m@ of /both/ the \"acquire\" and
Packit 1d883e
-- \"release\" computations will be discarded. To keep the monadic
Packit 1d883e
-- side effects of the \"acquire\" computation, use 'bracket' with
Packit 1d883e
-- constant functions instead.
Packit 1d883e
--
Packit 1d883e
-- Note that when your @acquire@ and @release@ computations are of type 'IO'
Packit 1d883e
-- it will be more efficient to write:
Packit 1d883e
--
Packit 1d883e
-- @'liftBaseOp_' ('E.bracket_' acquire release)@
Packit 1d883e
bracket_ :: MonadBaseControl IO m
Packit 1d883e
         => m a -- ^ computation to run first (\"acquire resource\")
Packit 1d883e
         -> m b -- ^ computation to run last (\"release resource\")
Packit 1d883e
         -> m c -- ^ computation to run in-between
Packit 1d883e
         -> m c
Packit 1d883e
bracket_ before after thing = control $ \runInIO ->
Packit 1d883e
                                E.bracket_ (runInIO before)
Packit 1d883e
                                           (runInIO after)
Packit 1d883e
                                           (runInIO thing)
Packit 1d883e
{-# INLINABLE bracket_ #-}
Packit 1d883e
Packit 1d883e
-- |Generalized version of 'E.bracketOnError'.
Packit 1d883e
--
Packit 1d883e
-- Note:
Packit 1d883e
--
Packit 1d883e
-- * When the \"acquire\" or \"release\" computations throw exceptions
Packit 1d883e
--   any monadic side effects in @m@ will be discarded.
Packit 1d883e
--
Packit 1d883e
-- * When the \"in-between\" computation throws an exception any
Packit 1d883e
--   monadic side effects in @m@ produced by that computation will be
Packit 1d883e
--   discarded but the side effects of the \"acquire\" computation
Packit 1d883e
--   will be retained.
Packit 1d883e
--
Packit 1d883e
-- * Also, any monadic side effects in @m@ of the \"release\"
Packit 1d883e
--   computation will be discarded; it is run only for its side
Packit 1d883e
--   effects in @IO@.
Packit 1d883e
--
Packit 1d883e
-- Note that when your @acquire@ and @release@ computations are of
Packit 1d883e
-- type 'IO' it will be more efficient to write:
Packit 1d883e
--
Packit 1d883e
-- @'liftBaseOp' ('E.bracketOnError' acquire release)@
Packit 1d883e
bracketOnError :: MonadBaseControl IO m
Packit 1d883e
               => m a       -- ^ computation to run first (\"acquire resource\")
Packit 1d883e
               -> (a -> m b) -- ^ computation to run last (\"release resource\")
Packit 1d883e
               -> (a -> m c) -- ^ computation to run in-between
Packit 1d883e
               -> m c
Packit 1d883e
bracketOnError before after thing =
Packit 1d883e
    control $ \runInIO ->
Packit 1d883e
      E.bracketOnError (runInIO before)
Packit 1d883e
                       (\st -> runInIO $ restoreM st >>= after)
Packit 1d883e
                       (\st -> runInIO $ restoreM st >>= thing)
Packit 1d883e
{-# INLINABLE bracketOnError #-}
Packit 1d883e
Packit 1d883e
Packit 1d883e
--------------------------------------------------------------------------------
Packit 1d883e
-- * Utilities
Packit 1d883e
--------------------------------------------------------------------------------
Packit 1d883e
Packit 1d883e
-- |Generalized version of 'E.finally'.
Packit 1d883e
--
Packit 1d883e
-- Note, any monadic side effects in @m@ of the \"afterward\"
Packit 1d883e
-- computation will be discarded.
Packit 1d883e
finally :: MonadBaseControl IO m
Packit 1d883e
        => m a -- ^ computation to run first
Packit 1d883e
        -> m b -- ^ computation to run afterward (even if an exception was raised)
Packit 1d883e
        -> m a
Packit 1d883e
finally a sequel = control $ \runInIO ->
Packit 1d883e
                     E.finally (runInIO a)
Packit 1d883e
                               (runInIO sequel)
Packit 1d883e
{-# INLINABLE finally #-}
Packit 1d883e
Packit 1d883e
-- |Generalized version of 'E.onException'.
Packit 1d883e
--
Packit 1d883e
-- Note, any monadic side effects in @m@ of the \"afterward\"
Packit 1d883e
-- computation will be discarded.
Packit 1d883e
onException :: MonadBaseControl IO m => m a -> m b -> m a
Packit 1d883e
onException m what = control $ \runInIO ->
Packit 1d883e
                       E.onException (runInIO m)
Packit 1d883e
                                     (runInIO what)
Packit 1d883e
{-# INLINABLE onException #-}