module Fx.EitherEffect
(
  EitherEffect,
  liftEffect1,
  liftEffect2,
  executor,
)
where

import Fx.Prelude
import qualified Fx.Executor as A


{-|
A sum of two effects (@effect1@ and @effect2@) to be executed
in @context@ producing @result@.
-}
newtype EitherEffect effect1 effect2 context result =
  EitherEffect (ReaderT (A.Executor effect1 context, A.Executor effect2 context) context result)
  deriving (Functor, Applicative, Alternative, Monad, MonadPlus, MonadIO)

instance MonadTrans (EitherEffect effect1 effect2) where
  lift =
    EitherEffect . lift

{-|
Lift the first of the two effects.
-}
liftEffect1 :: effect1 result -> EitherEffect effect1 effect2 context result
liftEffect1 effect =
  EitherEffect (ReaderT (\(executor, _) -> A.execute executor effect))

{-|
Lift the second of the two effects.
-}
liftEffect2 :: effect2 result -> EitherEffect effect1 effect2 context result
liftEffect2 effect =
  EitherEffect (ReaderT (\(_, executor) -> A.execute executor effect))

{-|
Compose the executors of each effect into an executor of either.
-}
executor
  :: A.Executor effect1 context
  -> A.Executor effect2 context
  -> A.Executor (EitherEffect effect1 effect2 context) context
executor executor1 executor2 =
  A.Executor (\(EitherEffect reader) -> runReaderT reader (executor1, executor2))