{-# LANGUAGE BangPatterns, TemplateHaskell #-}
module Polysemy.Output
(
Output (..)
, output
, runOutputList
, runLazyOutputList
, runOutputMonoid
, runLazyOutputMonoid
, runOutputMonoidAssocR
, runLazyOutputMonoidAssocR
, runOutputMonoidIORef
, runOutputMonoidTVar
, outputToIOMonoid
, outputToIOMonoidAssocR
, ignoreOutput
, runOutputBatched
, runOutputSem
) where
import Data.IORef
import Control.Concurrent.STM
import qualified Control.Monad.Trans.Writer.Lazy as Lazy
import Data.Semigroup (Endo(..))
import Data.Bifunctor (first)
import Polysemy
import Polysemy.State
import Control.Monad (when)
import Polysemy.Internal.Union
import Polysemy.Internal.Writer
data Output o m a where
Output :: o -> Output o m ()
makeSem ''Output
runOutputList
:: forall o r a
. Sem (Output o ': r) a
-> Sem r ([o], a)
runOutputList :: forall o (r :: EffectRow) a. Sem (Output o : r) a -> Sem r ([o], a)
runOutputList = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (forall (p :: * -> * -> *) a b c.
Bifunctor p =>
(a -> b) -> p a c -> p b c
first forall a. [a] -> [a]
reverse) forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall s (r :: EffectRow) a.
s -> Sem (State s : r) a -> Sem r (s, a)
runState [] forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (e1 :: Effect) (e2 :: Effect) (r :: EffectRow) a.
FirstOrder e1 "reinterpret" =>
(forall (rInitial :: EffectRow) x.
e1 (Sem rInitial) x -> Sem (e2 : r) x)
-> Sem (e1 : r) a -> Sem (e2 : r) a
reinterpret
(\case
Output o
o -> forall s (r :: EffectRow).
Member (State s) r =>
(s -> s) -> Sem r ()
modify' (o
o forall a. a -> [a] -> [a]
:)
)
{-# INLINE runOutputList #-}
runLazyOutputList
:: forall o r a
. Sem (Output o ': r) a
-> Sem r ([o], a)
runLazyOutputList :: forall o (r :: EffectRow) a. Sem (Output o : r) a -> Sem r ([o], a)
runLazyOutputList = forall o m (r :: EffectRow) a.
Monoid m =>
(o -> m) -> Sem (Output o : r) a -> Sem r (m, a)
runLazyOutputMonoidAssocR forall (f :: * -> *) a. Applicative f => a -> f a
pure
{-# INLINE runLazyOutputList #-}
runOutputMonoid
:: forall o m r a
. Monoid m
=> (o -> m)
-> Sem (Output o ': r) a
-> Sem r (m, a)
runOutputMonoid :: forall o m (r :: EffectRow) a.
Monoid m =>
(o -> m) -> Sem (Output o : r) a -> Sem r (m, a)
runOutputMonoid o -> m
f = forall s (r :: EffectRow) a.
s -> Sem (State s : r) a -> Sem r (s, a)
runState forall a. Monoid a => a
mempty forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (e1 :: Effect) (e2 :: Effect) (r :: EffectRow) a.
FirstOrder e1 "reinterpret" =>
(forall (rInitial :: EffectRow) x.
e1 (Sem rInitial) x -> Sem (e2 : r) x)
-> Sem (e1 : r) a -> Sem (e2 : r) a
reinterpret
(\case
Output o
o -> forall s (r :: EffectRow).
Member (State s) r =>
(s -> s) -> Sem r ()
modify' (forall a. Monoid a => a -> a -> a
`mappend` o -> m
f o
o)
)
{-# INLINE runOutputMonoid #-}
runLazyOutputMonoid
:: forall o m r a
. Monoid m
=> (o -> m)
-> Sem (Output o ': r) a
-> Sem r (m, a)
runLazyOutputMonoid :: forall o m (r :: EffectRow) a.
Monoid m =>
(o -> m) -> Sem (Output o : r) a -> Sem r (m, a)
runLazyOutputMonoid o -> m
f = forall o (e :: Effect) (r :: EffectRow) a.
Monoid o =>
(forall (m :: * -> *) x.
Monad m =>
Weaving e (WriterT o m) x -> WriterT o m x)
-> Sem (e : r) a -> Sem r (o, a)
interpretViaLazyWriter forall a b. (a -> b) -> a -> b
$ \(Weaving Output o (Sem rInitial) a
e f ()
s forall x. f (Sem rInitial x) -> WriterT m m (f x)
_ f a -> x
ex forall x. f x -> Maybe x
_) ->
case Output o (Sem rInitial) a
e of
Output o
o -> f a -> x
ex f ()
s forall (f :: * -> *) a b. Functor f => a -> f b -> f a
<$ forall (m :: * -> *) w. Monad m => w -> WriterT w m ()
Lazy.tell (o -> m
f o
o)
runOutputMonoidAssocR
:: forall o m r a
. Monoid m
=> (o -> m)
-> Sem (Output o ': r) a
-> Sem r (m, a)
runOutputMonoidAssocR :: forall o m (r :: EffectRow) a.
Monoid m =>
(o -> m) -> Sem (Output o : r) a -> Sem r (m, a)
runOutputMonoidAssocR o -> m
f =
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (forall (p :: * -> * -> *) a b c.
Bifunctor p =>
(a -> b) -> p a c -> p b c
first (forall a. Endo a -> a -> a
`appEndo` forall a. Monoid a => a
mempty))
forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall o m (r :: EffectRow) a.
Monoid m =>
(o -> m) -> Sem (Output o : r) a -> Sem r (m, a)
runOutputMonoid (\o
o -> let !o' :: m
o' = o -> m
f o
o in forall a. (a -> a) -> Endo a
Endo (m
o' forall a. Semigroup a => a -> a -> a
<>))
{-# INLINE runOutputMonoidAssocR #-}
runLazyOutputMonoidAssocR
:: forall o m r a
. Monoid m
=> (o -> m)
-> Sem (Output o ': r) a
-> Sem r (m, a)
runLazyOutputMonoidAssocR :: forall o m (r :: EffectRow) a.
Monoid m =>
(o -> m) -> Sem (Output o : r) a -> Sem r (m, a)
runLazyOutputMonoidAssocR o -> m
f =
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (forall (p :: * -> * -> *) a b c.
Bifunctor p =>
(a -> b) -> p a c -> p b c
first (forall a. Endo a -> a -> a
`appEndo` forall a. Monoid a => a
mempty))
forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall o m (r :: EffectRow) a.
Monoid m =>
(o -> m) -> Sem (Output o : r) a -> Sem r (m, a)
runLazyOutputMonoid (\o
o -> let o' :: m
o' = o -> m
f o
o in forall a. (a -> a) -> Endo a
Endo (m
o' forall a. Semigroup a => a -> a -> a
<>))
{-# INLINE runLazyOutputMonoidAssocR #-}
runOutputMonoidIORef
:: forall o m r a
. (Monoid m, Member (Embed IO) r)
=> IORef m
-> (o -> m)
-> Sem (Output o ': r) a
-> Sem r a
runOutputMonoidIORef :: forall o m (r :: EffectRow) a.
(Monoid m, Member (Embed IO) r) =>
IORef m -> (o -> m) -> Sem (Output o : r) a -> Sem r a
runOutputMonoidIORef IORef m
ref o -> m
f = forall (e :: Effect) (r :: EffectRow) a.
FirstOrder e "interpret" =>
(forall (rInitial :: EffectRow) x. e (Sem rInitial) x -> Sem r x)
-> Sem (e : r) a -> Sem r a
interpret forall a b. (a -> b) -> a -> b
$ \case
Output o
o -> forall (m :: * -> *) (r :: EffectRow) a.
Member (Embed m) r =>
m a -> Sem r a
embed forall a b. (a -> b) -> a -> b
$ forall a b. IORef a -> (a -> (a, b)) -> IO b
atomicModifyIORef' IORef m
ref (\m
s -> let !o' :: m
o' = o -> m
f o
o in (m
s forall a. Semigroup a => a -> a -> a
<> m
o', ()))
{-# INLINE runOutputMonoidIORef #-}
runOutputMonoidTVar
:: forall o m r a
. (Monoid m, Member (Embed IO) r)
=> TVar m
-> (o -> m)
-> Sem (Output o ': r) a
-> Sem r a
runOutputMonoidTVar :: forall o m (r :: EffectRow) a.
(Monoid m, Member (Embed IO) r) =>
TVar m -> (o -> m) -> Sem (Output o : r) a -> Sem r a
runOutputMonoidTVar TVar m
tvar o -> m
f = forall (e :: Effect) (r :: EffectRow) a.
FirstOrder e "interpret" =>
(forall (rInitial :: EffectRow) x. e (Sem rInitial) x -> Sem r x)
-> Sem (e : r) a -> Sem r a
interpret forall a b. (a -> b) -> a -> b
$ \case
Output o
o -> forall (m :: * -> *) (r :: EffectRow) a.
Member (Embed m) r =>
m a -> Sem r a
embed forall a b. (a -> b) -> a -> b
$ forall a. STM a -> IO a
atomically forall a b. (a -> b) -> a -> b
$ do
m
s <- forall a. TVar a -> STM a
readTVar TVar m
tvar
forall a. TVar a -> a -> STM ()
writeTVar TVar m
tvar forall a b. (a -> b) -> a -> b
$! m
s forall a. Semigroup a => a -> a -> a
<> o -> m
f o
o
{-# INLINE runOutputMonoidTVar #-}
outputToIOMonoid
:: forall o m r a
. (Monoid m, Member (Embed IO) r)
=> (o -> m)
-> Sem (Output o ': r) a
-> Sem r (m, a)
outputToIOMonoid :: forall o m (r :: EffectRow) a.
(Monoid m, Member (Embed IO) r) =>
(o -> m) -> Sem (Output o : r) a -> Sem r (m, a)
outputToIOMonoid o -> m
f Sem (Output o : r) a
sem = do
IORef m
ref <- forall (m :: * -> *) (r :: EffectRow) a.
Member (Embed m) r =>
m a -> Sem r a
embed forall a b. (a -> b) -> a -> b
$ forall a. a -> IO (IORef a)
newIORef forall a. Monoid a => a
mempty
a
res <- forall o m (r :: EffectRow) a.
(Monoid m, Member (Embed IO) r) =>
IORef m -> (o -> m) -> Sem (Output o : r) a -> Sem r a
runOutputMonoidIORef IORef m
ref o -> m
f Sem (Output o : r) a
sem
m
end <- forall (m :: * -> *) (r :: EffectRow) a.
Member (Embed m) r =>
m a -> Sem r a
embed forall a b. (a -> b) -> a -> b
$ forall a. IORef a -> IO a
readIORef IORef m
ref
forall (m :: * -> *) a. Monad m => a -> m a
return (m
end, a
res)
outputToIOMonoidAssocR
:: forall o m r a
. (Monoid m, Member (Embed IO) r)
=> (o -> m)
-> Sem (Output o ': r) a
-> Sem r (m, a)
outputToIOMonoidAssocR :: forall o m (r :: EffectRow) a.
(Monoid m, Member (Embed IO) r) =>
(o -> m) -> Sem (Output o : r) a -> Sem r (m, a)
outputToIOMonoidAssocR o -> m
f =
(forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (p :: * -> * -> *) a b c.
Bifunctor p =>
(a -> b) -> p a c -> p b c
first) (forall a. Endo a -> a -> a
`appEndo` forall a. Monoid a => a
mempty)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall o m (r :: EffectRow) a.
(Monoid m, Member (Embed IO) r) =>
(o -> m) -> Sem (Output o : r) a -> Sem r (m, a)
outputToIOMonoid (\o
o -> let !o' :: m
o' = o -> m
f o
o in forall a. (a -> a) -> Endo a
Endo (m
o' forall a. Semigroup a => a -> a -> a
<>))
ignoreOutput :: Sem (Output o ': r) a -> Sem r a
ignoreOutput :: forall o (r :: EffectRow) a. Sem (Output o : r) a -> Sem r a
ignoreOutput = forall (e :: Effect) (r :: EffectRow) a.
FirstOrder e "interpret" =>
(forall (rInitial :: EffectRow) x. e (Sem rInitial) x -> Sem r x)
-> Sem (e : r) a -> Sem r a
interpret forall a b. (a -> b) -> a -> b
$ \case
Output o
_ -> forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
{-# INLINE ignoreOutput #-}
runOutputBatched
:: forall o r a
. Member (Output [o]) r
=> Int
-> Sem (Output o ': r) a
-> Sem r a
runOutputBatched :: forall o (r :: EffectRow) a.
Member (Output [o]) r =>
Int -> Sem (Output o : r) a -> Sem r a
runOutputBatched Int
0 Sem (Output o : r) a
m = forall o (r :: EffectRow) a. Sem (Output o : r) a -> Sem r a
ignoreOutput Sem (Output o : r) a
m
runOutputBatched Int
size Sem (Output o : r) a
m = do
((Int
c, [o]
res), a
a) <-
forall s (r :: EffectRow) a.
s -> Sem (State s : r) a -> Sem r (s, a)
runState (Int
0 :: Int, [] :: [o]) forall a b. (a -> b) -> a -> b
$ forall (e1 :: Effect) (e2 :: Effect) (r :: EffectRow) a.
FirstOrder e1 "reinterpret" =>
(forall (rInitial :: EffectRow) x.
e1 (Sem rInitial) x -> Sem (e2 : r) x)
-> Sem (e1 : r) a -> Sem (e2 : r) a
reinterpret (\case
Output o
o -> do
(Int
count, [o]
acc) <- forall s (r :: EffectRow). Member (State s) r => Sem r s
get
let newCount :: Int
newCount = Int
1 forall a. Num a => a -> a -> a
+ Int
count
newAcc :: [o]
newAcc = o
o forall a. a -> [a] -> [a]
: [o]
acc
if Int
newCount forall a. Ord a => a -> a -> Bool
< Int
size
then forall s (r :: EffectRow). Member (State s) r => s -> Sem r ()
put (Int
newCount, [o]
newAcc)
else do
forall o (r :: EffectRow). Member (Output o) r => o -> Sem r ()
output (forall a. [a] -> [a]
reverse [o]
newAcc)
forall s (r :: EffectRow). Member (State s) r => s -> Sem r ()
put (Int
0 :: Int, [] :: [o])
) Sem (Output o : r) a
m
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Int
c forall a. Ord a => a -> a -> Bool
> Int
0) forall a b. (a -> b) -> a -> b
$ forall o (r :: EffectRow). Member (Output o) r => o -> Sem r ()
output @[o] (forall a. [a] -> [a]
reverse [o]
res)
forall (f :: * -> *) a. Applicative f => a -> f a
pure a
a
runOutputSem :: (o -> Sem r ()) -> Sem (Output o ': r) a -> Sem r a
runOutputSem :: forall o (r :: EffectRow) a.
(o -> Sem r ()) -> Sem (Output o : r) a -> Sem r a
runOutputSem o -> Sem r ()
act = forall (e :: Effect) (r :: EffectRow) a.
FirstOrder e "interpret" =>
(forall (rInitial :: EffectRow) x. e (Sem rInitial) x -> Sem r x)
-> Sem (e : r) a -> Sem r a
interpret forall a b. (a -> b) -> a -> b
$ \case
Output o
o -> o -> Sem r ()
act o
o
{-# INLINE runOutputSem #-}