module Control.Effect.ErrorIO ( -- * Effects ErrorIO(..) , X.Exception(..) , SomeException -- * Actions , throwIO , catchIO -- * Interpretations , errorIOToIO , errorIOToError -- * MonadCatch , C.MonadCatch -- * Carriers , ErrorIOToIOC , ErrorIOToErrorC ) where import Control.Monad import Control.Effect import Control.Effect.Optional import Control.Effect.Type.ErrorIO import Control.Effect.Type.Throw import Control.Effect.Type.Catch import Control.Exception (SomeException) import qualified Control.Exception as X import qualified Control.Monad.Catch as C -- For coercion purposes import Control.Monad.Trans.Identity import Control.Effect.Carrier.Internal.Intro import Control.Effect.Carrier.Internal.Compose import Control.Effect.Carrier.Internal.Interpret import Control.Effect.Internal.Utils throwIO :: (X.Exception e, Eff ErrorIO m) => e -> m a throwIO = send . ThrowIO catchIO :: (X.Exception e, Eff ErrorIO m) => m a -> (e -> m a) -> m a catchIO m h = send (CatchIO m h) data ErrorIOFinalH data ErrorIOToErrorH instance ( C.MonadThrow m , Eff (Optional ((->) SomeException)) m ) => Handler ErrorIOFinalH ErrorIO m where effHandler = \case ThrowIO x -> liftBase $ C.throwM x CatchIO m h -> join $ optionally (\x -> case X.fromException x of Just e -> h e Nothing -> liftBase $ C.throwM x ) (fmap pure m) {-# INLINEABLE effHandler #-} instance ( C.MonadCatch m , Carrier m ) => PrimHandler ErrorIOFinalH (Optional ((->) SomeException)) m where effPrimHandler = \case Optionally h m -> m `C.catch` (return . h) {-# INLINEABLE effPrimHandler #-} instance ( Eff (Error SomeException) m , Carrier m ) => Handler ErrorIOToErrorH ErrorIO m where effHandler = \case ThrowIO e -> send $ Throw (X.toException e) CatchIO m h -> send $ Catch m $ \e -> case X.fromException e of Just e' -> h e' _ -> send $ Throw e {-# INLINEABLE effHandler #-} type ErrorIOToIOC = CompositionC '[ ReinterpretC ErrorIOFinalH ErrorIO '[Optional ((->) SomeException)] , InterpretPrimC ErrorIOFinalH (Optional ((->) SomeException)) ] type ErrorIOToErrorC = InterpretC ErrorIOToErrorH ErrorIO -- | Transform an @'ErrorIO'@ effect into an @'Error' 'SomeException'@ -- effect. errorIOToError :: Eff (Error SomeException) m => ErrorIOToErrorC m a -> m a errorIOToError = interpretViaHandler {-# INLINE errorIOToError #-} -- | Run an @'ErrorIO'@ effect by making use of 'IO' exceptions. -- -- @'Derivs' (ErrorIOToIOC e m) = 'ErrorIO' ': 'Derivs' m@ -- -- @'Control.Effect.Carrier.Prims' (ErrorIOToIOC e m) = 'Control.Effect.Optional.Optional' ((->) 'SomeException') ': 'Control.Effect.Carrier.Prims' m@ errorIOToIO :: (Carrier m, C.MonadCatch m) => ErrorIOToIOC m a -> m a errorIOToIO = interpretPrimViaHandler .# reinterpretViaHandler .# runComposition {-# INLINE errorIOToIO #-}