packages feed

lazy-async-1.0.0.0: src/LazyAsync/Actions/Memoize.hs

{-# language Safe #-}

module LazyAsync.Actions.Memoize where

import LazyAsync.Actions.Spawn     (lazyAsync)
import LazyAsync.Actions.StartWait (startWait)

import LazyAsync.Prelude (ContT, IO, MonadBaseControl, Traversable, fmap,
                          runContT, traverse)

import qualified LazyAsync.Libraries.Rank2 as Rank2

{- | Creates a situation wherein:

  * The action shall begin running only once the memoized action runs
  * The action shall run at most once
  * The action shall run only within the continuation (when the continuation ends, the action is stopped)
-}
memoize :: (MonadBaseControl IO m) =>
    m a -- ^ Action
    -> ContT r m (m a) -- ^ Memoized action, in a continuation
memoize action = fmap startWait (lazyAsync action)

-- | Akin to 'memoize'
withMemoizedIO :: IO a -> (IO a -> IO b) -> IO b
withMemoizedIO action = runContT (memoize action)

-- | 🌈 'memoizeMany' is equivalent to @('traverse' 'memoize')@
memoizeMany :: (MonadBaseControl IO m, Traversable t) => t (m a) -> ContT r m (t (m a))
memoizeMany = traverse memoize

-- | 🌈 'memoizeRank2' is equivalent to @('Rank2.traverse' 'memoize')@
memoizeRank2 :: (MonadBaseControl IO m, Rank2.Traversable t) => t m -> ContT r m (t m)
memoizeRank2 = Rank2.traverse memoize

-- | Akin to 'memoizeMany'
withMemoizedListIO :: [IO a] -> ([IO a] -> IO b) -> IO b
withMemoizedListIO x = runContT (memoizeMany x)