packages feed

exceptiot-0.0.1.1: src/Control/Monad/Except/Catch.hs

{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE MultiParamTypeClasses #-}

module Control.Monad.Except.Catch
    ( ExceptCatchT (..)
    , runExceptCatchT
    , module Control.Monad.Error.Class
    , modifyError
    ) where

import Control.Applicative
import Control.Monad
import Control.Monad.Catch
import Control.Monad.Error.Class hiding (modifyError)
import Control.Monad.Fix
import Control.Monad.IO.Unlift
import Control.Monad.Reader
import Control.Monad.State
import Control.Monad.Writer

-- | This type is useful for translating a 'MonadError' constraint into
-- 'MonadCatch'. This type does not have an 'Either' return, which means we can
-- provide a 'MonadUnliftIO' instance.
--
-- @since 0.1.0.0
newtype ExceptCatchT e m a = ExceptCatchT { unsafeRunExceptCatchT :: m a }
    deriving newtype
        ( Functor, Applicative, Monad, MonadIO, MonadPlus, Alternative
        , Semigroup, Monoid, MonadUnliftIO, MonadReader r, MonadState s
        , MonadWriter w , MonadFix, MonadFail, MonadThrow, MonadCatch, MonadMask
        )

-- |
--
-- @since 0.1.0.0
instance (MonadCatch m, Exception e) => MonadError e (ExceptCatchT e m) where
    throwError = throwM
    catchError = catch

-- | Run an 'ExceptCatchT' action. This will catch any thrown @e@ exceptions,
-- regardless of whether you used 'throwM' or 'throwError'.
--
-- Any exception that is not mentioned in @e@ will be thrown - this does not
-- catch all exceptions!
--
-- @since 0.1.0.0
runExceptCatchT :: (Exception e, MonadCatch m) => ExceptCatchT e m a -> m (Either e a)
runExceptCatchT = try . unsafeRunExceptCatchT

-- | Like 'Control.Monad.Except.modifyError', but it selects the 'ExceptCatchT' instance for 'IO'
-- exceptions instead of the 'ExceptT' instance with an 'Either' error.
--
-- @since 0.1.0.0
modifyError
    :: (Exception e, MonadCatch m, MonadError e' m)
    => (e -> e') -> ExceptCatchT e m a -> m a
modifyError f action =
    runExceptCatchT action >>= either (throwError . f) pure