{-# LANGUAGE AllowAmbiguousTypes #-}
{-# OPTIONS_HADDOCK not-home #-}
module Polysemy.Internal.Combinators
(
interpret
, intercept
, reinterpret
, reinterpret2
, reinterpret3
, rewrite
, transform
, interpretH
, interceptH
, reinterpretH
, reinterpret2H
, reinterpret3H
, stateful
, lazilyStateful
) where
import Control.Monad
import qualified Control.Monad.Trans.State.Lazy as LS
import qualified Control.Monad.Trans.State.Strict as S
import qualified Data.Tuple as S (swap)
import Polysemy.Internal
import Polysemy.Internal.CustomErrors
import Polysemy.Internal.Tactics
import Polysemy.Internal.Union
swap :: (a, b) -> (b, a)
swap ~(a, b) = (b, a)
firstOrder
:: ((forall m x. e m x -> Tactical e m r x) -> t)
-> (forall m x. e m x -> Sem r x)
-> t
firstOrder higher f = higher $ \(e :: e m x) -> liftT @m $ f e
{-# INLINE firstOrder #-}
interpret
:: FirstOrder e "interpret"
=> (∀ x m. e m x -> Sem r x)
-> Sem (e ': r) a
-> Sem r a
interpret = firstOrder interpretH
{-# INLINE interpret #-}
interpretH
:: (∀ x m . e m x -> Tactical e m r x)
-> Sem (e ': r) a
-> Sem r a
interpretH f (Sem m) = m $ \u ->
case decomp u of
Left x -> liftSem $ hoist (interpretH f) x
Right (Weaving e s d y v) -> do
a <- runTactics s d v $ f e
pure $ y a
{-# INLINE interpretH #-}
interpretInStateT
:: (∀ x m. e m x -> S.StateT s (Sem r) x)
-> s
-> Sem (e ': r) a
-> Sem r (s, a)
interpretInStateT f s (Sem m) = Sem $ \k ->
(S.swap <$!>) $ flip S.runStateT s $ m $ \u ->
case decomp u of
Left x -> S.StateT $ \s' ->
(S.swap <$!>)
. k
. weave (s', ())
(uncurry $ interpretInStateT f)
(Just . snd)
$ x
Right (Weaving e z _ y _) ->
fmap (y . (<$ z)) $ S.mapStateT (usingSem k) $ f e
{-# INLINE interpretInStateT #-}
interpretInLazyStateT
:: (∀ x m. e m x -> LS.StateT s (Sem r) x)
-> s
-> Sem (e ': r) a
-> Sem r (s, a)
interpretInLazyStateT f s (Sem m) = Sem $ \k ->
fmap swap $ flip LS.runStateT s $ m $ \u ->
case decomp u of
Left x -> LS.StateT $ \s' ->
k . fmap swap
. weave (s', ())
(uncurry $ interpretInLazyStateT f)
(Just . snd)
$ x
Right (Weaving e z _ y _) ->
fmap (y . (<$ z)) $ LS.mapStateT (usingSem k) $ f e
{-# INLINE interpretInLazyStateT #-}
stateful
:: (∀ x m. e m x -> s -> Sem r (s, x))
-> s
-> Sem (e ': r) a
-> Sem r (s, a)
stateful f = interpretInStateT $ \e -> S.StateT $ (S.swap <$!>) . f e
{-# INLINE[3] stateful #-}
lazilyStateful
:: (∀ x m. e m x -> s -> Sem r (s, x))
-> s
-> Sem (e ': r) a
-> Sem r (s, a)
lazilyStateful f = interpretInLazyStateT $ \e -> LS.StateT $ fmap swap . f e
{-# INLINE[3] lazilyStateful #-}
reinterpretH
:: forall e1 e2 r a
. (∀ m x. e1 m x -> Tactical e1 m (e2 ': r) x)
-> Sem (e1 ': r) a
-> Sem (e2 ': r) a
reinterpretH f (Sem m) = Sem $ \k -> m $ \u ->
case decompCoerce u of
Left x -> k $ hoist (reinterpretH f) $ x
Right (Weaving e s d y v) -> do
a <- usingSem k $ runTactics s (raiseUnder . d) v $ f e
pure $ y a
{-# INLINE[3] reinterpretH #-}
reinterpret
:: forall e1 e2 r a
. FirstOrder e1 "reinterpret"
=> (∀ m x. e1 m x -> Sem (e2 ': r) x)
-> Sem (e1 ': r) a
-> Sem (e2 ': r) a
reinterpret = firstOrder reinterpretH
{-# INLINE[3] reinterpret #-}
reinterpret2H
:: forall e1 e2 e3 r a
. (∀ m x. e1 m x -> Tactical e1 m (e2 ': e3 ': r) x)
-> Sem (e1 ': r) a
-> Sem (e2 ': e3 ': r) a
reinterpret2H f (Sem m) = Sem $ \k -> m $ \u ->
case decompCoerce u of
Left x -> k $ weaken $ hoist (reinterpret2H f) $ x
Right (Weaving e s d y v) -> do
a <- usingSem k $ runTactics s (raiseUnder2 . d) v $ f e
pure $ y a
{-# INLINE[3] reinterpret2H #-}
reinterpret2
:: forall e1 e2 e3 r a
. FirstOrder e1 "reinterpret2"
=> (∀ m x. e1 m x -> Sem (e2 ': e3 ': r) x)
-> Sem (e1 ': r) a
-> Sem (e2 ': e3 ': r) a
reinterpret2 = firstOrder reinterpret2H
{-# INLINE[3] reinterpret2 #-}
reinterpret3H
:: forall e1 e2 e3 e4 r a
. (∀ m x. e1 m x -> Tactical e1 m (e2 ': e3 ': e4 ': r) x)
-> Sem (e1 ': r) a
-> Sem (e2 ': e3 ': e4 ': r) a
reinterpret3H f (Sem m) = Sem $ \k -> m $ \u ->
case decompCoerce u of
Left x -> k . weaken . weaken . hoist (reinterpret3H f) $ x
Right (Weaving e s d y v) -> do
a <- usingSem k $ runTactics s (raiseUnder3 . d) v $ f e
pure $ y a
{-# INLINE[3] reinterpret3H #-}
reinterpret3
:: forall e1 e2 e3 e4 r a
. FirstOrder e1 "reinterpret3"
=> (∀ m x. e1 m x -> Sem (e2 ': e3 ': e4 ': r) x)
-> Sem (e1 ': r) a
-> Sem (e2 ': e3 ': e4 ': r) a
reinterpret3 = firstOrder reinterpret3H
{-# INLINE[3] reinterpret3 #-}
intercept
:: ( Member e r
, FirstOrder e "intercept"
)
=> (∀ x m. e m x -> Sem r x)
-> Sem r a
-> Sem r a
intercept f = interceptH $ \(e :: e m x) -> liftT @m $ f e
{-# INLINE intercept #-}
interceptH
:: Member e r
=> (∀ x m. e m x -> Tactical e m r x)
-> Sem r a
-> Sem r a
interceptH f (Sem m) = Sem $ \k -> m $ \u ->
case prj u of
Just (Weaving e s d y v) ->
usingSem k $ fmap y $ runTactics s (raise . d) v $ f e
Nothing -> k $ hoist (interceptH f) u
{-# INLINE interceptH #-}
rewrite
:: forall e1 e2 r a
. (forall m x. e1 m x -> e2 m x)
-> Sem (e1 ': r) a
-> Sem (e2 ': r) a
rewrite f (Sem m) = Sem $ \k -> m $ \u ->
k $ hoist (rewrite f) $ case decompCoerce u of
Left x -> x
Right (Weaving e s d n y) -> injWeaving $ Weaving (f e) s d n y
transform
:: forall e1 e2 r a
. Member e2 r
=> (forall m x. e1 m x -> e2 m x)
-> Sem (e1 ': r) a
-> Sem r a
transform f (Sem m) = Sem $ \k -> m $ \u ->
k $ hoist (transform f) $ case decomp u of
Left g -> g
Right (Weaving e s wv ex ins) -> injWeaving (Weaving (f e) s wv ex ins)