monad-peel-0.1: Control/Exception/Peel.hs
{-# LANGUAGE ExistentialQuantification #-}
{- |
Module : Control.Exception.Peel
Copyright : © Anders Kaseorg, 2010
License : BSD-style
Maintainer : Anders Kaseorg <andersk@mit.edu>
Stability : experimental
Portability : non-portable (extended exceptions)
This is a wrapped version of Control.Exception with types generalized
from 'IO' to all monads in 'MonadPeelIO'.
-}
module Control.Exception.Peel (
module Control.Exception.Extensible,
throwIO, ioError,
catch, catches, Handler(..), catchJust,
handle, handleJust,
try, tryJust,
evaluate,
block, unblock,
bracket, bracket_, bracketOnError,
finally, onException,
) where
import Prelude hiding (catch, ioError)
import Control.Monad
import Control.Monad.IO.Class
import Control.Monad.IO.Peel
import Control.Exception.Extensible hiding (
throwIO, ioError,
catch, catches, Handler(..), catchJust,
handle, handleJust,
try, tryJust,
evaluate,
block, unblock,
bracket, bracket_, bracketOnError,
finally, onException,
)
import qualified Control.Exception.Extensible as E
-- |Generalized version of 'E.throwIO'.
throwIO :: (MonadIO m, Exception e) => e -> m a
throwIO = liftIO . E.throwIO
-- |Generalized version of 'E.ioError'.
ioError :: MonadIO m => IOError -> m a
ioError = liftIO . E.ioError
-- |Generalized version of 'E.catch'.
catch :: (MonadPeelIO m, Exception e) =>
m a -- ^ The computation to run
-> (e -> m a) -- ^ Handler to invoke if an exception is raised
-> m a
catch a handler = do
k <- peelIO
join $ liftIO $ E.catch (k a) (\e -> k $ handler e)
-- |Generalized version of 'E.catchJust'.
catchJust :: (MonadPeelIO m, Exception e) =>
(e -> Maybe b) -- ^ Predicate to select exceptions
-> m a -- ^ Computation to run
-> (b -> m a) -- ^ Handler
-> m a
catchJust p a handler = do
k <- peelIO
join $ liftIO $ E.catchJust p (k a) (\e -> k (handler e))
-- |Generalized version of 'E.catches'.
catches :: MonadPeelIO m => m a -> [Handler m a] -> m a
catches a handlers = do
k <- peelIO
join $ liftIO $ E.catches (k a) [E.Handler $ \e -> k $ handler e |
Handler handler <- handlers]
-- |Generalized version of 'E.Handler'.
data Handler m a = forall e. Exception e => Handler (e -> m a)
-- |Generalized version of 'E.handle'.
handle :: (MonadPeelIO m, Exception e) => (e -> m a) -> m a -> m a
handle handler a = do
k <- peelIO
join $ liftIO $ E.handle (\e -> k (handler e)) (k a)
-- |Generalized version of 'E.handleJust'.
handleJust :: (MonadPeelIO m, Exception e) =>
(e -> Maybe b) -> (b -> m a) -> m a -> m a
handleJust p handler a = do
k <- peelIO
join $ liftIO $ E.handleJust p (\e -> k (handler e)) (k a)
sequenceEither :: Monad m => Either e (m a) -> m (Either e a)
sequenceEither (Left e) = return $ Left e
sequenceEither (Right m) = liftM Right m
-- |Generalized version of 'E.try'.
try :: (MonadPeelIO m, Exception e) => m a -> m (Either e a)
try = liftIOOp_ (liftM sequenceEither . E.try)
-- |Generalized version of 'E.tryJust'.
tryJust :: (MonadPeelIO m, Exception e) =>
(e -> Maybe b) -> m a -> m (Either b a)
tryJust p = liftIOOp_ (liftM sequenceEither . E.tryJust p)
-- |Generalized version of 'E.evaluate'.
evaluate :: MonadIO m => a -> m a
evaluate = liftIO . E.evaluate
-- |Generalized version of 'E.block'.
block :: MonadPeelIO m => m a -> m a
block = liftIOOp_ E.block
-- |Generalized version of 'E.unblock'.
unblock :: MonadPeelIO m => m a -> m a
unblock = liftIOOp_ E.unblock
-- |Generalized version of 'E.bracket'. Note, any monadic side
-- effects in @m@ of the \"release\" computation will be discarded; it
-- is run only for its side effects in @IO@.
bracket :: MonadPeelIO m =>
m a -- ^ computation to run first (\"acquire resource\")
-> (a -> m b) -- ^ computation to run last (\"release resource\")
-> (a -> m c) -- ^ computation to run in-between
-> m c
bracket before after thing = do
k <- peelIO
k' <- peelIO
k'' <- peelIO
join $ liftIO $
E.bracket (k before) (\x -> k' $ x >>= after) (\x -> k'' $ x >>= thing)
-- |Generalized version of 'E.bracket_'. Note, any monadic side
-- effects in @m@ of /both/ the \"acquire\" and \"release\"
-- computations will be discarded. To keep the monadic side effects
-- of the \"acquire\" computation, use 'bracket' with constant
-- functions instead.
bracket_ :: MonadPeelIO m => m a -> m b -> m c -> m c
bracket_ before after thing = do
k <- peelIO
k' <- peelIO
k'' <- peelIO
join $ liftIO $ E.bracket_ (k before) (k' after) (k'' thing)
-- |Generalized version of 'E.bracketOnError'. Note, any monadic side
-- effects in @m@ of the \"release\" computation will be discarded.
bracketOnError :: MonadPeelIO m =>
m a -- ^ computation to run first (\"acquire resource\")
-> (a -> m b) -- ^ computation to run last (\"release resource\")
-> (a -> m c) -- ^ computation to run in-between
-> m c
bracketOnError before after thing = do
k <- peelIO
k' <- peelIO
k'' <- peelIO
join $ liftIO $
E.bracket (k before) (\x -> k' $ x >>= after) (\x -> k'' $ x >>= thing)
-- |Generalized version of 'E.finally'. Note, any monadic side
-- effects in @m@ of the \"afterward\" computation will be discarded.
finally :: MonadPeelIO m =>
m a -- ^ computation to run first
-> m b -- ^ computation to run afterward (even if an exception was raised)
-> m a
finally a sequel = do
k <- peelIO
k' <- peelIO
join $ liftIO $ E.finally (k a) (k' sequel)
-- |Generalized version of 'E.onException'. Note, any monadic side
-- effects in @m@ of the \"afterward\" computation will be discarded.
onException :: MonadPeelIO m => m a -> m b -> m a
onException m what = do
k <- peelIO
k' <- peelIO
join $ liftIO $ E.onException (k m) (k' what)