{-# LANGUAGE BlockArguments, DerivingVia #-}
module Control.Effect.Fail
(
Fail(..)
, runFail
, failToThrow
, failToNonDet
, failToAlt
, failToThrowSimple
, ErrorThreads
, FailC
, InterpretFailC(..)
, InterpretFailReifiedC
, FailToNonDetC
, FailToAltC
, InterpretFailSimpleC(..)
) where
import Data.Coerce
import Control.Applicative
import Control.Monad
import qualified Control.Monad.Fail as Fail
import Control.Effect
import Control.Effect.Error
import Control.Effect.NonDet
import Control.Effect.Type.Alt
import Control.Effect.Type.Fail
import Control.Effect.Carrier
import Control.Effect.Internal.Utils
import Control.Effect.Carrier.Internal.Interpret
import Control.Effect.Carrier.Internal.Intro
import Control.Effect.Carrier.Internal.Compose
import Control.Monad.Trans.Identity
newtype InterpretFailC h m a = InterpretFailC {
unInterpretFailC :: InterpretC h Fail m a
}
deriving ( Functor, Applicative, Monad
, Alternative, MonadPlus
, MonadFix, MonadIO
, MonadThrow, MonadCatch, MonadMask
, MonadBase b, MonadBaseControl b
)
deriving (MonadTrans, MonadTransControl) via IdentityT
type InterpretFailReifiedC m a
= forall s
. ReifiesHandler s Fail m
=> InterpretFailC (ViaReifiedH s) m a
deriving via InterpretC h Fail m instance
Handler h Fail m => Carrier (InterpretFailC h m)
deriving via Effly (InterpretFailC h m)
instance Handler h Fail m
=> MonadFail (InterpretFailC h m)
failToThrow :: Eff (Throw e) m
=> (String -> e)
-> InterpretFailReifiedC m a
-> m a
failToThrow f m =
interpret \case
Fail s -> throw (f s)
$ unInterpretFailC
$ m
{-# INLINE failToThrow #-}
data FailToAltH
type FailToAltC = InterpretFailC FailToAltH
instance Eff Alt m => Handler FailToAltH Fail m where
effHandler _ = runEffly empty
{-# INLINEABLE effHandler #-}
data FailToNonDetH
instance Eff NonDet m => Handler FailToNonDetH Fail m where
effHandler _ = lose
{-# INLINEABLE effHandler #-}
type FailToNonDetC = InterpretFailC FailToNonDetH
failToAlt :: Eff Alt m
=> FailToAltC m a
-> m a
failToAlt = interpretViaHandler .# unInterpretFailC
{-# INLINE failToAlt #-}
failToNonDet :: Eff NonDet m
=> FailToNonDetC m a
-> m a
failToNonDet = interpretViaHandler .# unInterpretFailC
{-# INLINE failToNonDet #-}
data FailH
type FailC = CompositionC
'[ ReinterpretC FailH Fail '[Throw String]
, ThrowC String
]
instance Eff (Throw String) m
=> Handler FailH Fail m where
effHandler = throw @String .# coerce
{-# INLINEABLE effHandler #-}
runFail :: forall m a p
. ( Threaders '[ErrorThreads] m p
, Carrier m
)
=> FailC m a
-> m (Either String a)
runFail =
runThrow
.# reinterpretViaHandler
.# runComposition
newtype InterpretFailSimpleC m a = InterpretFailSimpleC {
unInterpretFailSimpleC :: InterpretSimpleC Fail m a
}
deriving ( Functor, Applicative, Monad
, Alternative, MonadPlus
, MonadFix, MonadIO
, MonadThrow, MonadCatch, MonadMask
, MonadBase b, MonadBaseControl b
)
deriving MonadTrans
deriving newtype instance
(Monad m, Carrier (InterpretSimpleC Fail m))
=> Carrier (InterpretFailSimpleC m)
instance (Monad m, Carrier (InterpretSimpleC Fail m))
=> Fail.MonadFail (InterpretFailSimpleC m) where
fail = send .# Fail
{-# INLINE fail #-}
failToThrowSimple :: forall e m a p
. ( Eff (Throw e) m
, Threaders '[ReaderThreads] m p
)
=> (String -> e)
-> InterpretFailSimpleC m a
-> m a
failToThrowSimple f =
interpretSimple \case
Fail s -> throw (f s)
.# unInterpretFailSimpleC
{-# INLINE failToThrowSimple #-}