{-# LANGUAGE DeriveFunctor #-}
{-# OPTIONS_HADDOCK not-home #-}
module Control.Effect.Carrier.Internal.Stepped where
import Data.Coerce
import Control.Applicative
import Control.Monad.Trans
import Control.Monad.Trans.Free.Church.Alternate
import Control.Effect.Internal
import Control.Effect.Internal.Utils
import Control.Effect.Internal.Membership
import Control.Effect.Internal.Derive
import Control.Effect.Internal.Union
data FOEff e x where
FOEff :: e q x -> FOEff e x
class (forall m n x. Coercible (e m x) (e n x))
=> FirstOrder (e :: Effect)
instance (forall m n x. Coercible (e m x) (e n x))
=> FirstOrder e
newtype SteppedC (e :: Effect) m a = SteppedC {
unSteppedC :: FreeT (FOEff e) m a
}
deriving ( Functor, Applicative, Monad
, MonadFail, MonadIO, MonadBase b
, MonadThrow, MonadCatch
)
deriving MonadTrans
sendStepped :: e q a -> SteppedC e m a
sendStepped = SteppedC #. liftF . FOEff
{-# INLINE sendStepped #-}
instance ( Threads (FreeT (FOEff e)) (Prims m)
, Carrier m
)
=> Carrier (SteppedC e m) where
type Derivs (SteppedC e m) = e ': Derivs m
type Prims (SteppedC e m) = Prims m
algPrims = coerce (thread @(FreeT (FOEff e)) (algPrims @m))
{-# INLINEABLE algPrims #-}
reformulate n alg = powerAlg' (reformulate (n . lift) alg) (n . sendStepped)
{-# INLINEABLE reformulate #-}
data Steps (e :: Effect) m a where
Done :: a -> Steps e m a
More :: e q x -> (x -> m (Steps e m a)) -> Steps e m a
deriving instance Functor m => Functor (Steps e m)
instance Functor m => Applicative (Steps e m) where
pure = Done
{-# INLINE pure #-}
liftA2 f (Done a) fb = fmap (f a) fb
liftA2 f (More e c) fb = More e (fmap (\fa -> liftA2 f fa fb) . c)
instance Functor m => Monad (Steps e m) where
Done a >>= f = f a
More e c >>= f = More e (fmap (>>= f) . c)
steps :: forall e m a p
. ( Carrier m
, Threaders '[SteppedThreads] m p
)
=> SteppedC e m a -> m (Steps e m a)
steps =
foldFreeT
Done
(\c (FOEff e) -> return (More e c))
.# unSteppedC
{-# INLINE steps #-}
liftSteps :: (MonadTrans t, Monad m) => Steps e m a -> Steps e (t m) a
liftSteps (Done a) = Done a
liftSteps (More e c) = More e (lift . fmap liftSteps . c)
unsteps :: forall e m a
. ( FirstOrder e
, Member e (Derivs m)
, Carrier m
)
=> Steps e m a -> m a
unsteps (Done a) = return a
unsteps (More e c) = send @e (coerce e) >>= c >>= unsteps
type SteppedThreads = FreeThreads