-- | -- Module: Data.Chimera -- Copyright: (c) 2018-2019 Andrew Lelechenko -- Licence: BSD3 -- Maintainer: Andrew Lelechenko -- -- Lazy infinite streams with O(1) indexing. module Data.Chimera ( -- * Memoization memoize, memoizeFix, -- * Chimera Chimera, VChimera, UChimera, -- * Construction tabulate, tabulateFix, tabulateFix', iterate, iterateWithIndex, unfoldr, cycle, fromListWithDef, fromVectorWithDef, fromInfinite, -- * Manipulation interleave, prependVector, -- * Elimination index, foldr, toList, toInfinite, -- * Monadic construction -- $monadic tabulateM, tabulateFixM, tabulateFixM', iterateM, iterateWithIndexM, unfoldrM, -- * Subvectors -- $subvectors mapSubvectors, imapSubvectors, traverseSubvectors, zipWithSubvectors, zipWithMSubvectors, sliceSubvectors, ) where import Prelude hiding (Applicative (..), and, cycle, div, drop, foldr, fromIntegral, iterate, not, or, (*), (^)) import Data.Chimera.Internal import Data.Chimera.Memoize -- $monadic -- Be careful: the stream is infinite, so -- monadic effects must be lazy -- in order to be executed in a finite time. -- -- For instance, lazy state monad works fine: -- -- >>> import Control.Monad.State.Lazy -- >>> ch = evalState (tabulateM (\i -> do modify (+ i); get)) 0 :: UChimera Word -- >>> take 10 (toList ch) -- [0,1,3,6,10,15,21,28,36,45] -- -- But the same computation in the strict state -- monad "Control.Monad.State.Strict" diverges. -- $subvectors -- Internally 'Chimera' consists of a number of subvectors. -- Following functions provide a low-level access to them. -- This ability is especially important for streams of booleans. -- -- Let us use 'Chimera' to memoize predicates @f1@, @f2@ @::@ 'Word' @->@ 'Bool'. -- Imagine them both already -- caught in amber as @ch1@, @ch2@ @::@ 'UChimera' 'Bool', -- and now we want to memoize @f3 x = f1 x && f2 x@ as @ch3@. -- One can do it in as follows: -- -- > ch3 = tabulate (\i -> index ch1 i && index ch2 i) -- -- There are two unsatisfactory things here. Firstly, -- even unboxed vectors store only one boolean per byte. -- We would rather reach out for 'Data.Bit.Bit' wrapper, -- which provides an instance of unboxed vector -- with one boolean per bit. Secondly, combining -- existing predicates by indexing them and tabulating again -- becomes relatively expensive, given how small and simple -- our data is. Fortunately, there is an ultra-fast 'Data.Bit.zipBits' -- to zip bit vectors. We can combine it altogether like this: -- -- > import Data.Bit -- > import Data.Bits -- > ch1 = tabulate (Bit . f1) -- > ch2 = tabulate (Bit . f2) -- > ch3 = zipWithSubvectors (zipBits (.&.)) ch1 ch2