@@ -8,12 +8,13 @@
8-- Portability : GHC
8-- Portability : GHC
10-- See "Streamly.Data.Fold" for an overview and
10-- See "Streamly.Data.Fold" for an overview and
11−-- "Streamly.Internal.Data.Fold.Types" for design notes.
11+-- "Streamly.Internal.Data.Fold.Type" for design notes.
13−-- IMPORTANT: keep the signatures consistent with the folds in Streamly.Prelude
15module Streamly.Internal.Data.Fold
13module Streamly.Internal.Data.Fold
17 -- * Fold Type
18 -- * Fold Type
19 , Fold (..)
20 , Fold (..)
@@ -22,19 +23,17 @@ module Streamly.Internal.Data.Fold
22 -- | Which constructor to use?
23 -- | Which constructor to use?
24 -- * @foldl*@: If the fold never terminates i.e. does not use the 'Done'
25 -- * @foldl*@: If the fold never terminates i.e. does not use the 'Done'
25− -- constructor otherwise use the @mkFold@ variants.
26+ -- constructor otherwise use the @foldt*@ variants.
26 -- * @*M@: Use the @M@ suffix variants if any of the step, initial, or
27 -- * @*M@: Use the @M@ suffix variants if any of the step, initial, or
27 -- extract function is monadic, otherwise use the pure variants.
28 -- extract function is monadic, otherwise use the pure variants.
28− -- * @*_@: Use the @_@ suffix variants if the extract function is 'id' or
37− , foldrM
36+ , foldrM'
39 -- * Mappers
38 -- * Mappers
40 -- | Monadic functions useful with mapM/lmapM on folds or streams.
39 -- | Monadic functions useful with mapM/lmapM on folds or streams.
@@ -42,9 +41,6 @@ module Streamly.Internal.Data.Fold
44 -- * Folds
43 -- * Folds
49 -- ** Accumulators
45 -- ** Accumulators
50 -- *** Semigroups and Monoids
46 -- *** Semigroups and Monoids
@@ -55,15 +51,13 @@ module Streamly.Internal.Data.Fold
56 -- *** Reducers
52 -- *** Reducers
58− , drainBy
54+ , drainMapM
61− , genericLength
57+ , lengthGeneric
66 , rollingHash
59 , rollingHash
67 , rollingHashWithSalt
61 , rollingHashWithSalt
68 , rollingHashFirstN
62 , rollingHashFirstN
69 -- , rollingHashLastN
63 -- , rollingHashLastN
@@ -88,8 +82,7 @@ module Streamly.Internal.Data.Fold
88 -- $toListRev
82 -- $toListRev
89 , toStream
83 , toStream
90 , toStreamRev
84 , toStreamRev
91− , toMap
85+ , bottomBy
@@ -98,7 +91,7 @@ module Streamly.Internal.Data.Fold
98 -- the 'scanMaybe' combinator. For scanners the result of the fold is
91 -- the 'scanMaybe' combinator. For scanners the result of the fold is
99 -- usually a transformation of the current element rather than an
92 -- usually a transformation of the current element rather than an
100 -- aggregation of all elements till now.
93 -- aggregation of all elements till now.
101− , last -- XXX prev
94+ , latest
102 -- , nthLast -- using Ring array
95 -- , nthLast -- using Ring array
103 , indexingWith
96 , indexingWith
104 , indexing
97 , indexing
@@ -109,8 +102,6 @@ module Streamly.Internal.Data.Fold
109 -- | Useful in combination with the 'scanMaybe' combinator.
102 -- | Useful in combination with the 'scanMaybe' combinator.
110 , filtering
103 , filtering
111 , deleteBy
104 , deleteBy
116 , repeated
107 , repeated
@@ -118,18 +109,25 @@ module Streamly.Internal.Data.Fold
118 , elemIndices
109 , elemIndices
120 -- ** Terminating Folds
111 -- ** Terminating Folds
121− -- Element folds. Terminate after inspecting one element. All these can be
112+ -- *** Empty folds
113+ -- | Folds that return a result without consuming any input.
117+ -- *** Singleton folds
118+ -- | Folds that terminate after consuming exactly one input element. All
122− -- implemented in terms of the 'maybe' fold.
119+ -- these can be implemented in terms of the 'maybe' fold.
125 , satisfy
122 , satisfy
128− -- Sequence folds. Terminate after inspecting a sequence of elements.
126+ -- | Terminate after consuming one or more elements.
130 -- , lastN
128 -- , lastN
131 -- , (!!)
129 -- , (!!)
132− , genericIndex
130+ , indexGeneric
@@ -155,6 +153,20 @@ module Streamly.Internal.Data.Fold
155 , droppingWhile
153 , droppingWhile
160+ -- * Building Incrementally
158 -- * Combinators
170 -- * Combinators
159 -- ** Utilities
171 -- ** Utilities
@@ -182,8 +194,8 @@ module Streamly.Internal.Data.Fold
182 , indexed
194 , indexed
184 -- ** Zipping Input
196 -- ** Zipping Input
185− , zipWithM
197+ , zipStreamWithM
186− , zip
198+ , zipStream
188 -- ** Filtering Input
200 -- ** Filtering Input
189 , catMaybes
201 , catMaybes
@@ -260,41 +272,6 @@ module Streamly.Internal.Data.Fold
260 , partitionBy
272 , partitionBy
261 , partition
273 , partition
263− -- ** Demultiplexing
264− -- | Direct values in the input stream to different folds using an n-ary
265− -- fold selector. 'demux' is a generalization of 'classify' (and
266− -- 'partition') where each key of the classifier can use a different fold.
273− -- TODO: These can be implemented using the above operations
274− -- , demuxWithSel -- Stop when the fold for the specified key stops
275− -- , demuxWithMin -- Stop when any of the folds stop
276− -- , demuxWithAll -- Stop when all the folds stop (run once)
279− -- | In an input stream of key value pairs fold values for different keys
280− -- in individual output buckets using the given fold. 'classify' is a
281− -- special case of 'demux' where all the branches of the demultiplexer use
284− -- Different types of maps can be used with these combinators via the IsMap
285− -- type class. Hashmap performs better when there are more collisions, trie
286− -- Map performs better otherwise. Trie has an advantage of sorting the keys
287− -- at the same time. For example if we want to store a dictionary of words
288− -- and their meanings then trie Map would be better if we also want to
289− -- display them in sorted order.
295− -- , classifyWithSel
296− -- , classifyWithMin
298 -- ** Splitting
275 -- ** Splitting
300 , chunksOf
277 , chunksOf
@@ -304,20 +281,12 @@ module Streamly.Internal.Data.Fold
304 , unfoldMany
281 , unfoldMany
305 , concatSequence
282 , concatSequence
306 , concatMap
283 , concatMap
309− -- | Normally you would run a fold to completion by supplying it a stream,
310− -- e.g. using 'Stream.fold'. However, you could also run a fold partially
311− -- by using 'duplicate' on it and then running it with a stream.
312− -- Alternatively, 'initialize', 'snoc' and 'finish' can be used to run a
313− -- fold incrementally, however, that may not be the most efficient way to
317 , duplicate
284 , duplicate
320 -- * Deprecated
286 -- * Deprecated
322 , sequence
291 , sequence
@@ -336,11 +305,8 @@ import Data.Bits (shiftL, shiftR, (.|.), (.&.))
336import Data.Either (isLeft, isRight, fromLeft, fromRight)
305import Data.Either (isLeft, isRight, fromLeft, fromRight)
337import Data.Functor.Identity (Identity(..))
306import Data.Functor.Identity (Identity(..))
338import Data.Int (Int64)
307import Data.Int (Int64)
339−import Data.IORef (newIORef, readIORef, writeIORef)
340−import Data.Map.Strict (Map)
341import Data.Word (Word32)
308import Data.Word (Word32)
342import Foreign.Storable (peek, sizeOf)
309import Foreign.Storable (peek, sizeOf)
343−import Streamly.Internal.Data.IsMap (IsMap(..))
344import Streamly.Internal.Data.Maybe.Strict (Maybe'(..), toMaybe)
310import Streamly.Internal.Data.Maybe.Strict (Maybe'(..), toMaybe)
345import Streamly.Internal.Data.Pipe.Type (Pipe (..), PipeState(..))
311import Streamly.Internal.Data.Pipe.Type (Pipe (..), PipeState(..))
346import Streamly.Internal.Data.Unboxed (Unbox)
312import Streamly.Internal.Data.Unboxed (Unbox)
@@ -348,16 +314,14 @@ import Streamly.Internal.Data.Unfold.Type (Unfold(..))
348import Streamly.Internal.Data.Tuple.Strict (Tuple'(..), Tuple3'(..))
314import Streamly.Internal.Data.Tuple.Strict (Tuple'(..), Tuple3'(..))
349import Streamly.Internal.Data.Stream.Type (Stream)
315import Streamly.Internal.Data.Stream.Type (Stream)
351−import qualified Data.IntSet as IntSet
352−import qualified Data.Set as Set
353import qualified Prelude
317import qualified Prelude
354import qualified Streamly.Internal.Data.Array.Unboxed.Mut.Type as MA
318import qualified Streamly.Internal.Data.Array.Unboxed.Mut.Type as MA
355import qualified Streamly.Internal.Data.Array.Unboxed.Type as Array
319import qualified Streamly.Internal.Data.Array.Unboxed.Type as Array
356import qualified Streamly.Internal.Data.Fold.Window as FoldW
320import qualified Streamly.Internal.Data.Fold.Window as FoldW
357−import qualified Streamly.Internal.Data.IsMap as IsMap
358import qualified Streamly.Internal.Data.Pipe.Type as Pipe
321import qualified Streamly.Internal.Data.Pipe.Type as Pipe
359import qualified Streamly.Internal.Data.Ring.Unboxed as Ring
322import qualified Streamly.Internal.Data.Ring.Unboxed as Ring
360import qualified Streamly.Internal.Data.Stream.StreamD.Type as StreamD
323import qualified Streamly.Internal.Data.Stream.StreamD.Type as StreamD
324+import qualified Streamly.Internal.Data.Stream.StreamK as K
361import qualified Streamly.Internal.Data.Stream.Type as Stream
325import qualified Streamly.Internal.Data.Stream.Type as Stream
363import Prelude hiding
327import Prelude hiding
@@ -371,7 +335,13 @@ import Streamly.Internal.Data.Fold.Type
374−-- >>> import Prelude hiding (break, map, span, splitAt)
338+-- >>> :set -package random
339+-- >>> import Control.Monad (void)
340+-- >>> import Data.Functor.Identity (runIdentity)
341+-- >>> import Data.Maybe (isJust)
342+-- >>> import Data.Monoid (Last(..), Sum(..))
343+-- >>> import Streamly.Data.Stream (Stream)
344+-- >>> import Data.IORef (newIORef, readIORef, writeIORef)
375-- >>> import qualified Streamly.Data.Array.Unboxed as Array
345-- >>> import qualified Streamly.Data.Array.Unboxed as Array
376-- >>> import qualified Streamly.Data.Fold as Fold
346-- >>> import qualified Streamly.Data.Fold as Fold
377-- >>> import qualified Streamly.Data.Stream as Stream
347-- >>> import qualified Streamly.Data.Stream as Stream
@@ -382,8 +352,60 @@ import Streamly.Internal.Data.Fold.Type
382-- >>> import qualified Streamly.Internal.Data.Parser as Parser
352-- >>> import qualified Streamly.Internal.Data.Parser as Parser
383-- >>> import qualified Streamly.Internal.Data.Stream.Type as Stream
353-- >>> import qualified Streamly.Internal.Data.Stream.Type as Stream
384-- >>> import qualified Streamly.Internal.Data.Unfold as Unfold
354-- >>> import qualified Streamly.Internal.Data.Unfold as Unfold
385−-- >>> import Streamly.Internal.Data.Stream.Type (Stream)
355+-- >>> import Prelude hiding (break, map, span, splitAt)
386−-- >>> import Data.IORef (newIORef, readIORef, writeIORef)
356+
357+------------------------------------------------------------------------------
359+------------------------------------------------------------------------------
361+-- | Drive a fold using the supplied 'Stream', reducing the resulting
362+-- expression strictly at each step.
366+-- >>> drive = flip Stream.fold
370+-- >>> Fold.drive (Stream.enumerateFromTo 1 100) Fold.sum
374+drive :: Monad m => Stream m a -> Fold m a b -> m b
375+drive strm fl = StreamD.fold fl $ StreamD.fromStreamK $ Stream.toStreamK strm
377+-- | Like 'drive' but also returns the remaining stream. The resulting stream
378+-- would be 'Stream.nil' if the stream finished before the fold.
382+-- >>> driveBreak = flip Stream.foldBreak
386+{-# INLINE driveBreak #-}
387+driveBreak :: Monad m => Stream m a -> Fold m a b -> m (b, Stream m a)
388+driveBreak strm fl = fmap f $ K.foldBreak fl (Stream.toStreamK strm)
392+ f (b, str) = (b, Stream.fromStreamK str)
394+-- | Augment a fold strictly by adding a stream to it.
398+-- >>> augment stream = Fold.drive stream . Fold.duplicate
401+-- Fold.augment (Stream.enumerateFromTo 1 10) Fold.sum
402+-- >>= Fold.augment (Stream.enumerateFromTo 11 20)
403+-- >>= Fold.drive (Stream.enumerateFromTo 21 30)
407+augment :: Monad m => Stream m a -> Fold m a b -> m (Fold m a b)
408+augment stream = drive stream . duplicate
388------------------------------------------------------------------------------
410------------------------------------------------------------------------------
@@ -398,7 +420,7 @@ hoist f (Fold step initial extract) =
399-- | Adapt a pure fold to any monad
421-- | Adapt a pure fold to any monad
401−-- > generally = Fold.hoist (return . runIdentity)
423+-- >>> generally = Fold.hoist (return . runIdentity)
403-- /Pre-release/
425-- /Pre-release/
404generally :: Monad m => Fold Identity a b -> Fold m a b
426generally :: Monad m => Fold Identity a b -> Fold m a b
@@ -575,10 +597,12 @@ scanMany = scanWith True
575-- Filters
597-- Filters
576------------------------------------------------------------------------------
598------------------------------------------------------------------------------
578−-- | A filtering scan that deletes the first occurrence of the element in the
600+-- | Returns the latest element omitting the first occurrence that satisfies
579−-- stream that satisfies the given equality predicate.
601+-- the given equality predicate.
581−-- >>> input = Stream.unfold Unfold.fromList [1,3,3,5]
605+-- >>> input = Stream.fromList [1,3,3,5]
582-- >>> Stream.fold Fold.toList $ Stream.scanMaybe (Fold.deleteBy (==) 3) input
606-- >>> Stream.fold Fold.toList $ Stream.scanMaybe (Fold.deleteBy (==) 3) input
583-- [1,3,5]
607-- [1,3,5]
@@ -614,20 +638,19 @@ slide2 (Fold step1 initial1 extract1) = Fold step initial extract
615 extract (Tuple' _ s) = extract1 s
639 extract (Tuple' _ s) = extract1 s
617−-- | Drop repeated elements that are adjacent to each other using the supplied
618−-- comparison function.
641+-- | Return the latest unique element using the supplied comparison function.
642+-- Returns 'Nothing' if the current element is same as the last element
643+-- otherwise returns 'Just'.
620−-- To strip duplicate path separators:
645+-- Example, strip duplicate path separators:
622−-- >>> input = Stream.unfold Unfold.fromList "//a//b"
647+-- >>> input = Stream.fromList "//a//b"
623-- >>> f x y = x == '/' && y == '/'
648-- >>> f x y = x == '/' && y == '/'
624-- >>> Stream.fold Fold.toList $ Stream.scanMaybe (Fold.uniqBy f) input
649-- >>> Stream.fold Fold.toList $ Stream.scanMaybe (Fold.uniqBy f) input
627-- Space: @O(1)@
652-- Space: @O(1)@
629−-- See also: 'nubBy'.
631-- /Pre-release/
654-- /Pre-release/
633{-# INLINE uniqBy #-}
656{-# INLINE uniqBy #-}
@@ -641,7 +664,9 @@ uniqBy eq = rollingMap f
641 Nothing -> Just curr
664 Nothing -> Just curr
642 Just x -> if x `eq` curr then Nothing else Just curr
665 Just x -> if x `eq` curr then Nothing else Just curr
644−-- | Drop repeated elements that are adjacent to each other.
667+-- | See 'uniqBy'.
646-- >>> uniq = Fold.uniqBy (==)
671-- >>> uniq = Fold.uniqBy (==)
@@ -676,43 +701,6 @@ repeated :: -- (Monad m, Eq a) =>
676 Fold m a (Maybe a)
701 Fold m a (Maybe a)
677repeated = error "Not implemented yet!"
702repeated = error "Not implemented yet!"
679−-- | Used as a scan. Returns 'Just' for the first occurrence of an element,
680−-- returns 'Nothing' for any other occurrences.
682−-- >>> stream = Stream.fromList [1::Int,1,2,3,4,4,5,1,5,7]
683−-- >>> Stream.fold Fold.toList $ Stream.mapMaybe id $ Stream.postscan Fold.nub stream
688−nub :: (Monad m, Ord a) => Fold m a (Maybe a)
689−nub = fmap (\(Tuple' _ x) -> x) $ foldl' step initial
693− initial = Tuple' Set.empty Nothing
695− step (Tuple' set _) x =
697− then Tuple' set Nothing
698− else Tuple' (Set.insert x set) (Just x)
700−-- | Like 'nub' but specialized to a stream of 'Int', for better performance.
703−{-# INLINE nubInt #-}
704−nubInt :: Monad m => Fold m Int (Maybe Int)
705−nubInt = fmap (\(Tuple' _ x) -> x) $ foldl' step initial
709− initial = Tuple' IntSet.empty Nothing
711− step (Tuple' set _) x =
712− if IntSet.member x set
713− then Tuple' set Nothing
714− else Tuple' (IntSet.insert x set) (Just x)
716------------------------------------------------------------------------------
704------------------------------------------------------------------------------
717-- Left folds
705-- Left folds
718------------------------------------------------------------------------------
706------------------------------------------------------------------------------
@@ -722,28 +710,40 @@ nubInt = fmap (\(Tuple' _ x) -> x) $ foldl' step initial
722------------------------------------------------------------------------------
710------------------------------------------------------------------------------
725−-- > drainBy f = lmapM f drain
715+-- >>> drainMapM f = Fold.lmapM f Fold.drain
726−-- > drainBy = Fold.foldMapM (void . f)
716+-- >>> drainMapM f = Fold.foldMapM (void . f)
728-- Drain all input after passing it through a monadic function. This is the
718-- Drain all input after passing it through a monadic function. This is the
729-- dual of mapM_ on stream producers.
719-- dual of mapM_ on stream producers.
731−-- See also: 'Streamly.Prelude.mapM_'
721+{-# INLINE drainMapM #-}
732−--
722+drainMapM :: Monad m => (a -> m b) -> Fold m a ()
723+drainMapM f = lmapM f drain
725+{-# DEPRECATED drainBy "Please use 'drainMapM' instead." #-}
733{-# INLINE drainBy #-}
726{-# INLINE drainBy #-}
734drainBy :: Monad m => (a -> m b) -> Fold m a ()
727drainBy :: Monad m => (a -> m b) -> Fold m a ()
735−drainBy f = lmapM f drain
728+drainBy = drainMapM
737−-- | Extract the last element of the input stream, if any.
730+-- | Returns the latest element of the input stream, if any.
732+-- >>> latest = Fold.foldl1' (\_ x -> x)
739−-- > last = fmap getLast $ Fold.foldMap (Last . Just)
733+-- >>> latest = fmap getLast $ Fold.foldMap (Last . Just)
735+{-# INLINE latest #-}
736+latest :: Monad m => Fold m a (Maybe a)
737+latest = foldl1' (\_ x -> x)
739+{-# DEPRECATED last "Please use 'latest' instead." #-}
741{-# INLINE last #-}
740{-# INLINE last #-}
742last :: Monad m => Fold m a (Maybe a)
741last :: Monad m => Fold m a (Maybe a)
743−last = foldl1' (\_ x -> x)
742+last = latest
745−-- | If the stream consists of one or more occurences of the same element
744+-- | Terminates with 'Nothing' as soon as it finds an element different than
746−-- then returns that element else terminates and returns 'Nothing'.
745+-- the previous one, returns 'the' element if the entire input consists of the
748{-# INLINE the #-}
748{-# INLINE the #-}
749the :: (Monad m, Eq a) => Fold m a (Maybe a)
749the :: (Monad m, Eq a) => Fold m a (Maybe a)
@@ -765,82 +765,27 @@ the = foldt' step initial id
766-- | Like 'length', except with a more general 'Num' return value
766-- | Like 'length', except with a more general 'Num' return value
768−-- > genericLength = fmap getSum $ foldMap (Sum . const 1)
770+-- >>> lengthGeneric = fmap getSum $ Fold.foldMap (Sum . const 1)
771+-- >>> lengthGeneric = Fold.foldl' (\n _ -> n + 1) 0
770-- /Pre-release/
773-- /Pre-release/
771−{-# INLINE genericLength #-}
774+{-# INLINE lengthGeneric #-}
772−genericLength :: (Monad m, Num b) => Fold m a b
775+lengthGeneric :: (Monad m, Num b) => Fold m a b
773−genericLength = foldl' (\n _ -> n + 1) 0
776+lengthGeneric = foldl' (\n _ -> n + 1) 0
775-- | Determine the length of the input stream.
778-- | Determine the length of the input stream.
782+-- >>> length = Fold.lengthGeneric
777−-- > length = fmap getSum $ Fold.foldMap (Sum . const 1)
783+-- >>> length = fmap getSum $ Fold.foldMap (Sum . const 1)
779{-# INLINE length #-}
785{-# INLINE length #-}
780length :: Monad m => Fold m a Int
786length :: Monad m => Fold m a Int
781−length = genericLength
787+length = lengthGeneric
784−-- XXX Add a countDistinct window fold
785−-- XXX Add a bloom filter fold
787−-- | Count non-duplicate elements in the stream.
789−-- Equivalent to using 'nub' followed by 'length' on a stream.
791−-- >>> countDistinct = Fold.postscan Fold.nub $ Fold.catMaybes $ Fold.length
793−-- The memory used is proportional to the number of distinct elements in the
794−-- stream, to guard against using too much memory use it as a scan and
795−-- terminate if the count reaches more than a threshold.
797−-- /Space/: \(\mathcal{O}(n)\)
801−{-# INLINE countDistinct #-}
802−countDistinct :: (Monad m, Ord a) => Fold m a Int
803−countDistinct = postscan nub $ catMaybes length
805−countDistinct = fmap (\(Tuple' _ n) -> n) $ foldl' step initial
809− initial = Tuple' Set.empty 0
811− step (Tuple' set n) x = do
817− in Tuple' (Set.insert x set) cnt
820−-- | Like 'countDistinct' but specialized to a stream of 'Int', for better
823−-- >>> countDistinctInt = Fold.postscan Fold.nubInt $ Fold.catMaybes $ Fold.length
826−{-# INLINE countDistinctInt #-}
827−countDistinctInt :: Monad m => Fold m Int Int
828−countDistinctInt = postscan nubInt $ catMaybes length
830−countDistinctInt = fmap (\(Tuple' _ n) -> n) $ foldl' step initial
834− initial = Tuple' IntSet.empty 0
836− step (Tuple' set n) x = do
837− if IntSet.member x set
842− in Tuple' (IntSet.insert x set) cnt
845-- | Determine the sum of all elements of a stream of numbers. Returns additive
790-- | Determine the sum of all elements of a stream of numbers. Returns additive
846-- identity (@0@) when the stream is empty. Note that this is not numerically
791-- identity (@0@) when the stream is empty. Note that this is not numerically
@@ -861,7 +806,9 @@ sum = FoldW.cumulative FoldW.sum
861-- multiplicative identity (@1@) when the stream is empty. The fold terminates
806-- multiplicative identity (@1@) when the stream is empty. The fold terminates
862-- when it encounters (@0@) in its input.
807-- when it encounters (@0@) in its input.
809+-- Same as the following but terminates on multiplication by @0@:
864−-- Compare with @Fold.foldMap Product@.
811+-- >>> product = fmap Data.Monoid.getProduct $ Fold.foldMap Data.Monoid.Product
866{-# INLINE product #-}
813{-# INLINE product #-}
867product :: (Monad m, Num a, Eq a) => Fold m a a
814product :: (Monad m, Num a, Eq a) => Fold m a a
@@ -892,14 +839,17 @@ maximumBy cmp = foldl1' max'
895−-- |
842+-- | Determine the maximum element in a stream.
897−-- maximum = Fold.maximumBy compare
900−-- Determine the maximum element in a stream.
846+-- >>> maximum = Fold.maximumBy compare
847+-- >>> maximum = Fold.foldl1' max
902−-- Compare with @Fold.foldMap Max@.
849+-- Same as the following but without a default maximum. The 'Max' Monoid uses
850+-- the 'minBound' as the default maximum:
852+-- >>> maximum = fmap Data.Semigroup.getMax $ Fold.foldMap Data.Semigroup.Max
904{-# INLINE maximum #-}
854{-# INLINE maximum #-}
905maximum :: (Monad m, Ord a) => Fold m a (Maybe a)
855maximum :: (Monad m, Ord a) => Fold m a (Maybe a)
@@ -921,11 +871,15 @@ minimumBy cmp = foldl1' min'
921-- | Determine the minimum element in a stream using the supplied comparison
871-- | Determine the minimum element in a stream using the supplied comparison
922-- function.
872-- function.
924−-- @
874+-- Definitions:
925−-- minimum = 'minimumBy' compare
876+-- >>> minimum = Fold.minimumBy compare
926−-- @
877+-- >>> minimum = Fold.foldl1' min
879+-- Same as the following but without a default minimum. The 'Min' Monoid uses the
880+-- 'maxBound' as the default maximum:
928−-- Compare with @Fold.foldMap Min@.
882+-- >>> maximum = fmap Data.Semigroup.getMin $ Fold.foldMap Data.Semigroup.Min
930{-# INLINE minimum #-}
884{-# INLINE minimum #-}
931minimum :: (Monad m, Ord a) => Fold m a (Maybe a)
885minimum :: (Monad m, Ord a) => Fold m a (Maybe a)
@@ -1011,7 +965,7 @@ defaultSalt = -2578643520546668380
1012-- | Compute an 'Int' sized polynomial rolling hash of a stream.
966-- | Compute an 'Int' sized polynomial rolling hash of a stream.
1014−-- > rollingHash = Fold.rollingHashWithSalt defaultSalt
968+-- >>> rollingHash = Fold.rollingHashWithSalt Fold.defaultSalt
1016{-# INLINE rollingHash #-}
970{-# INLINE rollingHash #-}
1017rollingHash :: (Monad m, Enum a) => Fold m a Int64
971rollingHash :: (Monad m, Enum a) => Fold m a Int64
@@ -1020,7 +974,7 @@ rollingHash = rollingHashWithSalt defaultSalt
1020-- | Compute an 'Int' sized polynomial rolling hash of the first n elements of
974-- | Compute an 'Int' sized polynomial rolling hash of the first n elements of
1021-- a stream.
975-- a stream.
1023−-- > rollingHashFirstN = Fold.take n Fold.rollingHash
977+-- >>> rollingHashFirstN n = Fold.take n Fold.rollingHash
1025-- /Pre-release/
979-- /Pre-release/
1026{-# INLINE rollingHashFirstN #-}
980{-# INLINE rollingHashFirstN #-}
@@ -1053,6 +1007,9 @@ rollingMapM f = Fold step initial extract
1054 extract = return . snd
1008 extract = return . snd
1011+-- >>> rollingMap f = Fold.rollingMapM (\x y -> return $ f x y)
1056{-# INLINE rollingMap #-}
1013{-# INLINE rollingMap #-}
1057rollingMap :: Monad m => (Maybe a -> a -> b) -> Fold m a b
1014rollingMap :: Monad m => (Maybe a -> a -> b) -> Fold m a b
1058rollingMap f = rollingMapM (\x y -> return $ f x y)
1015rollingMap f = rollingMapM (\x y -> return $ f x y)
@@ -1061,26 +1018,31 @@ rollingMap f = rollingMapM (\x y -> return $ f x y)
1061-- Monoidal left folds
1018-- Monoidal left folds
1062------------------------------------------------------------------------------
1019------------------------------------------------------------------------------
1064−-- | Append the elements of an input stream to a provided starting value.
1021+-- | Semigroup concat. Append the elements of an input stream to a provided
1066−-- >>> Stream.fold (Fold.sconcat 10) (fmap Data.Monoid.Sum $ Stream.enumerateFromTo 1 10)
1024+-- Definition:
1067−-- Sum {getSum = 65}
1070−-- sconcat = Fold.foldl' (<>)
1026+-- >>> sconcat = Fold.foldl' (<>)
1028+-- >>> semigroups = fmap Data.Monoid.Sum $ Stream.enumerateFromTo 1 10
1029+-- >>> Stream.fold (Fold.sconcat 10) semigroups
1030+-- Sum {getSum = 65}
1073{-# INLINE sconcat #-}
1032{-# INLINE sconcat #-}
1074sconcat :: (Monad m, Semigroup a) => a -> Fold m a a
1033sconcat :: (Monad m, Semigroup a) => a -> Fold m a a
1075sconcat = foldl' (<>)
1034sconcat = foldl' (<>)
1077−-- | Fold an input stream consisting of monoidal elements using 'mappend'
1036+-- | Monoid concat. Fold an input stream consisting of monoidal elements using
1078−-- and 'mempty'.
1037+-- 'mappend' and 'mempty'.
1080−-- >>> Stream.fold Fold.mconcat (fmap Data.Monoid.Sum $ Stream.enumerateFromTo 1 10)
1039+-- Definition:
1081−-- Sum {getSum = 55}
1083−-- > mconcat = Fold.sconcat mempty
1041+-- >>> mconcat = Fold.sconcat mempty
1043+-- >>> monoids = fmap Data.Monoid.Sum $ Stream.enumerateFromTo 1 10
1044+-- >>> Stream.fold Fold.mconcat monoids
1045+-- Sum {getSum = 55}
1085{-# INLINE mconcat #-}
1047{-# INLINE mconcat #-}
1086mconcat ::
1048mconcat ::
@@ -1089,26 +1051,31 @@ mconcat ::
1089mconcat = sconcat mempty
1051mconcat = sconcat mempty
1092−-- > foldMap f = Fold.lmap f Fold.mconcat
1056+-- >>> foldMap f = Fold.lmap f Fold.mconcat
1094-- Make a fold from a pure function that folds the output of the function
1058-- Make a fold from a pure function that folds the output of the function
1095-- using 'mappend' and 'mempty'.
1059-- using 'mappend' and 'mempty'.
1097−-- >>> Stream.fold (Fold.foldMap Data.Monoid.Sum) $ Stream.enumerateFromTo 1 10
1061+-- >>> sum = Fold.foldMap Data.Monoid.Sum
1062+-- >>> Stream.fold sum $ Stream.enumerateFromTo 1 10
1098-- Sum {getSum = 55}
1063-- Sum {getSum = 55}
1100{-# INLINE foldMap #-}
1065{-# INLINE foldMap #-}
1101−foldMap :: (Monad m, Monoid b
1066+foldMap :: (Monad m, Monoid b) => (a -> b) -> Fold m a b
1102− ) => (a -> b) -> Fold m a b
1103foldMap f = lmap f mconcat
1067foldMap f = lmap f mconcat
1106−-- > foldMapM f = Fold.lmapM f Fold.mconcat
1072+-- >>> foldMapM f = Fold.lmapM f Fold.mconcat
1108-- Make a fold from a monadic function that folds the output of the function
1074-- Make a fold from a monadic function that folds the output of the function
1109-- using 'mappend' and 'mempty'.
1075-- using 'mappend' and 'mempty'.
1111−-- >>> Stream.fold (Fold.foldMapM (return . Data.Monoid.Sum)) $ Stream.enumerateFromTo 1 10
1077+-- >>> sum = Fold.foldMapM (return . Data.Monoid.Sum)
1078+-- >>> Stream.fold sum $ Stream.enumerateFromTo 1 10
1112-- Sum {getSum = 55}
1079-- Sum {getSum = 55}
1114{-# INLINE foldMapM #-}
1081{-# INLINE foldMapM #-}
@@ -1131,7 +1098,9 @@ foldMapM act = foldlM' step (pure mempty)
1132-- | Buffers the input stream to a list in the reverse order of the input.
1099-- | Buffers the input stream to a list in the reverse order of the input.
1134−-- > toListRev = Fold.foldl' (flip (:)) []
1103+-- >>> toListRev = Fold.foldl' (flip (:)) []
1136-- /Warning!/ working on large lists accumulated as buffers in memory could be
1105-- /Warning!/ working on large lists accumulated as buffers in memory could be
1137-- very inefficient, consider using "Streamly.Array" instead.
1106-- very inefficient, consider using "Streamly.Array" instead.
@@ -1149,7 +1118,9 @@ toListRev = foldl' (flip (:)) []
1149-- | A fold that drains the first n elements of its input, running the effects
1118-- | A fold that drains the first n elements of its input, running the effects
1150-- and discarding the results.
1119-- and discarding the results.
1152−-- > drainN n = Fold.take n Fold.drain
1123+-- >>> drainN n = Fold.take n Fold.drain
1154-- /Pre-release/
1125-- /Pre-release/
1155{-# INLINE drainN #-}
1126{-# INLINE drainN #-}
@@ -1163,9 +1134,9 @@ drainN n = take n drain
1163-- | Like 'index', except with a more general 'Integral' argument
1134-- | Like 'index', except with a more general 'Integral' argument
1165-- /Pre-release/
1136-- /Pre-release/
1166−{-# INLINE genericIndex #-}
1137+{-# INLINE indexGeneric #-}
1167−genericIndex :: (Integral i, Monad m) => i -> Fold m a (Maybe a)
1138+indexGeneric :: (Integral i, Monad m) => i -> Fold m a (Maybe a)
1168−genericIndex i = foldt' step (Partial 0) (const Nothing)
1139+indexGeneric i = foldt' step (Partial 0) (const Nothing)
@@ -1174,15 +1145,18 @@ genericIndex i = foldt' step (Partial 0) (const Nothing)
1174 then Done $ Just a
1145 then Done $ Just a
1175 else Partial (j + 1)
1146 else Partial (j + 1)
1177−-- | Lookup the element at the given index.
1148+-- | Return the element at the given index.
1179−-- See also: 'Streamly.Prelude.!!'
1150+-- Definition:
1152+-- >>> index = Fold.indexGeneric
1181{-# INLINE index #-}
1154{-# INLINE index #-}
1182index :: Monad m => Int -> Fold m a (Maybe a)
1155index :: Monad m => Int -> Fold m a (Maybe a)
1183−index = genericIndex
1156+index = indexGeneric
1158+-- | Consume a single input and transform it using the supplied 'Maybe'
1185−-- | Map a 'Maybe' returning function on the next element in the stream.
1159+-- returning function.
1187-- /Pre-release/
1161-- /Pre-release/
@@ -1190,16 +1164,24 @@ index = genericIndex
1190maybe :: Monad m => (a -> Maybe b) -> Fold m a (Maybe b)
1164maybe :: Monad m => (a -> Maybe b) -> Fold m a (Maybe b)
1191maybe f = foldt' (const (Done . f)) (Partial Nothing) id
1165maybe f = foldt' (const (Done . f)) (Partial Nothing) id
1193−-- | Test if the next element satisfies the supplied predicate.
1167+-- | Consume a single element and return it if it passes the predicate else
1168+-- return 'Nothing'.
1172+-- >>> satisfy f = Fold.maybe (\a -> if f a then Just a else Nothing)
1195-- /Pre-release/
1174-- /Pre-release/
1196{-# INLINE satisfy #-}
1175{-# INLINE satisfy #-}
1197satisfy :: Monad m => (a -> Bool) -> Fold m a (Maybe a)
1176satisfy :: Monad m => (a -> Bool) -> Fold m a (Maybe a)
1177+satisfy f = maybe (\a -> if f a then Just a else Nothing)
1198satisfy f = Fold step (return $ Partial ()) (const (return Nothing))
1179satisfy f = Fold step (return $ Partial ()) (const (return Nothing))
1202 step () a = return $ Done $ if f a then Just a else Nothing
1183 step () a = return $ Done $ if f a then Just a else Nothing
1204-- Naming notes:
1186-- Naming notes:
@@ -1228,6 +1210,12 @@ satisfy f = Fold step (return $ Partial ()) (const (return Nothing))
1229-- | Take one element from the stream and stop.
1211-- | Take one element from the stream and stop.
1215+-- >>> one = Fold.maybe Just
1217+-- This is similar to the stream 'Stream.uncons' operation.
1231{-# INLINE one #-}
1219{-# INLINE one #-}
1232one :: Monad m => Fold m a (Maybe a)
1220one :: Monad m => Fold m a (Maybe a)
1233one = maybe Just
1221one = maybe Just
@@ -1266,7 +1254,9 @@ find p = findM (return . p)
1266-- | In a stream of (key-value) pairs @(a, b)@, return the value @b@ of the
1254-- | In a stream of (key-value) pairs @(a, b)@, return the value @b@ of the
1267-- first pair where the key equals the given value @a@.
1255-- first pair where the key equals the given value @a@.
1269−-- > lookup = snd <$> Fold.find ((==) . fst)
1259+-- >>> lookup x = fmap snd <$> Fold.find ((== x) . fst)
1271{-# INLINE lookup #-}
1261{-# INLINE lookup #-}
1272lookup :: (Eq a, Monad m) => a -> Fold m (a,b) (Maybe b)
1262lookup :: (Eq a, Monad m) => a -> Fold m (a,b) (Maybe b)
@@ -1292,10 +1282,8 @@ findIndex predicate = foldt' step (Partial 0) (const Nothing)
1292 then Done $ Just i
1282 then Done $ Just i
1293 else Partial (i + 1)
1283 else Partial (i + 1)
1295−-- XXX If we have a Continue contructor we won't need a Maybe type for the
1285+-- | Returns the index of the latest element if the element satisfies the given
1296−-- scan. The fold will have the ability to skip producing output.
1286+-- predicate.
1298−-- | Returns all indices that satisfy the given predicate.
1300{-# INLINE findIndices #-}
1288{-# INLINE findIndices #-}
1301findIndices :: Monad m => (a -> Bool) -> Fold m a (Maybe Int)
1289findIndices :: Monad m => (a -> Bool) -> Fold m a (Maybe Int)
@@ -1310,8 +1298,10 @@ findIndices predicate =
1310 then Right (either id id i + 1)
1298 then Right (either id id i + 1)
1311 else Left (either id id i + 1)
1299 else Left (either id id i + 1)
1313−-- | Find all the indices where the value of the element in the stream is equal
1301+-- | Returns the index of the latest element if the element matches the given
1314−-- to the given value.
1302+-- value.
1316-- >>> elemIndices a = Fold.findIndices (== a)
1306-- >>> elemIndices a = Fold.findIndices (== a)
@@ -1321,31 +1311,46 @@ elemIndices a = findIndices (== a)
1322-- | Returns the first index where a given value is found in the stream.
1312-- | Returns the first index where a given value is found in the stream.
1324−-- > elemIndex a = Fold.findIndex (== a)
1316+-- >>> elemIndex a = Fold.findIndex (== a)
1326{-# INLINE elemIndex #-}
1318{-# INLINE elemIndex #-}
1327elemIndex :: (Eq a, Monad m) => a -> Fold m a (Maybe Int)
1319elemIndex :: (Eq a, Monad m) => a -> Fold m a (Maybe Int)
1328−elemIndex a = findIndex (a ==)
1320+elemIndex a = findIndex (== a)
1330------------------------------------------------------------------------------
1322------------------------------------------------------------------------------
1331-- To Boolean
1323-- To Boolean
1332------------------------------------------------------------------------------
1324------------------------------------------------------------------------------
1326+-- Similar to 'eof' parser, but the fold consumes and discards an input element
1327+-- when not at eof. XXX Remove or Rename to "eof"?
1329+-- | Consume one element, return 'True' if successful else return 'False'. In
1334−-- | Return 'True' if the input stream is empty.
1330+-- other words, test if the input is empty or not.
1332+-- WARNING! It consumes one element if the stream is not empty. If that is not
1333+-- what you want please use the eof parser instead.
1336−-- > null = fmap isJust Fold.one
1337+-- >>> null = fmap isJust Fold.one
1338{-# INLINE null #-}
1339{-# INLINE null #-}
1339null :: Monad m => Fold m a Bool
1340null :: Monad m => Fold m a Bool
1340null = foldt' (\() _ -> Done False) (Partial ()) (const True)
1341null = foldt' (\() _ -> Done False) (Partial ()) (const True)
1342−-- | Returns 'True' if any of the elements of a stream satisfies a predicate.
1343+-- | Returns 'True' if any element of the input satisfies the predicate.
1347+-- >>> any p = Fold.lmap p Fold.or
1344-- >>> Stream.fold (Fold.any (== 0)) $ Stream.fromList [1,0,1]
1351-- >>> Stream.fold (Fold.any (== 0)) $ Stream.fromList [1,0,1]
1347−-- > any p = Fold.lmap p Fold.or
1349{-# INLINE any #-}
1354{-# INLINE any #-}
1350any :: Monad m => (a -> Bool) -> Fold m a Bool
1355any :: Monad m => (a -> Bool) -> Fold m a Bool
1351any predicate = foldt' step initial id
1356any predicate = foldt' step initial id
@@ -1361,19 +1366,25 @@ any predicate = foldt' step initial id
1362-- | Return 'True' if the given element is present in the stream.
1367-- | Return 'True' if the given element is present in the stream.
1364−-- > elem a = Fold.any (== a)
1371+-- >>> elem a = Fold.any (== a)
1366{-# INLINE elem #-}
1373{-# INLINE elem #-}
1367elem :: (Eq a, Monad m) => a -> Fold m a Bool
1374elem :: (Eq a, Monad m) => a -> Fold m a Bool
1368−elem a = any (a ==)
1375+elem a = any (== a)
1370−-- | Returns 'True' if all elements of a stream satisfy a predicate.
1377+-- | Returns 'True' if all elements of the input satisfy the predicate.
1381+-- >>> all p = Fold.lmap p Fold.and
1372-- >>> Stream.fold (Fold.all (== 0)) $ Stream.fromList [1,0,1]
1385-- >>> Stream.fold (Fold.all (== 0)) $ Stream.fromList [1,0,1]
1375−-- > all p = Fold.lmap p Fold.and
1377{-# INLINE all #-}
1388{-# INLINE all #-}
1378all :: Monad m => (a -> Bool) -> Fold m a Bool
1389all :: Monad m => (a -> Bool) -> Fold m a Bool
1379all predicate = foldt' step initial id
1390all predicate = foldt' step initial id
@@ -1389,15 +1400,19 @@ all predicate = foldt' step initial id
1390-- | Returns 'True' if the given element is not present in the stream.
1401-- | Returns 'True' if the given element is not present in the stream.
1392−-- > notElem a = Fold.all (/= a)
1405+-- >>> notElem a = Fold.all (/= a)
1394{-# INLINE notElem #-}
1407{-# INLINE notElem #-}
1395notElem :: (Eq a, Monad m) => a -> Fold m a Bool
1408notElem :: (Eq a, Monad m) => a -> Fold m a Bool
1396−notElem a = all (a /=)
1409+notElem a = all (/= a)
1398-- | Returns 'True' if all elements are 'True', 'False' otherwise
1411-- | Returns 'True' if all elements are 'True', 'False' otherwise
1400−-- > and = Fold.all (== True)
1415+-- >>> and = Fold.all (== True)
1402{-# INLINE and #-}
1417{-# INLINE and #-}
1403and :: Monad m => Fold m Bool Bool
1418and :: Monad m => Fold m Bool Bool
@@ -1405,7 +1420,9 @@ and = all (== True)
1406-- | Returns 'True' if any element is 'True', 'False' otherwise
1421-- | Returns 'True' if any element is 'True', 'False' otherwise
1408−-- > or = Fold.any (== True)
1425+-- >>> or = Fold.any (== True)
1410{-# INLINE or #-}
1427{-# INLINE or #-}
1411or :: Monad m => Fold m Bool Bool
1428or :: Monad m => Fold m Bool Bool
@@ -1531,6 +1548,9 @@ droppingWhileM p = Fold step initial (return . toMaybe)
1531 else Just' a
1548 else Just' a
1532 step _ a = return $ Partial $ Just' a
1549 step _ a = return $ Partial $ Just' a
1552+-- >>> droppingWhile p = Fold.droppingWhileM (return . p)
1534{-# INLINE droppingWhile #-}
1554{-# INLINE droppingWhile #-}
1535droppingWhile :: Monad m => (a -> Bool) -> Fold m a (Maybe a)
1555droppingWhile :: Monad m => (a -> Bool) -> Fold m a (Maybe a)
1536droppingWhile p = droppingWhileM (return . p)
1556droppingWhile p = droppingWhileM (return . p)
@@ -1539,20 +1559,20 @@ droppingWhile p = droppingWhileM (return . p)
1539-- S.splitOn in favor of the fold.
1559-- S.splitOn in favor of the fold.
1541-- XXX Use Fold.many instead once it is fixed.
1561-- XXX Use Fold.many instead once it is fixed.
1542−--
1562+-- > Stream.splitOnSuffix p f = Stream.foldMany (Fold.takeEndBy_ p f)
1543-- | Like 'takeEndBy' but drops the element on which the predicate succeeds.
1564-- | Like 'takeEndBy' but drops the element on which the predicate succeeds.
1545−-- >>> Stream.fold (Fold.takeEndBy_ (== '\n') Fold.toList) $ Stream.fromList "hello\nthere\n"
1568+-- >>> input = Stream.fromList "hello\nthere\n"
1569+-- >>> line = Fold.takeEndBy_ (== '\n') Fold.toList
1570+-- >>> Stream.fold line input
1546-- "hello"
1571-- "hello"
1548−-- >>> Stream.fold Fold.toList $ Stream.foldMany (Fold.takeEndBy_ (== '\n') Fold.toList) $ Stream.fromList "hello\nthere\n"
1573+-- >>> Stream.fold Fold.toList $ Stream.foldMany line input
1549-- ["hello","there"]
1574-- ["hello","there"]
1551−-- > Stream.splitOnSuffix p f = Stream.foldMany (Fold.takeEndBy_ p f)
1553−-- See 'Streamly.Prelude.splitOnSuffix' for more details on splitting a
1554−-- stream using 'takeEndBy_'.
1556{-# INLINE takeEndBy_ #-}
1576{-# INLINE takeEndBy_ #-}
1557takeEndBy_ :: Monad m => (a -> Bool) -> Fold m a b -> Fold m a b
1577takeEndBy_ :: Monad m => (a -> Bool) -> Fold m a b -> Fold m a b
1558-- takeEndBy_ predicate = scanMaybe (takingEndBy_ predicate)
1578-- takeEndBy_ predicate = scanMaybe (takingEndBy_ predicate)
@@ -1566,20 +1586,22 @@ takeEndBy_ predicate (Fold fstep finitial fextract) =
1566 then fstep s a
1586 then fstep s a
1567 else Done <$> fextract s
1587 else Done <$> fextract s
1590+-- > Stream.splitWithSuffix p f = Stream.foldMany (Fold.takeEndBy p f)
1569-- | Take the input, stop when the predicate succeeds taking the succeeding
1592-- | Take the input, stop when the predicate succeeds taking the succeeding
1570-- element as well.
1593-- element as well.
1572−-- >>> Stream.fold (Fold.takeEndBy (== '\n') Fold.toList) $ Stream.fromList "hello\nthere\n"
1597+-- >>> input = Stream.fromList "hello\nthere\n"
1598+-- >>> line = Fold.takeEndBy (== '\n') Fold.toList
1599+-- >>> Stream.fold line input
1573-- "hello\n"
1600-- "hello\n"
1575−-- >>> Stream.fold Fold.toList $ Stream.foldMany (Fold.takeEndBy (== '\n') Fold.toList) $ Stream.fromList "hello\nthere\n"
1602+-- >>> Stream.fold Fold.toList $ Stream.foldMany line input
1576-- ["hello\n","there\n"]
1603-- ["hello\n","there\n"]
1578−-- > Stream.splitWithSuffix p f = Stream.foldMany (Fold.takeEndBy p f)
1580−-- See 'Streamly.Prelude.splitWithSuffix' for more details on splitting a
1581−-- stream using 'takeEndBy'.
1583{-# INLINE takeEndBy #-}
1605{-# INLINE takeEndBy #-}
1584takeEndBy :: Monad m => (a -> Bool) -> Fold m a b -> Fold m a b
1606takeEndBy :: Monad m => (a -> Bool) -> Fold m a b -> Fold m a b
1585-- takeEndBy predicate = scanMaybe (takingEndBy predicate)
1607-- takeEndBy predicate = scanMaybe (takingEndBy predicate)
@@ -1924,10 +1946,16 @@ takeEndBySeq_ patArr (Fold fstep finitial fextract) =
1924-- ---stream m a---| |---m (b,c)
1946-- ---stream m a---| |---m (b,c)
1925-- |-------Fold m a c--------|
1947-- |-------Fold m a c--------|
1927−-- >>> Stream.fold (Fold.tee Fold.sum Fold.length) (Stream.enumerateFromTo 1.0 100.0)
1930−-- > tee = teeWith (,)
1952+-- >>> tee = Fold.teeWith (,)
1956+-- >>> t = Fold.tee Fold.sum Fold.length
1957+-- >>> Stream.fold t (Stream.enumerateFromTo 1.0 100.0)
1932{-# INLINE tee #-}
1960{-# INLINE tee #-}
1933tee :: Monad m => Fold m a b -> Fold m a c -> Fold m a (b,c)
1961tee :: Monad m => Fold m a b -> Fold m a c -> Fold m a (b,c)
@@ -1992,16 +2020,15 @@ partitionByMUsing t f fld1 fld2 =
1992-- |-------Fold c y--------|
2020-- |-------Fold c y--------|
1995−-- Send input to either fold randomly:
2023+-- Example, send input to either fold randomly:
1998−-- > import System.Random (randomIO)
2025+-- >>> import System.Random (randomIO)
1999−-- > randomly a = randomIO >>= \\x -> return $ if x then Left a else Right a
2026+-- >>> randomly a = randomIO >>= \x -> return $ if x then Left a else Right a
2027+-- >>> f = Fold.partitionByM randomly Fold.length Fold.length
2000−-- > Stream.fold (Fold.partitionByM randomly Fold.length Fold.length) (Stream.enumerateFromTo 1 100)
2028+-- >>> Stream.fold f (Stream.enumerateFromTo 1 100)
2001−-- (59,41)
2029+-- ...
2004−-- Send input to the two folds in a proportion of 2:1:
2031+-- Example, send input to the two folds in a proportion of 2:1:
2006-- >>> :{
2033-- >>> :{
2007-- proportionately m n = do
2034-- proportionately m n = do
@@ -2014,8 +2041,9 @@ partitionByMUsing t f fld1 fld2 =
2015-- >>> :{
2042-- >>> :{
2016-- main = do
2043-- main = do
2017−-- f <- proportionately 2 1
2044+-- g <- proportionately 2 1
2045+-- let f = Fold.partitionByM g Fold.length Fold.length
2018−-- r <- Stream.fold (Fold.partitionByM f Fold.length Fold.length) (Stream.enumerateFromTo (1 :: Int) 100)
2046+-- r <- Stream.fold f (Stream.enumerateFromTo (1 :: Int) 100)
2019-- print r
2047-- print r
@@ -2040,7 +2068,6 @@ partitionByM = partitionByMUsing teeWith
2041-- | Similar to 'partitionByM' but terminates when the first fold terminates.
2069-- | Similar to 'partitionByM' but terminates when the first fold terminates.
2044{-# INLINE partitionByFstM #-}
2071{-# INLINE partitionByFstM #-}
2045partitionByFstM :: Monad m
2072partitionByFstM :: Monad m
2046 => (a -> m (Either b c)) -> Fold m b x -> Fold m c y -> Fold m a (x, y)
2073 => (a -> m (Either b c)) -> Fold m b x -> Fold m c y -> Fold m a (x, y)
@@ -2048,7 +2075,6 @@ partitionByFstM = partitionByMUsing teeWithFst
2049-- | Similar to 'partitionByM' but terminates when any fold terminates.
2076-- | Similar to 'partitionByM' but terminates when any fold terminates.
2052{-# INLINE partitionByMinM #-}
2078{-# INLINE partitionByMinM #-}
2053partitionByMinM :: Monad m =>
2079partitionByMinM :: Monad m =>
2054 (a -> m (Either b c)) -> Fold m b x -> Fold m c y -> Fold m a (x, y)
2080 (a -> m (Either b c)) -> Fold m b x -> Fold m c y -> Fold m a (x, y)
@@ -2057,9 +2083,10 @@ partitionByMinM = partitionByMUsing teeWithMin
2057-- Note: we could use (a -> Bool) instead of (a -> Either b c), but the latter
2083-- Note: we could use (a -> Bool) instead of (a -> Either b c), but the latter
2058-- makes the signature clearer as to which case belongs to which fold.
2084-- makes the signature clearer as to which case belongs to which fold.
2059-- XXX need to check the performance in both cases.
2085-- XXX need to check the performance in both cases.
2060-- | Same as 'partitionByM' but with a pure partition function.
2087-- | Same as 'partitionByM' but with a pure partition function.
2062−-- Count even and odd numbers in a stream:
2089+-- Example, count even and odd numbers in a stream:
2064-- >>> :{
2091-- >>> :{
2065-- let f = Fold.partitionBy (\n -> if even n then Left n else Right n)
2092-- let f = Fold.partitionBy (\n -> if even n then Left n else Right n)
@@ -2079,7 +2106,9 @@ partitionBy f = partitionByM (return . f)
2079-- and routes the 'Left' values to the first fold and 'Right' values to the
2106-- and routes the 'Left' values to the first fold and 'Right' values to the
2080-- second fold.
2107-- second fold.
2082−-- > partition = partitionBy id
2111+-- >>> partition = Fold.partitionBy id
2084{-# INLINE partition #-}
2113{-# INLINE partition #-}
2085partition :: Monad m
2114partition :: Monad m
@@ -2094,412 +2123,6 @@ partition = partitionBy id
2094-- partitionN fs = Fold step begin done
2123-- partitionN fs = Fold step begin done
2097−------------------------------------------------------------------------------
2098−-- demux: in a key value stream fold each key sub-stream with a different fold
2099−------------------------------------------------------------------------------
2101−-- TODO Demultiplex an input element into a number of typed variants. We want
2102−-- to statically restrict the target values within a set of predefined types,
2103−-- an enumeration of a GADT.
2105−-- This is the consumer side dual of the producer side 'mux' operation (XXX to
2108−-- XXX If we use Refold in it, it can perhaps fuse/be more efficient. For
2109−-- example we can store just the result rather than storing the whole fold in
2112−-- Note: There are separate functions to determine Key and Fold from the input
2113−-- because key is to be determined on each input whereas fold is to be
2114−-- determined only once for a key.
2116−-- | In a key value stream, fold values corresponding to each key with a key
2117−-- specific fold. The fold returns the fold result as the second component of
2118−-- the output tuple whenever a fold terminates. The first component of the
2119−-- tuple is a container of in-progress folds. If a fold terminates, another
2120−-- instance of the fold is started upon receiving an input with that key.
2122−-- This can be used to scan a stream and collect the results from the scan
2127−{-# INLINE demuxScanWith #-}
2128−demuxScanWith :: (Monad m, IsMap f, Traversable f) =>
2130− -> (a -> m (Fold m a b))
2131− -> Fold m a (m (f b), Maybe (Key f, b))
2132−demuxScanWith getKey getFold = fmap extract $ foldlM' step initial
2136− initial = return $ Tuple' IsMap.mapEmpty Nothing
2138− {-# INLINE runFold #-}
2139− runFold kv (Fold step1 initial1 extract1) (k, a) = do
2147− let fld = Fold step1 (return res1) extract1
2148− in Tuple' (IsMap.mapInsert k fld kv) Nothing
2149− Done b -> Tuple' (IsMap.mapDelete k kv) (Just (k, b))
2150− Done b -> return $ Tuple' kv (Just (k, b))
2152− step (Tuple' kv _) a = do
2154− case IsMap.mapLookup k kv of
2157− runFold kv fld (k, a)
2158− Just f -> runFold kv f (k, a)
2160− extract (Tuple' kv x) = (Prelude.mapM f kv, x)
2164− f (Fold _ i e) = do
2170−-- | This is specialized version of 'demuxScanWith' that uses mutable cells as
2171−-- fold accumulators for better performance.
2173−-- >>> demuxScanMutWith = Fold.demuxScanWith
2175−{-# INLINE demuxScanMutWith #-}
2176−demuxScanMutWith :: (MonadIO m, IsMap f, Traversable f) =>
2178− -> (a -> m (Fold m a b))
2179− -> Fold m a (m (f b), Maybe (Key f, b))
2180−demuxScanMutWith getKey getFold = fmap extract $ foldlM' step initial
2184− initial = return $ Tuple' IsMap.mapEmpty Nothing
2186− {-# INLINE initFold #-}
2187− initFold kv (Fold step1 initial1 extract1) (k, a) = do
2194− let fld = Fold step1 (return res1) extract1
2195− ref <- liftIO $ newIORef fld
2196− return $ Tuple' (IsMap.mapInsert k ref kv) Nothing
2197− Done b -> return $ Tuple' kv (Just (k, b))
2198− Done b -> return $ Tuple' kv (Just (k, b))
2200− {-# INLINE runFold #-}
2201− runFold kv ref (Fold step1 initial1 extract1) (k, a) = do
2208− let fld = Fold step1 (return res1) extract1
2209− liftIO $ writeIORef ref fld
2210− return $ Tuple' kv Nothing
2212− let kv1 = IsMap.mapDelete k kv
2213− in return $ Tuple' kv1 (Just (k, b))
2214− Done _ -> error "demuxScanMutWith: unreachable"
2216− step (Tuple' kv _) a = do
2218− case IsMap.mapLookup k kv of
2221− initFold kv f (k, a)
2223− f <- liftIO $ readIORef ref
2224− runFold kv ref f (k, a)
2226− extract (Tuple' kv x) = (Prelude.mapM f kv, x)
2231− (Fold _ i e) <- liftIO $ readIORef ref
2237−-- | This collects all the results of 'demuxScanWith' in a container.
2239−{-# INLINE demuxWith #-}
2240−demuxWith :: (Monad m, IsMap f, Traversable f) =>
2241− (a -> Key f) -> (a -> m (Fold m a b)) -> Fold m a (f b)
2242−demuxWith getKey getFold =
2244− classifier = demuxScanWith getKey getFold
2245− getMap Nothing = pure IsMap.mapEmpty
2246− getMap (Just action) = action
2248− teeWith IsMap.mapUnion
2249− (rmapM getMap $ lmap fst last)
2250− (lmap snd $ catMaybes toMap)
2251− in postscan classifier aggregator
2253−-- | Same as 'demuxWith' but uses 'demuxScanMutWith' for better performance.
2255−-- >>> demuxMutWith = Fold.demuxWith
2257−{-# INLINE demuxMutWith #-}
2258−demuxMutWith :: (MonadIO m, IsMap f, Traversable f) =>
2259− (a -> Key f) -> (a -> m (Fold m a b)) -> Fold m a (f b)
2260−demuxMutWith getKey getFold =
2262− classifier = demuxScanMutWith getKey getFold
2263− getMap Nothing = pure IsMap.mapEmpty
2264− getMap (Just action) = action
2266− teeWith IsMap.mapUnion
2267− (rmapM getMap $ lmap fst last)
2268− (lmap snd $ catMaybes toMap)
2269− in postscan classifier aggregator
2271−-- | Fold a stream of key value pairs using a function that maps keys to folds.
2273−-- >>> import Data.Map (Map)
2275−-- let f "SUM" = return Fold.sum
2276−-- f _ = return Fold.product
2277−-- input = Stream.fromList [("SUM",1),("PRODUCT",2),("SUM",3),("PRODUCT",4)]
2278−-- in Stream.fold (Fold.demux f) input :: IO (Map String Int)
2280−-- fromList [("PRODUCT",8),("SUM",4)]
2282−-- >>> demux f = Fold.demuxWith fst (Fold.lmap snd . f)
2285−{-# INLINE demux #-}
2286−demux :: (Monad m, IsMap f, Traversable f) =>
2287− (Key f -> m (Fold m a b)) -> Fold m (Key f, a) (f b)
2288−demux f = demuxWith fst (\(k, _) -> fmap (lmap snd) (f k))
2290−------------------------------------------------------------------------------
2291−-- Classify: Like demux but uses the same fold for all keys.
2292−------------------------------------------------------------------------------
2294−-- XXX Change these to make the behavior similar to demux* variants. We can
2295−-- implement this using classifyScanManyWith. Maintain a set of done folds in
2296−-- the underlying monad, and when initial is called look it up, if the fold is
2297−-- done then initial would set a flag in the state to ignore the input or
2300−-- | Folds the values for each key using the supplied fold. When scanning, as
2301−-- soon as the fold is complete, its result is available in the second
2302−-- component of the tuple. The first component of the tuple is a snapshot of
2303−-- the in-progress folds.
2305−-- Once the fold for a key is done, any future values of the key are ignored.
2307−-- >>> classifyScanWith f fld = Fold.demuxScanWith f (const fld)
2309−{-# INLINE classifyScanWith #-}
2310−classifyScanWith :: (Monad m, IsMap f, Traversable f, Ord (Key f)) =>
2311− -- Note: we need to return the Map itself to display the in-progress values
2312− -- e.g. to implement top. We could possibly create a separate abstraction
2313− -- for that use case. We return an action because we want it to be lazy so
2314− -- that the downstream consumers can choose to process or discard it.
2315− (a -> Key f) -> Fold m a b -> Fold m a (m (f b), Maybe (Key f, b))
2316−classifyScanWith f (Fold step1 initial1 extract1) =
2317− fmap extract $ foldlM' step initial
2321− initial = return $ Tuple3' IsMap.mapEmpty Set.empty Nothing
2323− {-# INLINE initFold #-}
2324− initFold kv set k a = do
2332− Tuple3' (IsMap.mapInsert k s1 kv) set Nothing
2334− Tuple3' kv set (Just (k, b))
2335− Done b -> return (Tuple3' kv (Set.insert k set) (Just (k, b)))
2337− step (Tuple3' kv set _) a = do
2339− case IsMap.mapLookup k kv of
2341− if Set.member k set
2342− then return (Tuple3' kv set Nothing)
2343− else initFold kv set k a
2349− Tuple3' (IsMap.mapInsert k s1 kv) set Nothing
2351− let kv1 = IsMap.mapDelete k kv
2352− in Tuple3' kv1 (Set.insert k set) (Just (k, b))
2354− extract (Tuple3' kv _ x) = (Prelude.mapM extract1 kv, x)
2356−-- XXX we can use a Prim IORef if we can constrain the state "s" to be Prim
2358−-- The code is almost the same as classifyScanWith except the IORef operations.
2360−-- | Same as classifyScanWith except that it uses mutable IORef cells in the
2361−-- Map providing better performance. Be aware that if this is used as a scan,
2362−-- the values in the intermediate Maps would be mutable.
2364−-- >>> classifyScanMutWith = classifyScanWith
2365−-- >>> classifyScanMutWith f fld = demuxScanMutWith f (const fld)
2367−{-# INLINE classifyScanMutWith #-}
2368−classifyScanMutWith :: (MonadIO m, IsMap f, Traversable f, Ord (Key f)) =>
2369− (a -> Key f) -> Fold m a b -> Fold m a (m (f b), Maybe (Key f, b))
2370−classifyScanMutWith f (Fold step1 initial1 extract1) =
2371− fmap extract $ foldlM' step initial
2375− initial = return $ Tuple3' IsMap.mapEmpty Set.empty Nothing
2377− {-# INLINE initFold #-}
2378− initFold kv set k a = do
2385− ref <- liftIO $ newIORef s1
2386− return $ Tuple3' (IsMap.mapInsert k ref kv) set Nothing
2388− return $ Tuple3' kv set (Just (k, b))
2389− Done b -> return (Tuple3' kv (Set.insert k set) (Just (k, b)))
2391− step (Tuple3' kv set _) a = do
2393− case IsMap.mapLookup k kv of
2395− if Set.member k set
2396− then return (Tuple3' kv set Nothing)
2397− else initFold kv set k a
2399− s <- liftIO $ readIORef ref
2403− liftIO $ writeIORef ref s1
2404− return $ Tuple3' kv set Nothing
2406− let kv1 = IsMap.mapDelete k kv
2408− $ Tuple3' kv1 (Set.insert k set) (Just (k, b))
2410− extract (Tuple3' kv _ x) =
2411− (Prelude.mapM (\ref -> liftIO (readIORef ref) >>= extract1) kv, x)
2413−-- | Fold a key value stream to a key-value container. If the same key appears
2414−-- multiple times, only the last value is retained.
2415−{-# INLINE toMap #-}
2416−toMap :: (Monad m, IsMap f) => Fold m (Key f, a) (f a)
2417−toMap = foldl' (\kv (k, v) -> IsMap.mapInsert k v kv) IsMap.mapEmpty
2419−-- | Split the input stream based on a key field and fold each split using the
2420−-- given fold. Useful for map/reduce, bucketizing the input in different bins
2421−-- or for generating histograms.
2423−-- >>> import Data.Map.Strict (Map)
2425−-- let input = Stream.fromList [("ONE",1),("ONE",1.1),("TWO",2), ("TWO",2.2)]
2426−-- classify = Fold.classifyWith fst (Fold.lmap snd Fold.toList)
2427−-- in Stream.fold classify input :: IO (Map String [Double])
2429−-- fromList [("ONE",[1.0,1.1]),("TWO",[2.0,2.2])]
2431−-- Once the classifier fold terminates for a particular key any further inputs
2432−-- in that bucket are ignored.
2434−-- Space used is proportional to the number of keys seen till now and
2435−-- monotonically increases because it stores whether a key has been seen or
2442−{-# INLINE classifyWith #-}
2443−classifyWith :: (Monad m, IsMap f, Traversable f, Ord (Key f)) =>
2444− (a -> Key f) -> Fold m a b -> Fold m a (f b)
2445−classifyWith f fld =
2447− classifier = classifyScanWith f fld
2448− getMap Nothing = pure IsMap.mapEmpty
2449− getMap (Just action) = action
2451− teeWith IsMap.mapUnion
2452− (rmapM getMap $ lmap fst last)
2453− (lmap snd $ catMaybes toMap)
2454− in postscan classifier aggregator
2456−-- | Same as 'classifyWith' but maybe faster because it uses mutable cells as
2457−-- fold accumulators in the Map.
2459−-- >>> classifyMutWith = Fold.classifyWith
2461−{-# INLINE classifyMutWith #-}
2462−classifyMutWith :: (MonadIO m, IsMap f, Traversable f, Ord (Key f)) =>
2463− (a -> Key f) -> Fold m a b -> Fold m a (f b)
2464−classifyMutWith f fld =
2466− classifier = classifyScanMutWith f fld
2467− getMap Nothing = pure IsMap.mapEmpty
2468− getMap (Just action) = action
2470− teeWith IsMap.mapUnion
2471− (rmapM getMap $ lmap fst last)
2472− (lmap snd $ catMaybes toMap)
2473− in postscan classifier aggregator
2475−-- | Given an input stream of key value pairs and a fold for values, fold all
2476−-- the values belonging to each key. Useful for map/reduce, bucketizing the
2477−-- input in different bins or for generating histograms.
2480−-- let input = Stream.fromList [("ONE",1),("ONE",1.1),("TWO",2), ("TWO",2.2)]
2481−-- in Stream.fold (Fold.classify Fold.toList) input
2483−-- fromList [("ONE",[1.0,1.1]),("TWO",[2.0,2.2])]
2487−-- >>> classify = Fold.classifyWith fst . Fold.lmap snd
2490−{-# INLINE classify #-}
2491−classify :: (Monad m, Ord k) => Fold m a b -> Fold m (k, a) (Map k b)
2492−classify = classifyWith fst . lmap snd
2494−-- | Determine the frequency of each element in the stream.
2496−-- You can just collect the keys of the resulting map to get the unique
2497−-- elements in the stream.
2499−{-# INLINE frequency #-}
2500−frequency :: (Monad m, Ord a) => Fold m a (Map a Int)
2501−frequency = classifyWith id length
2503------------------------------------------------------------------------------
2126------------------------------------------------------------------------------
2504-- Unzipping
2127-- Unzipping
2505------------------------------------------------------------------------------
2128------------------------------------------------------------------------------
@@ -2522,7 +2145,9 @@ unzipWithMUsing t f fld1 fld2 =
2523-- | Like 'unzipWith' but with a monadic splitter function.
2146-- | Like 'unzipWith' but with a monadic splitter function.
2525−-- @unzipWithM k f1 f2 = lmapM k (unzip f1 f2)@
2150+-- >>> unzipWithM k f1 f2 = Fold.lmapM k (Fold.unzip f1 f2)
2527-- /Pre-release/
2152-- /Pre-release/
2528{-# INLINE unzipWithM #-}
2153{-# INLINE unzipWithM #-}
@@ -2532,7 +2157,6 @@ unzipWithM = unzipWithMUsing teeWith
2533-- | Similar to 'unzipWithM' but terminates when the first fold terminates.
2158-- | Similar to 'unzipWithM' but terminates when the first fold terminates.
2536{-# INLINE unzipWithFstM #-}
2160{-# INLINE unzipWithFstM #-}
2537unzipWithFstM :: Monad m =>
2161unzipWithFstM :: Monad m =>
2538 (a -> m (b, c)) -> Fold m b x -> Fold m c y -> Fold m a (x, y)
2162 (a -> m (b, c)) -> Fold m b x -> Fold m c y -> Fold m a (x, y)
@@ -2540,7 +2164,6 @@ unzipWithFstM = unzipWithMUsing teeWithFst
2541-- | Similar to 'unzipWithM' but terminates when any fold terminates.
2165-- | Similar to 'unzipWithM' but terminates when any fold terminates.
2544{-# INLINE unzipWithMinM #-}
2167{-# INLINE unzipWithMinM #-}
2545unzipWithMinM :: Monad m =>
2168unzipWithMinM :: Monad m =>
2546 (a -> m (b,c)) -> Fold m b x -> Fold m c y -> Fold m a (x,y)
2169 (a -> m (b,c)) -> Fold m b x -> Fold m c y -> Fold m a (x,y)
@@ -2549,7 +2172,10 @@ unzipWithMinM = unzipWithMUsing teeWithMin
2549-- | Split elements in the input stream into two parts using a pure splitter
2172-- | Split elements in the input stream into two parts using a pure splitter
2550-- function, direct each part to a different fold and zip the results.
2173-- function, direct each part to a different fold and zip the results.
2177+-- >>> unzipWith f = Fold.unzipWithM (return . f)
2552−-- @unzipWith f fld1 fld2 = Fold.lmap f (Fold.unzip fld1 fld2)@
2178+-- >>> unzipWith f fld1 fld2 = Fold.lmap f (Fold.unzip fld1 fld2)
2554-- This fold terminates when both the input folds terminate.
2180-- This fold terminates when both the input folds terminate.
@@ -2570,7 +2196,9 @@ unzipWith f = unzipWithM (return . f)
2573−-- > unzip = Fold.unzipWith id
2201+-- >>> unzip = Fold.unzipWith id
2575-- This is the consumer side dual of the producer side 'zip' operation.
2203-- This is the consumer side dual of the producer side 'zip' operation.
@@ -2588,22 +2216,27 @@ unzip = unzipWith id
2588-- handled in parsers using the Continue facility. See zipWithM in the Parser
2216-- handled in parsers using the Continue facility. See zipWithM in the Parser
2589-- module.
2217-- module.
2219+-- cmpBy, eqBy, isPrefixOf, isSubsequenceOf etc can be implemented using
2591-- | Zip a stream with the input of a fold using the supplied function.
2222-- | Zip a stream with the input of a fold using the supplied function.
2593-- /Unimplemented/
2224-- /Unimplemented/
2595−{-# INLINE zipWithM #-}
2226+{-# INLINE zipStreamWithM #-}
2596−zipWithM :: -- Monad m =>
2227+zipStreamWithM :: -- Monad m =>
2597− (a -> b -> m c) -> t m a -> Fold m c x -> Fold m b x
2228+ (a -> b -> m c) -> Stream m a -> Fold m c x -> Fold m b x
2598−zipWithM = undefined
2229+zipStreamWithM = undefined
2600-- | Zip a stream with the input of a fold.
2231-- | Zip a stream with the input of a fold.
2233+-- >>> zip = Fold.zipStreamWithM (curry return)
2602-- /Unimplemented/
2235-- /Unimplemented/
2604−{-# INLINE zip #-}
2237+{-# INLINE zipStream #-}
2605−zip :: Monad m => t m a -> Fold m (a, b) x -> Fold m b x
2238+zipStream :: Monad m => Stream m a -> Fold m (a, b) x -> Fold m b x
2606−zip = zipWithM (curry return)
2239+zipStream = zipStreamWithM (curry return)
2608-- | Pair each element of a fold input with its index, starting from index 0.
2241-- | Pair each element of a fold input with its index, starting from index 0.
@@ -2618,16 +2251,24 @@ indexingWith i f = fmap toMaybe $ foldl' step initial
2618 step Nothing' a = Just' (i, a)
2251 step Nothing' a = Just' (i, a)
2619 step (Just' (n, _)) a = Just' (f n, a)
2252 step (Just' (n, _)) a = Just' (f n, a)
2255+-- >>> indexing = Fold.indexingWith 0 (+ 1)
2621{-# INLINE indexing #-}
2257{-# INLINE indexing #-}
2622indexing :: Monad m => Fold m a (Maybe (Int, a))
2258indexing :: Monad m => Fold m a (Maybe (Int, a))
2623indexing = indexingWith 0 (+ 1)
2259indexing = indexingWith 0 (+ 1)
2262+-- >>> indexingRev n = Fold.indexingWith n (subtract 1)
2625{-# INLINE indexingRev #-}
2264{-# INLINE indexingRev #-}
2626indexingRev :: Monad m => Int -> Fold m a (Maybe (Int, a))
2265indexingRev :: Monad m => Int -> Fold m a (Maybe (Int, a))
2627indexingRev n = indexingWith n (subtract 1)
2266indexingRev n = indexingWith n (subtract 1)
2629-- | Pair each element of a fold input with its index, starting from index 0.
2268-- | Pair each element of a fold input with its index, starting from index 0.
2270+-- >>> indexed = Fold.scanMaybe Fold.indexing
2631{-# INLINE indexed #-}
2272{-# INLINE indexed #-}
2632indexed :: Monad m => Fold m (Int, a) b -> Fold m a b
2273indexed :: Monad m => Fold m (Int, a) b -> Fold m a b
2633indexed = scanMaybe indexing
2274indexed = scanMaybe indexing
@@ -2636,8 +2277,9 @@ indexed = scanMaybe indexing
2636-- additional state input @(s, a) -> b@. Convenient to filter with an
2277-- additional state input @(s, a) -> b@. Convenient to filter with an
2637-- addiitonal index or time input.
2278-- addiitonal index or time input.
2280+-- >>> filterWithIndex = Fold.with Fold.indexed Fold.filter
2640−-- filterWithIndex = with indexed filter
2641-- filterWithAbsTime = with timestamped filter
2283-- filterWithAbsTime = with timestamped filter
2642-- filterWithRelTime = with timeIndexed filter
2284-- filterWithRelTime = with timeIndexed filter
@@ -2756,12 +2398,14 @@ unfoldMany (Unfold ustep inject) (Fold fstep initial extract) =
2756 {-# INLINE_LATE consume #-}
2398 {-# INLINE_LATE consume #-}
2757 consume s a = inject a >>= produce s
2399 consume s a = inject a >>= produce s
2401+-- | Get the bottom most @n@ elements using the supplied comparison function.
2759−{-# INLINE topBy #-}
2403+{-# INLINE bottomBy #-}
2760−topBy :: (MonadIO m, Unbox a) =>
2404+bottomBy :: (MonadIO m, Unbox a) =>
2761 (a -> a -> Ordering)
2405 (a -> a -> Ordering)
2763 -> Fold m a (MA.Array a)
2407 -> Fold m a (MA.Array a)
2764−topBy cmp n = Fold step initial extract
2408+bottomBy cmp n = Fold step initial extract
@@ -2790,6 +2434,10 @@ topBy cmp n = Fold step initial extract
2791-- | Fold the input stream to top n elements.
2435-- | Fold the input stream to top n elements.
2439+-- >>> top = Fold.bottomBy $ flip compare
2793-- >>> stream = Stream.fromList [2::Int,7,9,3,1,5,6,11,17]
2441-- >>> stream = Stream.fromList [2::Int,7,9,3,1,5,6,11,17]
2794-- >>> Stream.fold (Fold.top 3) stream >>= MA.toList
2442-- >>> Stream.fold (Fold.top 3) stream >>= MA.toList
2795-- [17,11,9]
2443-- [17,11,9]
@@ -2797,10 +2445,14 @@ topBy cmp n = Fold step initial extract
2797-- /Pre-release/
2445-- /Pre-release/
2798{-# INLINE top #-}
2446{-# INLINE top #-}
2799top :: (MonadIO m, Unbox a, Ord a) => Int -> Fold m a (MA.Array a)
2447top :: (MonadIO m, Unbox a, Ord a) => Int -> Fold m a (MA.Array a)
2800−top = topBy $ flip compare
2448+top = bottomBy $ flip compare
2802-- | Fold the input stream to bottom n elements.
2450-- | Fold the input stream to bottom n elements.
2454+-- >>> bottom = Fold.bottomBy compare
2804-- >>> stream = Stream.fromList [2::Int,7,9,3,1,5,6,11,17]
2456-- >>> stream = Stream.fromList [2::Int,7,9,3,1,5,6,11,17]
2805-- >>> Stream.fold (Fold.bottom 3) stream >>= MA.toList
2457-- >>> Stream.fold (Fold.bottom 3) stream >>= MA.toList
2806-- [1,2,3]
2458-- [1,2,3]
@@ -2808,4 +2460,4 @@ top = topBy $ flip compare
2808-- /Pre-release/
2460-- /Pre-release/
2809{-# INLINE bottom #-}
2461{-# INLINE bottom #-}
2810bottom :: (MonadIO m, Unbox a, Ord a) => Int -> Fold m a (MA.Array a)
2462bottom :: (MonadIO m, Unbox a, Ord a) => Int -> Fold m a (MA.Array a)
2811−bottom = topBy compare
2463+bottom = bottomBy compare