module Control.Monad.Exception.Class
(
MonadException (..)
)
where
import Control.Exception (Exception, SomeException (..))
import qualified Control.Exception as E
import Control.Monad.Base (liftBase)
import Control.Monad.IO.Class (MonadIO (..))
import Control.Monad.Trans.Class (MonadTrans (..))
import Control.Monad.Trans.Control
( MonadBaseControl (..)
, MonadTransControl (..)
, Run
, control
)
import Prelude hiding (catch)
class Monad m => MonadException m where
throw :: Exception e => e -> m a
catch :: Exception e => m a -> (e -> m a) -> m a
bracket :: m a -> (a -> m b) -> (a -> m c) -> m c
bracket open close thing = do
a <- open
b <- thing a `catch` \e@(SomeException _) -> close a >> throw e
close a
return b
instance MonadException (Either SomeException) where
throw = Left . E.toException
catch m h = either (\e -> maybe (Left e) h (E.fromException e)) Right m
instance MonadException IO where
throw = E.throwIO
catch = E.catch
bracket = E.bracket
instance (MonadException b, MonadBaseControl b m) => MonadException m where
throw = liftBase . throw
catch m h = control $ \run -> catch (run m) (run . h)
bracket a b c = control $ \run -> bracket (run a)
(\a' -> run $ restoreM a' >>= b)
(\a' -> run $ restoreM a' >>= c)
instance (MonadTransControl t, Monad (t m), MonadException m) => MonadException (t m) where
throw = lift . throw
catch m h = controlT $ \run -> catch (run m) (run . h)
bracket a b c = controlT $ \run -> bracket (run a)
(\a' -> run $ restoreT (return a') >>= b)
(\a' -> run $ restoreT (return a') >>= c)
controlT
:: (Monad m, Monad (t m), MonadTransControl t)
=> (Run t -> m (StT t a))
-> t m a
controlT f = liftWith f >>= restoreT . return