module Control.Monad.Trans.Writer.Ref
( WriterRefT
, runWriterRefT
, runWriterIORefT
, runWriterSTRefT
, module Control.Monad.Writer.Class
) where
import Control.Applicative (Applicative (..))
import Control.Monad.Catch (MonadCatch (..), MonadMask (..),
MonadThrow (..))
import Control.Monad.IO.Class (MonadIO (..))
import Control.Monad.Reader.Class (MonadReader (..))
import Control.Monad.Trans.Control (defaultLiftBaseWith,
defaultRestoreM)
import Control.Monad.Trans.Unlift
import Control.Monad.Trans.Resource (MonadResource (..))
import Control.Monad.Writer.Class
import Data.Monoid (Monoid, mappend, mempty)
import Data.Mutable (IORef, MCState, MutableRef,
PrimMonad, PrimState, RealWorld,
RefElement, STRef, modifyRef',
newRef, readRef, writeRef)
newtype WriterRefT ref w m a = WriterRefT
{ unWriterRefT :: ref w -> m a
}
deriving Functor
runWriterRefT
:: ( Monad m
, w ~ RefElement (ref w)
, MCState (ref w) ~ PrimState b
, MonadBase b m
, MutableRef (ref w)
, PrimMonad b
, Monoid w
)
=> WriterRefT ref w m a
-> m (a, w)
runWriterRefT (WriterRefT f) = do
ref <- liftBase $ newRef mempty
a <- f ref
v <- liftBase $ readRef ref
return (a, v)
runWriterIORefT
:: ( Monad m
, RealWorld ~ PrimState b
, MonadBase b m
, PrimMonad b
, Monoid w
)
=> WriterRefT IORef w m a
-> m (a, w)
runWriterIORefT = runWriterRefT
runWriterSTRefT
:: ( Monad m
, ps ~ PrimState b
, MonadBase b m
, PrimMonad b
, Monoid w
)
=> WriterRefT (STRef ps) w m a
-> m (a, w)
runWriterSTRefT = runWriterRefT
instance Applicative m => Applicative (WriterRefT ref w m) where
pure = WriterRefT . const . pure
WriterRefT f <*> WriterRefT g = WriterRefT $ \x -> f x <*> g x
instance Monad m => Monad (WriterRefT ref w m) where
return = WriterRefT . const . return
WriterRefT f >>= g = WriterRefT $ \x -> do
a <- f x
unWriterRefT (g a) x
instance ( MCState (ref w) ~ PrimState b
, Monad m
, w ~ RefElement (ref w)
, MutableRef (ref w)
, PrimMonad b
, MonadBase b m
, Monoid w
)
=> MonadWriter w (WriterRefT ref w m) where
writer (a, w) = WriterRefT $ \ref ->
liftBase $ modifyRef' ref (`mappend` w) >> return a
tell w = WriterRefT $ \ref -> liftBase $ modifyRef' ref (`mappend` w)
listen (WriterRefT f) = lift $ do
ref <- liftBase (newRef mempty)
a <- f ref
w <- liftBase (readRef ref)
return (a, w)
pass (WriterRefT f) = WriterRefT $ \ref -> do
(a, g) <- f ref
liftBase $ modifyRef' ref g
return a
instance MonadReader r m => MonadReader r (WriterRefT ref w m) where
ask = WriterRefT $ const ask
local f m = WriterRefT $ local f . unWriterRefT m
reader = WriterRefT . const . reader
instance MonadTrans (WriterRefT ref w) where
lift = WriterRefT . const
instance MonadIO m => MonadIO (WriterRefT ref w m) where
liftIO = lift . liftIO
instance MonadBase b m => MonadBase b (WriterRefT ref w m) where
liftBase = lift . liftBase
instance MonadTransControl (WriterRefT ref w) where
type StT (WriterRefT ref w) a = a
liftWith f = WriterRefT $ \r -> f $ \t -> unWriterRefT t r
restoreT = WriterRefT . const
instance MonadBaseControl b m => MonadBaseControl b (WriterRefT ref w m) where
type StM (WriterRefT ref w m) a = StM m a
liftBaseWith = defaultLiftBaseWith
restoreM = defaultRestoreM
instance MonadThrow m => MonadThrow (WriterRefT ref w m) where
throwM = lift . throwM
instance MonadCatch m => MonadCatch (WriterRefT ref w m) where
catch (WriterRefT f) g = WriterRefT $ \e -> catch (f e) ((`unWriterRefT` e) . g)
instance MonadMask m => MonadMask (WriterRefT ref w m) where
mask a = WriterRefT $ \e -> mask $ \u -> unWriterRefT (a $ q u) e
where q :: (m a -> m a) -> WriterRefT ref w m a -> WriterRefT ref w m a
q u (WriterRefT b) = WriterRefT (u . b)
uninterruptibleMask a =
WriterRefT $ \e -> uninterruptibleMask $ \u -> unWriterRefT (a $ q u) e
where q :: (m a -> m a) -> WriterRefT ref w m a -> WriterRefT ref w m a
q u (WriterRefT b) = WriterRefT (u . b)
instance MonadResource m => MonadResource (WriterRefT ref w m) where
liftResourceT = lift . liftResourceT