Safe Haskell | None |
---|---|
Language | Haskell2010 |
Memoization support. This module is provided for access to Haxl internals only; most users should import Haxl.Core instead.
- cachedComputation :: forall req u a. (Eq (req a), Hashable (req a), Typeable (req a)) => req a -> GenHaxl u a -> GenHaxl u a
- preCacheComputation :: forall req u a. (Eq (req a), Hashable (req a), Typeable (req a)) => req a -> GenHaxl u a -> GenHaxl u a
- memo :: (Typeable a, Typeable k, Hashable k, Eq k) => k -> GenHaxl u a -> GenHaxl u a
- memoFingerprint :: Typeable a => MemoFingerprintKey a -> GenHaxl u a -> GenHaxl u a
- data MemoFingerprintKey a where
- MemoFingerprintKey :: !Word64 -> !Word64 -> Addr# -> Addr# -> MemoFingerprintKey a
- memoize :: GenHaxl u a -> GenHaxl u (GenHaxl u a)
- memoize1 :: (Eq a, Hashable a) => (a -> GenHaxl u b) -> GenHaxl u (a -> GenHaxl u b)
- memoize2 :: (Eq a, Hashable a, Eq b, Hashable b) => (a -> b -> GenHaxl u c) -> GenHaxl u (a -> b -> GenHaxl u c)
- newMemo :: GenHaxl u (MemoVar u a)
- newMemoWith :: GenHaxl u a -> GenHaxl u (MemoVar u a)
- prepareMemo :: MemoVar u a -> GenHaxl u a -> GenHaxl u ()
- runMemo :: MemoVar u a -> GenHaxl u a
Basic memoization
cachedComputation :: forall req u a. (Eq (req a), Hashable (req a), Typeable (req a)) => req a -> GenHaxl u a -> GenHaxl u a Source #
cachedComputation
memoizes a Haxl computation. The key is a
request.
Note: These cached computations will not be included in the output
of dumpCacheAsHaskell
.
preCacheComputation :: forall req u a. (Eq (req a), Hashable (req a), Typeable (req a)) => req a -> GenHaxl u a -> GenHaxl u a Source #
Like cachedComputation
, but fails if the cache is already
populated.
Memoization can be (ab)used to "mock" a cached computation, by pre-populating the cache with an alternative implementation. In that case we don't want the operation to populate the cache to silently succeed if the cache is already populated.
High-level memoization
memo :: (Typeable a, Typeable k, Hashable k, Eq k) => k -> GenHaxl u a -> GenHaxl u a Source #
Memoize a computation using an arbitrary key. The result will be
calculated once; the second and subsequent time it will be returned
immediately. It is the caller's responsibility to ensure that for
every two calls memo key haxl
, if they have the same key
then
they compute the same result.
memoFingerprint :: Typeable a => MemoFingerprintKey a -> GenHaxl u a -> GenHaxl u a Source #
data MemoFingerprintKey a where Source #
A memo key derived from a 128-bit MD5 hash. Do not use this directly, it is for use by automatically-generated memoization.
MemoFingerprintKey :: !Word64 -> !Word64 -> Addr# -> Addr# -> MemoFingerprintKey a |
Eq (MemoFingerprintKey a) Source # | |
Hashable (MemoFingerprintKey a) Source # | |
memoize :: GenHaxl u a -> GenHaxl u (GenHaxl u a) Source #
Transform a Haxl computation into a memoized version of itself.
Given a Haxl computation, memoize
creates a version which stores its result
in a MemoVar
(which memoize
creates), and returns the stored result on
subsequent invocations. This permits the creation of local memos, whose
lifetimes are scoped to the current function, rather than the entire request.
memoize1 :: (Eq a, Hashable a) => (a -> GenHaxl u b) -> GenHaxl u (a -> GenHaxl u b) Source #
Transform a 1-argument function returning a Haxl computation into a memoized version of itself.
Given a function f
of type a -> GenHaxl u b
, memoize1
creates a version
which memoizes the results of f
in a table keyed by its argument, and
returns stored results on subsequent invocations with the same argument.
e.g.:
allFriends :: [Int] -> GenHaxl u [Int] allFriends ids = do memoizedFriendsOf <- memoize1 friendsOf concat <$> mapM memoizeFriendsOf ids
The above implementation will not invoke the underlying friendsOf
repeatedly for duplicate values in ids
.
memoize2 :: (Eq a, Hashable a, Eq b, Hashable b) => (a -> b -> GenHaxl u c) -> GenHaxl u (a -> b -> GenHaxl u c) Source #
Transform a 2-argument function returning a Haxl computation, into a memoized version of itself.
The 2-ary version of memoize1
, see its documentation for details.
Local memoization
newMemo :: GenHaxl u (MemoVar u a) Source #
Create a new MemoVar
for storing a memoized computation. The created
MemoVar
is initially empty, not tied to any specific computation. Running
this memo (with runMemo
) without preparing it first (with prepareMemo
)
will result in an exception.
newMemoWith :: GenHaxl u a -> GenHaxl u (MemoVar u a) Source #
Convenience function, combines newMemo
and prepareMemo
.
prepareMemo :: MemoVar u a -> GenHaxl u a -> GenHaxl u () Source #
Store a computation within a supplied MemoVar
. Any memo stored within the
MemoVar
already (regardless of completion) will be discarded, in favor of
the supplied computation. A MemoVar
must be prepared before it is run.
runMemo :: MemoVar u a -> GenHaxl u a Source #
Continue the memoized computation within a given MemoVar
.
Notes:
- If the memo contains a complete result, return that result.
- If the memo contains an in-progress computation, continue it as far as possible for this round.
- If the memo is empty (it was not prepared), throw an error.
For example, to memoize the computation one
given by:
one :: Haxl Int one = return 1
use:
do oneMemo <- newMemoWith one let memoizedOne = runMemo aMemo one oneResult <- memoizedOne
To memoize mutually dependent computations such as in:
h :: Haxl Int h = do a <- f b <- g return (a + b) where f = return 42 g = succ <$> f
without needing to reorder them, use:
h :: Haxl Int h = do fMemoRef <- newMemo gMemoRef <- newMemo let f = runMemo fMemoRef g = runMemo gMemoRef prepareMemo fMemoRef $ return 42 prepareMemo gMemoRef $ succ <$> f a <- f b <- g return (a + b)