{-# LANGUAGE AllowAmbiguousTypes #-} module Polysemy.Tactics ( Tactics (..) , start , continue , begin , toH2 , runTactics ) where import Polysemy import Polysemy.Internal.Union import Polysemy.Internal.Effect data Tactics f n r m a where GetInitialState :: Tactics f n r m (f ()) HoistInterpretation :: (a -> n b) -> Tactics f n r m (f a -> Semantic r (f b)) begin :: forall f n r a e . Functor f => a -> Semantic (Tactics f n (e ': r) ': r) (f a) begin a = do istate <- send @(Tactics f n (e ': r)) GetInitialState pure $ a <$ istate start :: forall f n r a e . n a -> Semantic (Tactics f n (e ': r) ': r) (Semantic (e ': r) (f a)) start na = do istate <- send @(Tactics _ n (e ': r)) GetInitialState na' <- continue (const na) pure $ na' istate {-# INLINE start #-} continue :: (a -> n b) -> Semantic (Tactics f n (e ': r) ': r) (f a -> Semantic (e ': r) (f b)) continue f = send $ HoistInterpretation f {-# INLINE continue #-} toH2 :: forall n f r a e . ( Functor f ) => Semantic r a -> Semantic (Tactics f n (e ': r) ': r) (f a) toH2 m = do istate <- send @(Tactics f n (e ':r)) GetInitialState raise $ fmap (<$ istate) m {-# INLINE toH2 #-} runTactics :: Functor f => f () -> (∀ x. f (m x) -> Semantic r2 (f x)) -> Semantic (Tactics f m r2 ': r) a -> Semantic r a runTactics s d (Semantic m) = m $ \u -> case decomp u of Left x -> liftSemantic $ hoist (runTactics_b s d) x Right (Yo GetInitialState s' _ y) -> pure $ y $ s <$ s' Right (Yo (HoistInterpretation na) s' _ y) -> do pure $ y $ (d . fmap na) <$ s' {-# INLINE runTactics #-} runTactics_b :: Functor f => f () -> (∀ x. f (m x) -> Semantic r2 (f x)) -> Semantic (Tactics f m r2 ': r) a -> Semantic r a runTactics_b = runTactics {-# NOINLINE runTactics_b #-}