module Control.Monad.Ref where
import Control.Monad
import Control.Monad.Trans
import Control.Monad.Reader
import Control.Monad.Writer
import Data.IORef
class Monad m => MonadRef m where
type Ref m :: * -> *
newRef :: a -> m (Ref m a)
readRef :: Ref m a -> m a
writeRef :: Ref m a -> a -> m ()
atomicModifyRef :: Ref m a -> (a -> (a, b)) -> m b
instance MonadRef IO where
type Ref IO = IORef
newRef = newIORef
readRef = readIORef
writeRef = writeIORef
atomicModifyRef r f = do
result <- atomicModifyIORef' r f
return result
cacheM :: (MonadRef m, MonadRef m', Ref m ~ Ref m') => m' a -> m (m' a, m ())
cacheM a = do
r <- newRef undefined
let invalidate = writeRef r $ do
result <- a
writeRef r $ return result
return result
invalidate
return (join $ readRef r, invalidate)
cacheMWithTry :: (MonadRef m, MonadRef m', Ref m ~ Ref m') => m' a -> m (m' a, m (Maybe a), m ())
cacheMWithTry a = do
r <- newRef $ Left a
let invalidate = writeRef r $ Left a
get = readRef r >>= \case
Left a' -> do
result <- a'
writeRef r $ Right result
return result
Right result -> return result
tryGet = readRef r >>= \case
Left _ -> return Nothing
Right result -> return $ Just result
return (get, tryGet, invalidate)
memoM :: (MonadRef m, MonadRef m', Ref m ~ Ref m') => m' a -> m (m' a)
memoM = liftM fst . cacheM
replaceRef :: MonadRef m => Ref m a -> a -> m a
replaceRef r new = atomicModifyRef r $ \old -> (new, old)
modifyRef :: MonadRef m => Ref m a -> (a -> a) -> m ()
modifyRef r f = atomicModifyRef r $ \a -> (f a, ())
instance (Monoid w, MonadRef m) => MonadRef (WriterT w m) where
type Ref (WriterT w m) = Ref m
newRef = lift . newRef
readRef = lift . readRef
writeRef r = lift . writeRef r
atomicModifyRef r f = lift $ atomicModifyRef r f
instance MonadRef m => MonadRef (ReaderT r m) where
type Ref (ReaderT r m) = Ref m
newRef = lift . newRef
readRef = lift . readRef
writeRef r = lift . writeRef r
atomicModifyRef r f = lift $ atomicModifyRef r f