GPipe-2.1.6: src/Data/SNMap.hs
{-# LANGUAGE GeneralizedNewtypeDeriving, ExistentialQuantification, RankNTypes #-}
module Data.SNMap (
SNMap,
SNMapReaderT,
runSNMapReaderT,
newSNMap,
memoize,
memoizeM,
scopedM
)where
import System.Mem.StableName
import qualified Data.HashTable.IO as HT
import Data.Functor
import Control.Monad.IO.Class (liftIO, MonadIO)
import Control.Monad.Trans.Class
import System.Mem.Weak (addFinalizer)
import Control.Applicative (Applicative)
import Control.Monad.Exception (MonadException, MonadAsyncException)
import Control.Monad.Trans.State.Strict
newtype SNMap m a = SNMap (HT.BasicHashTable (StableName (m a)) a)
newSNMap :: IO (SNMap m a)
newSNMap = SNMap <$> HT.new
memoize :: MonadIO m => m (SNMap m a) -> m a -> m a
memoize getter m = do s <- liftIO $ makeStableName $! m
(SNMap h) <- getter
x <- liftIO $ HT.lookup h s
case x of
Just a -> return a
Nothing -> do a <- m
(SNMap h') <- getter --Need to redo because of scope
liftIO $ HT.insert h' s a
return a
newtype SNMapReaderT a m b = SNMapReaderT (StateT (SNMap (SNMapReaderT a m) a) m b) deriving (Functor, Applicative, Monad, MonadIO, MonadException, MonadAsyncException)
runSNMapReaderT :: MonadIO m => SNMapReaderT a m b -> m b
runSNMapReaderT (SNMapReaderT m) = do h <- liftIO newSNMap
evalStateT m h
instance MonadTrans (SNMapReaderT a) where
lift = SNMapReaderT . lift
memoizeM :: MonadIO m => SNMapReaderT a m a -> SNMapReaderT a m a
memoizeM = memoize (SNMapReaderT get)
-- | Run a subcomputation in a scope, where nothing memoized inside will be remembered after
scopedM :: MonadIO m => SNMapReaderT a m x -> SNMapReaderT a m x
scopedM m= do SNMap h <- SNMapReaderT get
save <- liftIO $ HT.toList h
x <- m
h' <- liftIO $ HT.fromList save
SNMapReaderT $ put (SNMap h')
return x