{-# LANGUAGE BlockArguments, DerivingVia #-}
module Control.Effect.Alt
(
Alt(..)
, Alternative(..)
, runAltMaybe
, altToError
, altToNonDet
, altToErrorSimple
, ErrorThreads
, AltMaybeC
, InterpretAltC(..)
, InterpretAltReifiedC
, AltToNonDetC
, InterpretAltSimpleC(..)
) where
import Control.Applicative
import Control.Monad
import Control.Effect
import Control.Effect.Carrier
import Control.Effect.Error
import Control.Effect.NonDet
import Control.Effect.Type.Alt
import Control.Effect.Internal.Utils
import Control.Effect.Internal.Error
import Control.Effect.Carrier.Internal.Compose
import Control.Effect.Carrier.Internal.Interpret
import Control.Effect.Carrier.Internal.Intro
import Control.Monad.Trans.Except
import Control.Monad.Trans.Identity
newtype InterpretAltC h m a = InterpretAltC {
unInterpretAltC :: InterpretC h Alt m a
}
deriving ( Functor, Applicative, Monad
, MonadFix, MonadIO, MonadFail
, MonadThrow, MonadCatch, MonadMask
, MonadBase b, MonadBaseControl b
)
deriving (MonadTrans, MonadTransControl)
newtype InterpretAltSimpleC m a = InterpretAltSimpleC {
unInterpretAltSimpleC :: InterpretSimpleC Alt m a
}
deriving ( Functor, Applicative, Monad
, MonadFix, MonadIO, MonadFail
, MonadThrow, MonadCatch, MonadMask
, MonadBase b, MonadBaseControl b
)
deriving MonadTrans
type InterpretAltReifiedC m a =
forall s
. ReifiesHandler s Alt m
=> InterpretAltC (ViaReifiedH s) m a
deriving newtype instance Handler h Alt m => Carrier (InterpretAltC h m)
deriving via Effly (InterpretAltC h m)
instance Handler h Alt m => Alternative (InterpretAltC h m)
instance Handler h Alt m => MonadPlus (InterpretAltC h m)
deriving newtype instance
(Monad m, Carrier (InterpretSimpleC Alt m))
=> Carrier (InterpretAltSimpleC m)
deriving via Effly (InterpretAltSimpleC m)
instance (Monad m, Carrier (InterpretSimpleC Alt m))
=> Alternative (InterpretAltSimpleC m)
instance (Monad m, Carrier (InterpretSimpleC Alt m))
=> MonadPlus (InterpretAltSimpleC m)
data AltToErrorUnitH
instance Eff (Error ()) m
=> Handler AltToErrorUnitH Alt m where
effHandler = \case
Empty -> throw ()
Alt ma mb -> ma `catch` \() -> mb
{-# INLINEABLE effHandler #-}
type AltMaybeC = CompositionC
'[ IntroUnderC Alt '[Catch (), Throw ()]
, InterpretAltC AltToErrorUnitH
, ErrorC ()
]
runAltMaybe :: forall m a p
. ( Threaders '[ErrorThreads] m p
, Carrier m
)
=> AltMaybeC m a
-> m (Maybe a)
runAltMaybe =
fmap (either (const Nothing) Just)
.# runError
.# interpretViaHandler
.# unInterpretAltC
.# introUnder
.# runComposition
{-# INLINE runAltMaybe #-}
altToError :: forall e m a
. Eff (Error e) m
=> e
-> InterpretAltReifiedC m a
-> m a
altToError e m =
interpret \case
Empty -> throw e
Alt ma mb -> ma `catch` \(_ :: e) -> mb
$ unInterpretAltC
$ m
{-# INLINE altToError #-}
data AltToNonDetH
instance Eff NonDet m => Handler AltToNonDetH Alt m where
effHandler = \case
Empty -> lose
Alt ma mb -> choose ma mb
{-# INLINEABLE effHandler #-}
type AltToNonDetC = InterpretAltC AltToNonDetH
altToNonDet :: Eff NonDet m
=> AltToNonDetC m a
-> m a
altToNonDet = interpretViaHandler .# unInterpretAltC
{-# INLINE altToNonDet #-}
altToErrorSimple :: forall e m a p
. ( Eff (Error e) m
, Threaders '[ReaderThreads] m p
)
=> e
-> InterpretAltSimpleC m a
-> m a
altToErrorSimple e =
interpretSimple \case
Empty -> throw e
Alt ma mb -> ma `catch` \(_ :: e) -> mb
.# unInterpretAltSimpleC
{-# INLINE altToErrorSimple #-}