{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE TypeOperators #-}
module Control.Program.Writer
(
Writer(..)
, newWriter
, tell
) where
import Data.IORef (modifyIORef', newIORef, readIORef)
import Control.Program (Has, Program, pullWith)
newtype Writer w = Writer { Writer w -> w -> IO ()
writeValue :: w -> IO () }
newWriter :: Monoid w => IO (Writer w, IO w)
newWriter :: IO (Writer w, IO w)
newWriter = do
IORef w
ref <- w -> IO (IORef w)
forall a. a -> IO (IORef a)
newIORef w
forall a. Monoid a => a
mempty
let writer :: Writer w
writer = Writer :: forall w. (w -> IO ()) -> Writer w
Writer
{ writeValue :: w -> IO ()
writeValue = \w
w -> IORef w -> (w -> w) -> IO ()
forall a. IORef a -> (a -> a) -> IO ()
modifyIORef' IORef w
ref (w -> w -> w
forall a. Semigroup a => a -> a -> a
<> w
w) }
(Writer w, IO w) -> IO (Writer w, IO w)
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Writer w
writer, IORef w -> IO w
forall a. IORef a -> IO a
readIORef IORef w
ref)
tell :: e `Has` Writer w => w -> Program e ()
tell :: w -> Program e ()
tell = (Writer w -> IO ()) -> Program e ()
forall e t a. Has e t => (t -> IO a) -> Program e a
pullWith ((Writer w -> IO ()) -> Program e ())
-> (w -> Writer w -> IO ()) -> w -> Program e ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Writer w -> w -> IO ()) -> w -> Writer w -> IO ()
forall a b c. (a -> b -> c) -> b -> a -> c
flip Writer w -> w -> IO ()
forall w. Writer w -> w -> IO ()
writeValue