{-# LANGUAGE Trustworthy #-}
module Cleff.Writer
(
Writer (..)
, tell
, listen
, listens
, runWriter
, runWriterBatch
) where
import Cleff
import Cleff.Internal.Base
import Data.Atomics (atomicModifyIORefCAS_)
import Data.Foldable (traverse_)
import UnliftIO.IORef (IORef, newIORef, readIORef)
data Writer w :: Effect where
Tell :: w -> Writer w m ()
Listen :: m a -> Writer w m (a, w)
makeEffect_ ''Writer
tell :: Writer w :> es => w -> Eff es ()
listen :: Writer w :> es => Eff es a -> Eff es (a, w)
listens :: Writer w :> es => (w -> x) -> Eff es a -> Eff es (a, x)
listens :: (w -> x) -> Eff es a -> Eff es (a, x)
listens w -> x
f Eff es a
m = do
(a
a, w
w) <- Eff es a -> Eff es (a, w)
forall w (es :: [(Type -> Type) -> Type -> Type]) a.
(Writer w :> es) =>
Eff es a -> Eff es (a, w)
listen Eff es a
m
(a, x) -> Eff es (a, x)
forall (f :: Type -> Type) a. Applicative f => a -> f a
pure (a
a, w -> x
f w
w)
runWriter :: ∀ w es a. Monoid w => Eff (Writer w ': es) a -> Eff es (a, w)
runWriter :: Eff (Writer w : es) a -> Eff es (a, w)
runWriter Eff (Writer w : es) a
m = Eff (IOE : es) (a, w) -> Eff es (a, w)
forall (es :: [(Type -> Type) -> Type -> Type]).
Eff (IOE : es) ~> Eff es
thisIsPureTrustMe do
IORef w
rw <- w -> Eff (IOE : es) (IORef w)
forall (m :: Type -> Type) a. MonadIO m => a -> m (IORef a)
newIORef w
forall a. Monoid a => a
mempty
a
x <- Handler (Writer w) (IOE : es)
-> Eff (Writer w : es) a -> Eff (IOE : es) a
forall (e' :: (Type -> Type) -> Type -> Type)
(e :: (Type -> Type) -> Type -> Type)
(es :: [(Type -> Type) -> Type -> Type]).
Handler e (e' : es) -> Eff (e : es) ~> Eff (e' : es)
reinterpret ([IORef w] -> Handler (Writer w) (IOE : es)
h [IORef w
rw]) Eff (Writer w : es) a
m
w
w' <- IORef w -> Eff (IOE : es) w
forall (m :: Type -> Type) a. MonadIO m => IORef a -> m a
readIORef IORef w
rw
(a, w) -> Eff (IOE : es) (a, w)
forall (f :: Type -> Type) a. Applicative f => a -> f a
pure (a
x, w
w')
where
h :: [IORef w] -> Handler (Writer w) (IOE ': es)
h :: [IORef w] -> Handler (Writer w) (IOE : es)
h [IORef w]
rws = \case
Tell w
w' -> (IORef w -> Eff (IOE : es) ()) -> [IORef w] -> Eff (IOE : es) ()
forall (t :: Type -> Type) (f :: Type -> Type) a b.
(Foldable t, Applicative f) =>
(a -> f b) -> t a -> f ()
traverse_ (\IORef w
rw -> IO () -> Eff (IOE : es) ()
forall (m :: Type -> Type) a. MonadIO m => IO a -> m a
liftIO (IO () -> Eff (IOE : es) ()) -> IO () -> Eff (IOE : es) ()
forall a b. (a -> b) -> a -> b
$ IORef w -> (w -> w) -> IO ()
forall t. IORef t -> (t -> t) -> IO ()
atomicModifyIORefCAS_ IORef w
rw (w -> w -> w
forall a. Semigroup a => a -> a -> a
<> w
w')) [IORef w]
rws
Listen Eff esSend a
m' -> do
IORef w
rw' <- w -> Eff (IOE : es) (IORef w)
forall (m :: Type -> Type) a. MonadIO m => a -> m (IORef a)
newIORef w
forall a. Monoid a => a
mempty
a
x <- Handler (Writer w) (IOE : es) -> Eff esSend a -> Eff (IOE : es) a
forall (esSend :: [(Type -> Type) -> Type -> Type])
(e :: (Type -> Type) -> Type -> Type)
(es :: [(Type -> Type) -> Type -> Type]).
Handling esSend e es =>
Handler e es -> Eff esSend ~> Eff es
toEffWith ([IORef w] -> Handler (Writer w) (IOE : es)
h ([IORef w] -> Handler (Writer w) (IOE : es))
-> [IORef w] -> Handler (Writer w) (IOE : es)
forall a b. (a -> b) -> a -> b
$ IORef w
rw' IORef w -> [IORef w] -> [IORef w]
forall a. a -> [a] -> [a]
: [IORef w]
rws) Eff esSend a
m'
w
w' <- IORef w -> Eff (IOE : es) w
forall (m :: Type -> Type) a. MonadIO m => IORef a -> m a
readIORef IORef w
rw'
(a, w) -> Eff (IOE : es) (a, w)
forall (f :: Type -> Type) a. Applicative f => a -> f a
pure (a
x, w
w')
{-# INLINE runWriter #-}
runWriterBatch :: ∀ w es a. Monoid w => Eff (Writer w ': es) a -> Eff es (a, w)
runWriterBatch :: Eff (Writer w : es) a -> Eff es (a, w)
runWriterBatch Eff (Writer w : es) a
m = Eff (IOE : es) (a, w) -> Eff es (a, w)
forall (es :: [(Type -> Type) -> Type -> Type]).
Eff (IOE : es) ~> Eff es
thisIsPureTrustMe do
IORef w
rw <- w -> Eff (IOE : es) (IORef w)
forall (m :: Type -> Type) a. MonadIO m => a -> m (IORef a)
newIORef w
forall a. Monoid a => a
mempty
a
x <- Handler (Writer w) (IOE : es)
-> Eff (Writer w : es) a -> Eff (IOE : es) a
forall (e' :: (Type -> Type) -> Type -> Type)
(e :: (Type -> Type) -> Type -> Type)
(es :: [(Type -> Type) -> Type -> Type]).
Handler e (e' : es) -> Eff (e : es) ~> Eff (e' : es)
reinterpret (IORef w -> Handler (Writer w) (IOE : es)
h IORef w
rw) Eff (Writer w : es) a
m
w
w' <- IORef w -> Eff (IOE : es) w
forall (m :: Type -> Type) a. MonadIO m => IORef a -> m a
readIORef IORef w
rw
(a, w) -> Eff (IOE : es) (a, w)
forall (f :: Type -> Type) a. Applicative f => a -> f a
pure (a
x, w
w')
where
h :: IORef w -> Handler (Writer w) (IOE ': es)
h :: IORef w -> Handler (Writer w) (IOE : es)
h IORef w
rw = \case
Tell w
w' -> IO () -> Eff (IOE : es) ()
forall (m :: Type -> Type) a. MonadIO m => IO a -> m a
liftIO (IO () -> Eff (IOE : es) ()) -> IO () -> Eff (IOE : es) ()
forall a b. (a -> b) -> a -> b
$ IORef w -> (w -> w) -> IO ()
forall t. IORef t -> (t -> t) -> IO ()
atomicModifyIORefCAS_ IORef w
rw (w -> w -> w
forall a. Semigroup a => a -> a -> a
<> w
w')
Listen Eff esSend a
m' -> do
IORef w
rw' <- w -> Eff (IOE : es) (IORef w)
forall (m :: Type -> Type) a. MonadIO m => a -> m (IORef a)
newIORef w
forall a. Monoid a => a
mempty
a
x <- Handler (Writer w) (IOE : es) -> Eff esSend a -> Eff (IOE : es) a
forall (esSend :: [(Type -> Type) -> Type -> Type])
(e :: (Type -> Type) -> Type -> Type)
(es :: [(Type -> Type) -> Type -> Type]).
Handling esSend e es =>
Handler e es -> Eff esSend ~> Eff es
toEffWith (IORef w -> Handler (Writer w) (IOE : es)
h IORef w
rw') Eff esSend a
m'
w
w' <- IORef w -> Eff (IOE : es) w
forall (m :: Type -> Type) a. MonadIO m => IORef a -> m a
readIORef IORef w
rw'
IO () -> Eff (IOE : es) ()
forall (m :: Type -> Type) a. MonadIO m => IO a -> m a
liftIO (IO () -> Eff (IOE : es) ()) -> IO () -> Eff (IOE : es) ()
forall a b. (a -> b) -> a -> b
$ IORef w -> (w -> w) -> IO ()
forall t. IORef t -> (t -> t) -> IO ()
atomicModifyIORefCAS_ IORef w
rw (w -> w -> w
forall a. Semigroup a => a -> a -> a
<> w
w')
(a, w) -> Eff (IOE : es) (a, w)
forall (f :: Type -> Type) a. Applicative f => a -> f a
pure (a
x, w
w')
{-# INLINE runWriterBatch #-}