{- | Module : Control.Monad.Trans.Memo.ReaderCache Copyright : (c) Eduard Sergeev 2013 License : BSD-style (see the file LICENSE) Maintainer : eduard.sergeev@gmail.com Stability : experimental Portability : non-portable Generic StateCache - similar to `Control.Monad.Trans.Reader.ReaderT` but optimised for carrying cache container -} {-# LANGUAGE NoImplicitPrelude, BangPatterns #-} module Control.Monad.Trans.Memo.ReaderCache ( ReaderCache(..), container ) where import Data.Function import Control.Applicative import Control.Monad import Control.Monad.Fix import Control.Monad.Trans -- | Generic memoization cache which uses provided container -- This is pretty much identical to `Control.Monad.Trans.Reader.ReaderT`, -- but is tuned to speed up implementations which use unboxed mutable containers newtype ReaderCache c m a = ReaderCache { evalReaderCache :: c -> m a } -- | Returns internal container container :: Monad m => ReaderCache c m c {-# INLINE container #-} container = ReaderCache $ \ !c -> return c instance (Functor m) => Functor (ReaderCache c m) where {-# INLINE fmap #-} fmap f m = ReaderCache $ \ !c -> fmap f (evalReaderCache m c) instance (Applicative m) => Applicative (ReaderCache arr m) where {-# INLINE pure #-} pure a = ReaderCache $ \_ -> pure a {-# INLINE (<*>) #-} f <*> v = ReaderCache $ \ !c -> evalReaderCache f c <*> evalReaderCache v c instance (Alternative m) => Alternative (ReaderCache c m) where {-# INLINE empty #-} empty = ReaderCache $ const empty {-# INLINE (<|>) #-} m <|> n = ReaderCache $ \ !c -> evalReaderCache m c <|> evalReaderCache n c instance (Monad m) => Monad (ReaderCache c m) where {-# INLINE return #-} return a = ReaderCache $ \ !c -> return a {-# INLINE (>>=) #-} m >>= k = ReaderCache $ \ !c -> do a <- evalReaderCache m c evalReaderCache (k a) c {-# INLINE (>>) #-} m >> k = ReaderCache $ \ !c -> do evalReaderCache m c evalReaderCache k c instance (MonadPlus m) => MonadPlus (ReaderCache c m) where {-# INLINE mzero #-} mzero = lift mzero {-# INLINE mplus #-} m `mplus` n = ReaderCache $ \ !c -> evalReaderCache m c `mplus` evalReaderCache n c instance (MonadFix m) => MonadFix (ReaderCache c m) where mfix f = ReaderCache $ \ !c -> mfix $ \a -> evalReaderCache (f a) c instance MonadTrans (ReaderCache c) where {-# INLINE lift #-} lift = ReaderCache . const instance (MonadIO m) => MonadIO (ReaderCache c m) where {-# INLINE liftIO #-} liftIO = lift . liftIO