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)