module Control.Effect.ErrorIO
(
ErrorIO(..)
, X.Exception(..)
, SomeException
, throwIO
, catchIO
, errorIOToIO
, errorIOToError
, C.MonadCatch
, 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
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
errorIOToError :: Eff (Error SomeException) m
=> ErrorIOToErrorC m a
-> m a
errorIOToError = interpretViaHandler
{-# INLINE errorIOToError #-}
errorIOToIO :: (Carrier m, C.MonadCatch m)
=> ErrorIOToIOC m a
-> m a
errorIOToIO =
interpretPrimViaHandler
.# reinterpretViaHandler
.# runComposition
{-# INLINE errorIOToIO #-}