haskus-utils-1.5: src/lib/Haskus/Utils/MonadVar.hs
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE BlockArguments #-}
-- | Monadic variable with cache
module Haskus.Utils.MonadVar
( MonadVar (..)
, updateMonadVarForce
, updateMonadVarMaybe
, updateMonadVar
-- * Non-empty
, MonadVarNE (..)
, updateMonadVarNEMaybe
, updateMonadVarNE
)
where
import Haskus.Utils.Flow
import Haskus.Utils.Maybe
-- | A value that can be read with IO. The last read can be cached in it too.
--
-- We store both the read value (type s) and a pure modifier function (s -> a).
-- By doing this we can easily compare a read value to the cached one without
-- performing extra computations. The functor instance compose with the modifier
-- function.
--
-- The supposedly costly modifier function is applied lazily
data MonadVar m s a
= MonadVar !(m s) (s -> a) -- ^ IO accessor + modifier function
| CachedMonadVar a !s !(m s) (s -> a) -- ^ Additional cached transformed and read values.
deriving (Functor)
-- | Check if the MonadVar cache needs to be updated.
--
-- Invariably produce an MonadVar with cached values or Nothing if the old one
-- hasn't changed.
updateMonadVarMaybe :: (Monad m, Eq s) => MonadVar m s a -> m (Maybe (MonadVar m s a))
updateMonadVarMaybe dv@(MonadVar {}) = Just <|| updateMonadVarForce dv
updateMonadVarMaybe (CachedMonadVar _ s io f) = do
s' <- io
if s == s'
then pure Nothing
else pure <| Just <| CachedMonadVar (f s') s' io f
-- | Check if the MonadVar cache needs to be updated. Return the updated MonadVar.
--
-- Invariably produce an MonadVar with cached values.
updateMonadVar :: (Monad m, Eq s) => MonadVar m s a -> m (MonadVar m s a)
updateMonadVar dv = fromMaybe dv <|| updateMonadVarMaybe dv
-- | Update an MonadVar without comparing to the cache even if it is available.
--
-- Invariably produce an MonadVar with cached values.
updateMonadVarForce :: (Monad m, Eq s) => MonadVar m s a -> m (MonadVar m s a)
updateMonadVarForce (CachedMonadVar _ _ io f) = do
s <- io
pure (CachedMonadVar (f s) s io f)
updateMonadVarForce (MonadVar io f) = do
s <- io
pure (CachedMonadVar (f s) s io f)
----------------------------------
-- Non-empty MonadVar
----------------------------------
-- Non-empty MonadVar
--
-- The value may be set purely if the source is Nothing
data MonadVarNE m s a
= MonadVarNE a !(Maybe s) !(m s) (s -> a) -- ^ Additional cached transformed and read values.
deriving (Functor)
-- | Check if the MonadVarNE cache needs to be updated.
updateMonadVarNEMaybe :: (Monad m, Eq s) => MonadVarNE m s a -> m (Maybe (MonadVarNE m s a))
updateMonadVarNEMaybe (MonadVarNE _ ms io f) = do
s' <- io
pure case ms of
Just s | s == s' -> Nothing
_ -> Just <| MonadVarNE (f s') (Just s') io f
-- | Check if the MonadVarNE cache needs to be updated. Return the updated
-- MonadVarNE
updateMonadVarNE :: (Monad m, Eq s) => MonadVarNE m s a -> m (MonadVarNE m s a)
updateMonadVarNE dv = fromMaybe dv <|| updateMonadVarNEMaybe dv