-- | A Store a contains an (a) value which is only to be computed once,
-- when it is first needed.
--
-- Perhaps we should use laziness and unsafePerformIO?
module Util.Store(
   Store,
   newStore, -- :: IO (Store a)
   takeStore, -- :: IO a -> Store a -> IO a
   ) where

import Control.Concurrent.MVar

newtype Store a = Store (MVar (Maybe a))

newStore :: IO (Store a)
newStore :: IO (Store a)
newStore =
   do
      MVar (Maybe a)
mVar <- Maybe a -> IO (MVar (Maybe a))
forall a. a -> IO (MVar a)
newMVar Maybe a
forall a. Maybe a
Nothing
      Store a -> IO (Store a)
forall (m :: * -> *) a. Monad m => a -> m a
return (MVar (Maybe a) -> Store a
forall a. MVar (Maybe a) -> Store a
Store MVar (Maybe a)
mVar)

takeStore :: IO a -> Store a -> IO a
takeStore :: IO a -> Store a -> IO a
takeStore IO a
getA (Store MVar (Maybe a)
mVar) =
   MVar (Maybe a) -> (Maybe a -> IO (Maybe a, a)) -> IO a
forall a b. MVar a -> (a -> IO (a, b)) -> IO b
modifyMVar
      MVar (Maybe a)
mVar
      (\ Maybe a
aOpt -> case Maybe a
aOpt of
         Just a
a -> (Maybe a, a) -> IO (Maybe a, a)
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe a
aOpt,a
a)
         Maybe a
Nothing ->
            do
               a
a <- IO a
getA
               (Maybe a, a) -> IO (Maybe a, a)
forall (m :: * -> *) a. Monad m => a -> m a
return (a -> Maybe a
forall a. a -> Maybe a
Just a
a,a
a)
         )