{-# 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