From 999f861e7a82cdc09b8a10a4d51912df42c4ddab Mon Sep 17 00:00:00 2001 From: Bodigrim Date: Tue, 26 Dec 2023 12:35:22 +0000 Subject: [PATCH] Extend documentation --- src/Data/Chimera/Internal.hs | 12 ++++++++++++ src/Data/Chimera/Memoize.hs | 22 ++++++++++++++++------ 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/src/Data/Chimera/Internal.hs b/src/Data/Chimera/Internal.hs index be2003f..357e15e 100644 --- a/src/Data/Chimera/Internal.hs +++ b/src/Data/Chimera/Internal.hs @@ -177,6 +177,10 @@ bits = finiteBitSize (0 :: Word) -- >>> take 10 (toList ch) -- [0,1,4,9,16,25,36,49,64,81] -- +-- Note that @a@ could be a function type itself, +-- so one can tabulate a function of multiple arguments +-- as a nested 'Chimera' of 'Chimera's. +-- -- @since 0.2.0.0 tabulate :: G.Vector v a => (Word -> a) -> Chimera v a tabulate f = runIdentity $ tabulateM (coerce f) @@ -226,6 +230,11 @@ tabulateM f = Chimera <$> generateArrayM (bits + 1) tabulateSubVector -- __Note__: Only recursive function calls with decreasing arguments are memoized. -- If full memoization is desired, use 'tabulateFix'' instead. -- +-- Using unboxed \/ storable \/ primitive vectors with 'tabulateFix' is not always a win: +-- the internal memoizing routine necessarily uses boxed vectors to achieve +-- a certain degree of laziness, so converting to 'UChimera' is extra work. +-- This could pay off in a long run by reducing memory residence though. +-- -- @since 0.2.0.0 tabulateFix :: (G.Vector v a, Typeable v) => ((Word -> a) -> Word -> a) -> Chimera v a tabulateFix uf = runIdentity $ tabulateFixM (coerce uf) @@ -252,6 +261,9 @@ tabulateFix uf = runIdentity $ tabulateFixM (coerce uf) -- >>> maximumBy (comparing $ memoizeFix collatzF) [0..1000000] -- 56991483520 -- +-- Since 'tabulateFix'' memoizes all recursive calls, even with increasing argument, +-- you most likely do not want to use it with anything else than boxed vectors ('VChimera'). +-- -- @since 0.3.2.0 tabulateFix' :: (G.Vector v a, Typeable v) => ((Word -> a) -> Word -> a) -> Chimera v a tabulateFix' uf = runIdentity $ tabulateFixM' (coerce uf) diff --git a/src/Data/Chimera/Memoize.hs b/src/Data/Chimera/Memoize.hs index 64e3b72..424f5d1 100644 --- a/src/Data/Chimera/Memoize.hs +++ b/src/Data/Chimera/Memoize.hs @@ -28,11 +28,15 @@ import Data.Chimera.Internal -- would compute @f@ @n@ only once -- and cache the result in 'VChimera'. -- This is just a shortcut for 'index' '.' 'tabulate'. --- When @a@ is 'U.Unbox', it is faster to use --- 'index' ('tabulate' @f@ :: 'UChimera' @a@). -- -- prop> memoize f n = f n -- +-- Note that @a@ could be a function type itself. This allows, for instance, +-- to define +-- +-- > memoize2 :: (Word -> Word -> a) -> Word -> Word -> a +-- > memoize2 = memoize . (memoize .) +-- -- @since 0.3.0.0 memoize :: (Word -> a) -> (Word -> a) memoize = index @V.Vector . tabulate @@ -40,8 +44,6 @@ memoize = index @V.Vector . tabulate -- | For a given @f@ memoize a recursive function 'fix' @f@, -- caching results in 'VChimera'. -- This is just a shortcut for 'index' '.' 'tabulateFix'. --- When @a@ is 'U.Unbox', it is faster to use --- 'index' ('tabulateFix' @f@ :: 'UChimera' @a@). -- -- prop> memoizeFix f n = fix f n -- @@ -64,8 +66,7 @@ memoize = index @V.Vector . tabulate -- -- This function can be used even when arguments -- of recursive calls are not strictly decreasing, --- but they might not get memoized. If this is not desired --- use 'tabulateFix'' instead. +-- but they might not get memoized. -- For example, here is a routine to measure the length of -- : -- @@ -73,6 +74,15 @@ memoize = index @V.Vector . tabulate -- >>> memoizeFix collatzF 27 -- 111 -- +-- If you want to memoize all recursive calls, even with increasing arguments, +-- you can employ another function of the same signature: +-- 'Data.Function.fix' '.' ('memoize' '.'). It is less efficient though. +-- +-- To memoize recursive functions of multiple arguments, one can use +-- +-- > memoizeFix2 :: ((Word -> Word -> a) -> Word -> Word -> a) -> Word -> Word -> a +-- > memoizeFix2 = let memoize2 = memoize . (memoize .) in Data.Function.fix . (memoize2 .) +-- -- @since 0.3.0.0 memoizeFix :: ((Word -> a) -> Word -> a) -> (Word -> a) memoizeFix = index @V.Vector . tabulateFix