on f8d80cc help sign in
1743 lines 51 kB history raw
1-- |
2-- Module : Streamly.Internal.Data.Fold
3-- Copyright : (c) 2019 Composewell Technologies
4-- (c) 2013 Gabriel Gonzalez
5-- License : BSD3
6-- Maintainer : streamly@composewell.com
7-- Stability : experimental
8-- Portability : GHC
9--
10-- See "Streamly.Data.Fold" for an overview and
11-- "Streamly.Internal.Data.Fold.Types" for design notes.
12--
13-- IMPORTANT: keep the signatures consistent with the folds in Streamly.Prelude
15module Streamly.Internal.Data.Fold
16 (
17 -- * Fold Type
18 Step (..)
19 , Fold (..)
21 -- * Constructors
22 , foldl'
23 , foldlM'
24 , foldl1'
25 , foldr
26 , foldrM
27 , mkFold
28 , mkFold_
29 , mkFoldM
30 , mkFoldM_
32 -- * Folds
33 -- ** Identity
34 , fromPure
35 , fromEffect
37 -- ** Accumulators
38 -- *** Semigroups and Monoids
39 , sconcat
40 , mconcat
41 , foldMap
42 , foldMapM
44 -- *** Reducers
45 , drain
46 , drainBy
47 , last
48 , length
49 , mean
50 , variance
51 , stdDev
52 , rollingHash
53 , rollingHashWithSalt
54 , rollingHashFirstN
55 -- , rollingHashLastN
57 -- *** Saturating Reducers
58 -- | 'product' terminates if it becomes 0. Other folds can theoretically
59 -- saturate on bounded types, and therefore terminate, however, they will
60 -- run forever on unbounded types like Integer/Double.
61 , sum
62 , product
63 , maximumBy
64 , maximum
65 , minimumBy
66 , minimum
68 -- *** Collectors
69 -- | Avoid using these folds in scalable or performance critical
70 -- applications, they buffer all the input in GC memory which can be
71 -- detrimental to performance if the input is large.
72 , toList
73 , toListRev
74 -- $toListRev
75 , toStream
76 , toStreamRev
78 -- ** Terminating Folds
79 , drainN
80 -- , lastN
81 -- , (!!)
82 , genericIndex
83 , index
84 , head
85 -- , findM
86 , find
87 , lookup
88 , findIndex
89 , elemIndex
90 , null
91 , elem
92 , notElem
93 , all
94 , any
95 , and
96 , or
97 -- , the
99 -- * Combinators
100 -- ** Utilities
101 , with
103 -- ** Transforming the Monad
104 , hoist
105 , generally
107 -- ** Mapping on output
108 , rmapM
110 -- ** Mapping on Input
111 , transform
112 , lmap
113 --, lsequence
114 , lmapM
115 , scan
116 , indexed
118 -- ** Filtering
119 , filter
120 , filterM
121 , sampleFromthen
122 -- , ldeleteBy
123 -- , luniq
125 -- ** Mapping Filters
126 , catMaybes
127 , mapMaybe
128 -- , mapMaybeM
130 {-
131 -- ** Scanning Filters
132 , findIndices
133 , elemIndices
135 -- ** Insertion
136 -- | Insertion adds more elements to the stream.
138 , insertBy
139 , intersperseM
141 -- ** Reordering
142 , reverse
143 -}
145 -- ** Trimming
146 , take
148 -- By elements
149 , takeEndBy
150 , takeEndBy_
151 -- , takeEndBySeq
152 {-
153 , drop
154 , dropWhile
155 , dropWhileM
156 -}
158 -- ** Serial Append
159 , serialWith
160 , serial_
161 -- , tail
162 -- , init
163 , splitAt -- spanN
164 -- , splitIn -- sessionN
166 -- ** Parallel Distribution
167 , teeWith
168 , tee
169 , teeWithFst
170 , teeWithMin
171 , distribute
172 -- , distributeFst
173 -- , distributeMin
175 -- ** Parallel Alternative
176 , shortest
177 , longest
179 -- ** Partitioning
180 , partitionByM
181 , partitionByFstM
182 , partitionByMinM
183 , partitionBy
184 , partition
186 -- ** Demultiplexing
187 -- | Direct values in the input stream to different folds using an n-ary
188 -- fold selector.
189 , demux -- XXX rename this to demux_
190 , demuxWith
191 , demuxDefault -- XXX rename this to demux
192 , demuxDefaultWith
193 -- , demuxWithSel
194 -- , demuxWithMin
196 -- ** Classifying
197 -- | In an input stream of key value pairs fold values for different keys
198 -- in individual output buckets using the given fold.
199 , classify
200 , classifyWith
201 -- , classifyWithSel
202 -- , classifyWithMin
204 -- ** Unzipping
205 , unzip
206 -- These two can be expressed using lmap/lmapM and unzip
207 , unzipWith
208 , unzipWithM
209 , unzipWithFstM
210 , unzipWithMinM
212 -- ** Zipping
213 , zipWithM
214 , zip
216 -- ** Splitting
217 , many
218 , chunksOf
219 , chunksBetween
221 -- ** Nesting
222 , concatSequence
223 , concatMap
225 -- * Running A Fold
226 -- | Normally you would run a fold to completion by supplying it a stream,
227 -- e.g. using 'Stream.fold'. However, you could also run a fold partially
228 -- by using 'duplicate' on it and then running it with a stream.
229 -- Alternatively, 'initialize', 'snoc' and 'finish' can be used to run a
230 -- fold incrementally, however, that may not be the most efficient way to
231 -- run a fold.
232 , initialize
233 , snoc
234 , duplicate
235 , finish
237 -- * Deprecated
238 , sequence
239 , mapM
240 )
241where
243import Data.Bifunctor (first)
244import Data.Either (isLeft, isRight)
245import Data.Functor.Identity (Identity(..))
246import Data.Int (Int64)
247import Data.Map.Strict (Map)
248import Data.Maybe (isJust, fromJust)
249#if __GLASGOW_HASKELL__ < 804
250import Data.Semigroup (Semigroup((<>)))
251#endif
252import Streamly.Internal.BaseCompat (fromLeft, fromRight)
253import Streamly.Internal.Data.Either.Strict
254 (Either'(..), fromLeft', fromRight', isLeft', isRight')
255import Streamly.Internal.Data.Pipe.Type (Pipe (..), PipeState(..))
256import Streamly.Internal.Data.Tuple.Strict (Tuple'(..), Tuple3'(..))
257import Streamly.Internal.Data.Stream.Serial (SerialT(..))
259import qualified Data.Map.Strict as Map
260import qualified Streamly.Internal.Data.Pipe.Type as Pipe
261-- import qualified Streamly.Internal.Data.Stream.IsStream.Enumeration as Stream
262import qualified Prelude
264import Prelude hiding
265 ( filter, foldl1, drop, dropWhile, take, takeWhile, zipWith
266 , foldl, foldr, map, mapM_, sequence, all, any, sum, product, elem
267 , notElem, maximum, minimum, head, last, tail, length, null
268 , reverse, iterate, init, and, or, lookup, (!!)
269 , scanl, scanl1, replicate, concatMap, mconcat, foldMap, unzip
270 , span, splitAt, break, mapM, zip)
271import Streamly.Internal.Data.Fold.Type
273-- $setup
274-- >>> :m
275-- >>> import Prelude hiding (break, map, span, splitAt)
276-- >>> import qualified Streamly.Prelude as Stream
277-- >>> import qualified Streamly.Internal.Data.Stream.IsStream as Stream (parse, foldMany)
278-- >>> import qualified Streamly.Data.Fold as Fold
279-- >>> import qualified Streamly.Internal.Data.Fold as Fold
280-- >>> import qualified Streamly.Internal.Data.Fold.Type as Fold
281-- >>> import qualified Streamly.Internal.Data.Parser as Parser
282-- >>> import Streamly.Internal.Data.Stream.Serial (SerialT(..))
283-- >>> import Data.IORef (newIORef, readIORef, writeIORef)
285------------------------------------------------------------------------------
286-- hoist
287------------------------------------------------------------------------------
289-- | Change the underlying monad of a fold
290--
291-- /Pre-release/
292hoist :: (forall x. m x -> n x) -> Fold m a b -> Fold n a b
293hoist f (Fold step initial extract) =
294 Fold (\x a -> f $ step x a) (f initial) (f . extract)
296-- | Adapt a pure fold to any monad
297--
298-- > generally = Fold.hoist (return . runIdentity)
299--
300-- /Pre-release/
301generally :: Monad m => Fold Identity a b -> Fold m a b
302generally = hoist (return . runIdentity)
304------------------------------------------------------------------------------
305-- Transformations on fold inputs
306------------------------------------------------------------------------------
308-- | Flatten the monadic output of a fold to pure output.
309--
310-- @since 0.7.0
311{-# DEPRECATED sequence "Use \"rmapM id\" instead" #-}
312{-# INLINE sequence #-}
313sequence :: Monad m => Fold m a (m b) -> Fold m a b
314sequence = rmapM id
316-- | Map a monadic function on the output of a fold.
317--
318-- @since 0.7.0
319{-# DEPRECATED mapM "Use rmapM instead" #-}
320{-# INLINE mapM #-}
321mapM :: Monad m => (b -> m c) -> Fold m a b -> Fold m a c
322mapM = rmapM
324-- | @mapMaybe f fold@ maps a 'Maybe' returning function @f@ on the input of
325-- the fold, filters out 'Nothing' elements, and return the values extracted
326-- from 'Just'.
327--
328-- >>> f x = if even x then Just x else Nothing
329-- >>> fld = Fold.mapMaybe f Fold.toList
330-- >>> Stream.fold fld (Stream.enumerateFromTo 1 10)
331-- [2,4,6,8,10]
332--
333-- @since 0.8.0
334{-# INLINE mapMaybe #-}
335mapMaybe :: (Monad m) => (a -> Maybe b) -> Fold m b r -> Fold m a r
336mapMaybe f = lmap f . filter isJust . lmap fromJust
338------------------------------------------------------------------------------
339-- Transformations on fold inputs
340------------------------------------------------------------------------------
342-- rename to lpipe?
343--
344-- | Apply a transformation on a 'Fold' using a 'Pipe'.
345--
346-- /Pre-release/
347{-# INLINE transform #-}
348transform :: Monad m => Pipe m a b -> Fold m b c -> Fold m a c
349transform (Pipe pstep1 pstep2 pinitial) (Fold fstep finitial fextract) =
350 Fold step initial extract
352 where
354 initial = first (Tuple' pinitial) <$> finitial
356 step (Tuple' ps fs) x = do
357 r <- pstep1 ps x
358 go fs r
360 where
362 -- XXX use SPEC?
363 go acc (Pipe.Yield b (Consume ps')) = do
364 acc' <- fstep acc b
365 return
366 $ case acc' of
367 Partial s -> Partial $ Tuple' ps' s
368 Done b2 -> Done b2
369 go acc (Pipe.Yield b (Produce ps')) = do
370 acc' <- fstep acc b
371 r <- pstep2 ps'
372 case acc' of
373 Partial s -> go s r
374 Done b2 -> return $ Done b2
375 go acc (Pipe.Continue (Consume ps')) =
376 return $ Partial $ Tuple' ps' acc
377 go acc (Pipe.Continue (Produce ps')) = do
378 r <- pstep2 ps'
379 go acc r
381 extract (Tuple' _ fs) = fextract fs
383-- | Scan the input of a 'Fold' to change it in a stateful manner using another
384-- 'Fold'.
385-- /Pre-release/
386{-# INLINE scan #-}
387scan :: Monad m => Fold m a b -> Fold m b c -> Fold m a c
388scan (Fold stepL initialL extractL) (Fold stepR initialR extractR) =
389 Fold step initial extract
391 where
393 runStep actionL sR = do
394 rL <- actionL
395 case rL of
396 Done bL -> do
397 rR <- stepR sR bL
398 case rR of
399 Partial sR1 -> Done <$> extractR sR1
400 Done bR -> return $ Done bR
401 Partial sL -> do
402 !b <- extractL sL
403 rR <- stepR sR b
404 return
405 $ case rR of
406 Partial sR1 -> Partial (sL, sR1)
407 Done bR -> Done bR
409 initial = do
410 r <- initialR
411 case r of
412 Partial sR -> runStep initialL sR
413 Done b -> return $ Done b
415 step (sL, sR) x = runStep (stepL sL x) sR
417 extract = extractR . snd
419------------------------------------------------------------------------------
420-- Left folds
421------------------------------------------------------------------------------
423------------------------------------------------------------------------------
424-- Run Effects
425------------------------------------------------------------------------------
427-- |
428-- > drainBy f = lmapM f drain
429-- > drainBy = Fold.foldMapM (void . f)
430--
431-- Drain all input after passing it through a monadic function. This is the
432-- dual of mapM_ on stream producers.
433--
434-- See also: 'Streamly.Prelude.mapM_'
435--
436-- @since 0.7.0
437{-# INLINABLE drainBy #-}
438drainBy :: Monad m => (a -> m b) -> Fold m a ()
439drainBy f = lmapM f drain
441-- | Extract the last element of the input stream, if any.
442--
443-- > last = fmap getLast $ Fold.foldMap (Last . Just)
444--
445-- @since 0.7.0
446{-# INLINABLE last #-}
447last :: Monad m => Fold m a (Maybe a)
448last = foldl1' (\_ x -> x)
450------------------------------------------------------------------------------
451-- To Summary
452------------------------------------------------------------------------------
454-- | Like 'length', except with a more general 'Num' return value
455--
456-- > genericLength = fmap getSum $ foldMap (Sum . const 1)
457--
458-- /Pre-release/
459{-# INLINE genericLength #-}
460genericLength :: (Monad m, Num b) => Fold m a b
461genericLength = foldl' (\n _ -> n + 1) 0
463-- | Determine the length of the input stream.
464--
465-- > length = fmap getSum $ Fold.foldMap (Sum . const 1)
466--
467-- @since 0.7.0
468{-# INLINE length #-}
469length :: Monad m => Fold m a Int
470length = genericLength
472-- | Determine the sum of all elements of a stream of numbers. Returns additive
473-- identity (@0@) when the stream is empty. Note that this is not numerically
474-- stable for floating point numbers.
475--
476-- > sum = fmap getSum $ Fold.foldMap Sum
477--
478-- @since 0.7.0
479{-# INLINE sum #-}
480sum :: (Monad m, Num a) => Fold m a a
481sum = foldl' (+) 0
483-- | Determine the product of all elements of a stream of numbers. Returns
484-- multiplicative identity (@1@) when the stream is empty. The fold terminates
485-- when it encounters (@0@) in its input.
486--
487-- Compare with @Fold.foldMap Product@.
488--
489-- @since 0.7.0
490-- /Since 0.8.0 (Added 'Eq' constraint)/
491{-# INLINE product #-}
492product :: (Monad m, Num a, Eq a) => Fold m a a
493product = mkFold_ step (Partial 1)
495 where
497 step x a =
498 if a == 0
499 then Done 0
500 else Partial $ x * a
502------------------------------------------------------------------------------
503-- To Summary (Maybe)
504------------------------------------------------------------------------------
506-- | Determine the maximum element in a stream using the supplied comparison
507-- function.
508--
509-- @since 0.7.0
510{-# INLINE maximumBy #-}
511maximumBy :: Monad m => (a -> a -> Ordering) -> Fold m a (Maybe a)
512maximumBy cmp = foldl1' max'
514 where
516 max' x y =
517 case cmp x y of
518 GT -> x
519 _ -> y
521-- |
522-- @
523-- maximum = Fold.maximumBy compare
524-- @
525--
526-- Determine the maximum element in a stream.
527--
528-- Compare with @Fold.foldMap Max@.
529--
530-- @since 0.7.0
531{-# INLINE maximum #-}
532maximum :: (Monad m, Ord a) => Fold m a (Maybe a)
533maximum = foldl1' max
535-- | Computes the minimum element with respect to the given comparison function
536--
537-- @since 0.7.0
538{-# INLINE minimumBy #-}
539minimumBy :: Monad m => (a -> a -> Ordering) -> Fold m a (Maybe a)
540minimumBy cmp = foldl1' min'
542 where
544 min' x y =
545 case cmp x y of
546 GT -> y
547 _ -> x
549-- | Determine the minimum element in a stream using the supplied comparison
550-- function.
551--
552-- @
553-- minimum = 'minimumBy' compare
554-- @
555--
556-- Compare with @Fold.foldMap Min@.
557--
558-- @since 0.7.0
559{-# INLINE minimum #-}
560minimum :: (Monad m, Ord a) => Fold m a (Maybe a)
561minimum = foldl1' min
563------------------------------------------------------------------------------
564-- To Summary (Statistical)
565------------------------------------------------------------------------------
567-- | Compute a numerically stable arithmetic mean of all elements in the input
568-- stream.
569--
570-- @since 0.7.0
571{-# INLINABLE mean #-}
572mean :: (Monad m, Fractional a) => Fold m a a
573mean = fmap done $ foldl' step begin
575 where
577 begin = Tuple' 0 0
579 step (Tuple' x n) y =
580 let n1 = n + 1
581 in Tuple' (x + (y - x) / n1) n1
583 done (Tuple' x _) = x
585-- | Compute a numerically stable (population) variance over all elements in
586-- the input stream.
587--
588-- @since 0.7.0
589{-# INLINABLE variance #-}
590variance :: (Monad m, Fractional a) => Fold m a a
591variance = fmap done $ foldl' step begin
593 where
595 begin = Tuple3' 0 0 0
597 step (Tuple3' n mean_ m2) x = Tuple3' n' mean' m2'
599 where
601 n' = n + 1
602 mean' = (n * mean_ + x) / (n + 1)
603 delta = x - mean_
604 m2' = m2 + delta * delta * n / (n + 1)
606 done (Tuple3' n _ m2) = m2 / n
608-- | Compute a numerically stable (population) standard deviation over all
609-- elements in the input stream.
610--
611-- @since 0.7.0
612{-# INLINABLE stdDev #-}
613stdDev :: (Monad m, Floating a) => Fold m a a
614stdDev = sqrt <$> variance
616-- | Compute an 'Int' sized polynomial rolling hash
617--
618-- > H = salt * k ^ n + c1 * k ^ (n - 1) + c2 * k ^ (n - 2) + ... + cn * k ^ 0
619--
620-- Where @c1@, @c2@, @cn@ are the elements in the input stream and @k@ is a
621-- constant.
622--
623-- This hash is often used in Rabin-Karp string search algorithm.
624--
625-- See https://en.wikipedia.org/wiki/Rolling_hash
626--
627-- @since 0.8.0
628{-# INLINABLE rollingHashWithSalt #-}
629rollingHashWithSalt :: (Monad m, Enum a) => Int64 -> Fold m a Int64
630rollingHashWithSalt = foldl' step
632 where
634 k = 2891336453 :: Int64
636 step cksum a = cksum * k + fromIntegral (fromEnum a)
638-- | A default salt used in the implementation of 'rollingHash'.
639{-# INLINE defaultSalt #-}
640defaultSalt :: Int64
641defaultSalt = -2578643520546668380
643-- | Compute an 'Int' sized polynomial rolling hash of a stream.
644--
645-- > rollingHash = Fold.rollingHashWithSalt defaultSalt
646--
647-- @since 0.8.0
648{-# INLINABLE rollingHash #-}
649rollingHash :: (Monad m, Enum a) => Fold m a Int64
650rollingHash = rollingHashWithSalt defaultSalt
652-- | Compute an 'Int' sized polynomial rolling hash of the first n elements of
653-- a stream.
654--
655-- > rollingHashFirstN = Fold.take n Fold.rollingHash
656--
657-- /Pre-release/
658{-# INLINABLE rollingHashFirstN #-}
659rollingHashFirstN :: (Monad m, Enum a) => Int -> Fold m a Int64
660rollingHashFirstN n = take n rollingHash
662------------------------------------------------------------------------------
663-- Monoidal left folds
664------------------------------------------------------------------------------
666-- | Append the elements of an input stream to a provided starting value.
667--
668-- >>> Stream.fold (Fold.sconcat 10) (Stream.map Data.Monoid.Sum $ Stream.enumerateFromTo 1 10)
669-- Sum {getSum = 65}
670--
671-- @
672-- sconcat = Fold.foldl' (<>)
673-- @
674--
675-- @since 0.8.0
676{-# INLINE sconcat #-}
677sconcat :: (Monad m, Semigroup a) => a -> Fold m a a
678sconcat = foldl' (<>)
680-- | Fold an input stream consisting of monoidal elements using 'mappend'
681-- and 'mempty'.
682--
683-- >>> Stream.fold Fold.mconcat (Stream.map Data.Monoid.Sum $ Stream.enumerateFromTo 1 10)
684-- Sum {getSum = 55}
685--
686-- > mconcat = Fold.sconcat mempty
687--
688-- @since 0.7.0
689{-# INLINE mconcat #-}
690mconcat ::
691 ( Monad m
692#if !MIN_VERSION_base(4,11,0)
693 , Semigroup a
694#endif
695 , Monoid a) => Fold m a a
696mconcat = sconcat mempty
698-- |
699-- > foldMap f = Fold.lmap f Fold.mconcat
700--
701-- Make a fold from a pure function that folds the output of the function
702-- using 'mappend' and 'mempty'.
703--
704-- >>> Stream.fold (Fold.foldMap Data.Monoid.Sum) $ Stream.enumerateFromTo 1 10
705-- Sum {getSum = 55}
706--
707-- @since 0.7.0
708{-# INLINABLE foldMap #-}
709foldMap :: (Monad m, Monoid b
710#if !MIN_VERSION_base(4,11,0)
711 , Semigroup b
712#endif
713 ) => (a -> b) -> Fold m a b
714foldMap f = lmap f mconcat
716-- |
717-- > foldMapM f = Fold.lmapM f Fold.mconcat
718--
719-- Make a fold from a monadic function that folds the output of the function
720-- using 'mappend' and 'mempty'.
721--
722-- >>> Stream.fold (Fold.foldMapM (return . Data.Monoid.Sum)) $ Stream.enumerateFromTo 1 10
723-- Sum {getSum = 55}
724--
725-- @since 0.7.0
726{-# INLINABLE foldMapM #-}
727foldMapM :: (Monad m, Monoid b) => (a -> m b) -> Fold m a b
728foldMapM act = foldlM' step (pure mempty)
730 where
732 step m a = do
733 m' <- act a
734 return $! mappend m m'
736------------------------------------------------------------------------------
737-- To Containers
738------------------------------------------------------------------------------
740-- $toListRev
741-- This is more efficient than 'Streamly.Internal.Data.Fold.toList'. toList is
742-- exactly the same as reversing the list after 'toListRev'.
744-- | Buffers the input stream to a list in the reverse order of the input.
745--
746-- > toListRev = Fold.foldl' (flip (:)) []
747--
748-- /Warning!/ working on large lists accumulated as buffers in memory could be
749-- very inefficient, consider using "Streamly.Array" instead.
750--
751-- @since 0.8.0
753-- xn : ... : x2 : x1 : []
754{-# INLINABLE toListRev #-}
755toListRev :: Monad m => Fold m a [a]
756toListRev = foldl' (flip (:)) []
758------------------------------------------------------------------------------
759-- Partial Folds
760------------------------------------------------------------------------------
762-- | A fold that drains the first n elements of its input, running the effects
763-- and discarding the results.
764--
765-- > drainN n = Fold.take n Fold.drain
766--
767-- /Pre-release/
768{-# INLINABLE drainN #-}
769drainN :: Monad m => Int -> Fold m a ()
770drainN n = take n drain
772------------------------------------------------------------------------------
773-- To Elements
774------------------------------------------------------------------------------
776-- | Like 'index', except with a more general 'Integral' argument
777--
778-- /Pre-release/
779{-# INLINABLE genericIndex #-}
780genericIndex :: (Integral i, Monad m) => i -> Fold m a (Maybe a)
781genericIndex i = mkFold step (Partial 0) (const Nothing)
783 where
785 step j a =
786 if i == j
787 then Done $ Just a
788 else Partial (j + 1)
790-- | Lookup the element at the given index.
791--
792-- See also: 'Streamly.Prelude.!!'
793--
794-- @since 0.7.0
795{-# INLINABLE index #-}
796index :: Monad m => Int -> Fold m a (Maybe a)
797index = genericIndex
799-- | Extract the first element of the stream, if any.
800--
801-- @since 0.7.0
802{-# INLINABLE head #-}
803head :: Monad m => Fold m a (Maybe a)
804head = mkFold_ (const (Done . Just)) (Partial Nothing)
806-- | Returns the first element that satisfies the given predicate.
807--
808-- @since 0.7.0
809{-# INLINABLE find #-}
810find :: Monad m => (a -> Bool) -> Fold m a (Maybe a)
811find predicate = mkFold step (Partial ()) (const Nothing)
813 where
815 step () a =
816 if predicate a
817 then Done (Just a)
818 else Partial ()
820-- | In a stream of (key-value) pairs @(a, b)@, return the value @b@ of the
821-- first pair where the key equals the given value @a@.
822--
823-- > lookup = snd <$> Fold.find ((==) . fst)
824--
825-- @since 0.7.0
826{-# INLINABLE lookup #-}
827lookup :: (Eq a, Monad m) => a -> Fold m (a,b) (Maybe b)
828lookup a0 = mkFold step (Partial ()) (const Nothing)
830 where
832 step () (a, b) =
833 if a == a0
834 then Done $ Just b
835 else Partial ()
837-- | Returns the first index that satisfies the given predicate.
838--
839-- @since 0.7.0
840{-# INLINABLE findIndex #-}
841findIndex :: Monad m => (a -> Bool) -> Fold m a (Maybe Int)
842findIndex predicate = mkFold step (Partial 0) (const Nothing)
844 where
846 step i a =
847 if predicate a
848 then Done $ Just i
849 else Partial (i + 1)
851-- | Returns the first index where a given value is found in the stream.
852--
853-- > elemIndex a = Fold.findIndex (== a)
854--
855-- @since 0.7.0
856{-# INLINABLE elemIndex #-}
857elemIndex :: (Eq a, Monad m) => a -> Fold m a (Maybe Int)
858elemIndex a = findIndex (a ==)
860------------------------------------------------------------------------------
861-- To Boolean
862------------------------------------------------------------------------------
864-- | Return 'True' if the input stream is empty.
865--
866-- > null = fmap isJust Fold.head
867--
868-- @since 0.7.0
869{-# INLINABLE null #-}
870null :: Monad m => Fold m a Bool
871null = mkFold (\() _ -> Done False) (Partial ()) (const True)
873-- | Returns 'True' if any of the elements of a stream satisfies a predicate.
874--
875-- >>> Stream.fold (Fold.any (== 0)) $ Stream.fromList [1,0,1]
876-- True
877--
878-- > any p = Fold.lmap p Fold.or
879--
880-- @since 0.7.0
881{-# INLINE any #-}
882any :: Monad m => (a -> Bool) -> Fold m a Bool
883any predicate = mkFold_ step initial
885 where
887 initial = Partial False
889 step _ a =
890 if predicate a
891 then Done True
892 else Partial False
894-- | Return 'True' if the given element is present in the stream.
895--
896-- > elem a = Fold.any (== a)
897--
898-- @since 0.7.0
899{-# INLINABLE elem #-}
900elem :: (Eq a, Monad m) => a -> Fold m a Bool
901elem a = any (a ==)
903-- | Returns 'True' if all elements of a stream satisfy a predicate.
904--
905-- >>> Stream.fold (Fold.all (== 0)) $ Stream.fromList [1,0,1]
906-- False
907--
908-- > all p = Fold.lmap p Fold.and
909--
910-- @since 0.7.0
911{-# INLINABLE all #-}
912all :: Monad m => (a -> Bool) -> Fold m a Bool
913all predicate = mkFold_ step initial
915 where
917 initial = Partial True
919 step _ a =
920 if predicate a
921 then Partial True
922 else Done False
924-- | Returns 'True' if the given element is not present in the stream.
925--
926-- > notElem a = Fold.all (/= a)
927--
928-- @since 0.7.0
929{-# INLINABLE notElem #-}
930notElem :: (Eq a, Monad m) => a -> Fold m a Bool
931notElem a = all (a /=)
933-- | Returns 'True' if all elements are 'True', 'False' otherwise
934--
935-- > and = Fold.all (== True)
936--
937-- @since 0.7.0
938{-# INLINE and #-}
939and :: Monad m => Fold m Bool Bool
940and = all (== True)
942-- | Returns 'True' if any element is 'True', 'False' otherwise
943--
944-- > or = Fold.any (== True)
945--
946-- @since 0.7.0
947{-# INLINE or #-}
948or :: Monad m => Fold m Bool Bool
949or = any (== True)
951------------------------------------------------------------------------------
952-- Grouping/Splitting
953------------------------------------------------------------------------------
955------------------------------------------------------------------------------
956-- Grouping without looking at elements
957------------------------------------------------------------------------------
959------------------------------------------------------------------------------
960-- Binary APIs
961------------------------------------------------------------------------------
963-- | @splitAt n f1 f2@ composes folds @f1@ and @f2@ such that first @n@
964-- elements of its input are consumed by fold @f1@ and the rest of the stream
965-- is consumed by fold @f2@.
966--
967-- >>> let splitAt_ n xs = Stream.fold (Fold.splitAt n Fold.toList Fold.toList) $ Stream.fromList xs
968--
969-- >>> splitAt_ 6 "Hello World!"
970-- ("Hello ","World!")
971--
972-- >>> splitAt_ (-1) [1,2,3]
973-- ([],[1,2,3])
974--
975-- >>> splitAt_ 0 [1,2,3]
976-- ([],[1,2,3])
977--
978-- >>> splitAt_ 1 [1,2,3]
979-- ([1],[2,3])
980--
981-- >>> splitAt_ 3 [1,2,3]
982-- ([1,2,3],[])
983--
984-- >>> splitAt_ 4 [1,2,3]
985-- ([1,2,3],[])
986--
987-- > splitAt n f1 f2 = Fold.serialWith (,) (Fold.take n f1) f2
988--
989-- /Internal/
991{-# INLINE splitAt #-}
992splitAt
993 :: Monad m
994 => Int
995 -> Fold m a b
996 -> Fold m a c
997 -> Fold m a (b, c)
998splitAt n fld = serialWith (,) (take n fld)
1000------------------------------------------------------------------------------
1001-- Element Aware APIs
1002------------------------------------------------------------------------------
1004------------------------------------------------------------------------------
1005-- Binary APIs
1006------------------------------------------------------------------------------
1008-- Note: Keep this consistent with S.splitOn. In fact we should eliminate
1009-- S.splitOn in favor of the fold.
1011-- XXX Use Fold.many instead once it is fixed.
1013-- | Like 'takeEndBy' but drops the element on which the predicate succeeds.
1015-- >>> Stream.fold (Fold.takeEndBy_ (== '\n') Fold.toList) $ Stream.fromList "hello\nthere\n"
1016-- "hello"
1018-- >>> Stream.toList $ Stream.foldMany (Fold.takeEndBy_ (== '\n') Fold.toList) $ Stream.fromList "hello\nthere\n"
1019-- ["hello","there"]
1021-- > Stream.splitOnSuffix p f = Stream.foldMany (Fold.takeEndBy_ p f)
1023-- See 'Streamly.Prelude.splitOnSuffix' for more details on splitting a
1024-- stream using 'takeEndBy_'.
1026-- @since 0.8.0
1027{-# INLINE takeEndBy_ #-}
1028takeEndBy_ :: Monad m => (a -> Bool) -> Fold m a b -> Fold m a b
1029takeEndBy_ predicate (Fold fstep finitial fextract) =
1030 Fold step finitial fextract
1032 where
1034 step s a =
1035 if not (predicate a)
1036 then fstep s a
1037 else Done <$> fextract s
1039-- | Take the input, stop when the predicate succeeds taking the succeeding
1040-- element as well.
1042-- >>> Stream.fold (Fold.takeEndBy (== '\n') Fold.toList) $ Stream.fromList "hello\nthere\n"
1043-- "hello\n"
1045-- >>> Stream.toList $ Stream.foldMany (Fold.takeEndBy (== '\n') Fold.toList) $ Stream.fromList "hello\nthere\n"
1046-- ["hello\n","there\n"]
1048-- > Stream.splitWithSuffix p f = Stream.foldMany (Fold.takeEndBy p f)
1050-- See 'Streamly.Prelude.splitWithSuffix' for more details on splitting a
1051-- stream using 'takeEndBy'.
1053-- @since 0.8.0
1054{-# INLINE takeEndBy #-}
1055takeEndBy :: Monad m => (a -> Bool) -> Fold m a b -> Fold m a b
1056takeEndBy predicate (Fold fstep finitial fextract) =
1057 Fold step finitial fextract
1059 where
1061 step s a = do
1062 res <- fstep s a
1063 if not (predicate a)
1064 then return res
1065 else do
1066 case res of
1067 Partial s1 -> Done <$> fextract s1
1068 Done b -> return $ Done b
1070------------------------------------------------------------------------------
1071-- Binary splitting on a separator
1072------------------------------------------------------------------------------
1075-- | Find the first occurrence of the specified sequence in the input stream
1076-- and break the input stream into two parts, the first part consisting of the
1077-- stream before the sequence and the second part consisting of the sequence
1078-- and the rest of the stream.
1080-- > let breakOn_ pat xs = S.fold (S.breakOn pat FL.toList FL.toList) $ S.fromList xs
1082-- >>> breakOn_ "dear" "Hello dear world!"
1083-- > ("Hello ","dear world!")
1085{-# INLINE breakOn #-}
1086breakOn :: Monad m => Array a -> Fold m a b -> Fold m a c -> Fold m a (b,c)
1087breakOn pat f m = undefined
1090------------------------------------------------------------------------------
1091-- Distributing
1092------------------------------------------------------------------------------
1094-- | Distribute one copy of the stream to each fold and zip the results.
1096-- @
1097-- |-------Fold m a b--------|
1098-- ---stream m a---| |---m (b,c)
1099-- |-------Fold m a c--------|
1100-- @
1101-- >>> Stream.fold (Fold.tee Fold.sum Fold.length) (Stream.enumerateFromTo 1.0 100.0)
1102-- (5050.0,100)
1104-- > tee = teeWith (,)
1106-- @since 0.7.0
1107{-# INLINE tee #-}
1108tee :: Monad m => Fold m a b -> Fold m a c -> Fold m a (b,c)
1109tee = teeWith (,)
1111-- XXX use "List" instead of "[]"?, use Array for output to scale it to a large
1112-- number of consumers? For polymorphic case a vector could be helpful. For
1113-- Storables we can use arrays. Will need separate APIs for those.
1115-- | Distribute one copy of the stream to each fold and collect the results in
1116-- a container.
1118-- @
1120-- |-------Fold m a b--------|
1121-- ---stream m a---| |---m [b]
1122-- |-------Fold m a b--------|
1123-- | |
1124-- ...
1125-- @
1127-- >>> Stream.fold (Fold.distribute [Fold.sum, Fold.length]) (Stream.enumerateFromTo 1 5)
1128-- [15,5]
1130-- > distribute = Prelude.foldr (Fold.teeWith (:)) (Fold.fromPure [])
1132-- This is the consumer side dual of the producer side 'sequence' operation.
1134-- Stops when all the folds stop.
1136-- @since 0.7.0
1137{-# INLINE distribute #-}
1138distribute :: Monad m => [Fold m a b] -> Fold m a [b]
1139distribute = Prelude.foldr (teeWith (:)) (fromPure [])
1141------------------------------------------------------------------------------
1142-- Partitioning
1143------------------------------------------------------------------------------
1145{-# INLINE partitionByMUsing #-}
1146partitionByMUsing :: Monad m =>
1147 ( (x -> y -> (x, y))
1148 -> Fold m (Either b c) x
1149 -> Fold m (Either b c) y
1150 -> Fold m (Either b c) (x, y)
1152 -> (a -> m (Either b c))
1153 -> Fold m b x
1154 -> Fold m c y
1155 -> Fold m a (x, y)
1156partitionByMUsing t f fld1 fld2 =
1157 let l = lmap (fromLeft undefined) fld1 -- :: Fold m (Either b c) x
1158 r = lmap (fromRight undefined) fld2 -- :: Fold m (Either b c) y
1159 in lmapM f (t (,) (filter isLeft l) (filter isRight r))
1161-- | Partition the input over two folds using an 'Either' partitioning
1162-- predicate.
1164-- @
1166-- |-------Fold b x--------|
1167-- -----stream m a --> (Either b c)----| |----(x,y)
1168-- |-------Fold c y--------|
1169-- @
1171-- Send input to either fold randomly:
1173-- @
1174-- > import System.Random (randomIO)
1175-- > randomly a = randomIO >>= \\x -> return $ if x then Left a else Right a
1176-- > Stream.fold (Fold.partitionByM randomly Fold.length Fold.length) (Stream.enumerateFromTo 1 100)
1177-- (59,41)
1178-- @
1180-- Send input to the two folds in a proportion of 2:1:
1182-- >>> :{
1183-- proportionately m n = do
1184-- ref <- newIORef $ cycle $ concat [replicate m Left, replicate n Right]
1185-- return $ \a -> do
1186-- r <- readIORef ref
1187-- writeIORef ref $ tail r
1188-- return $ Prelude.head r a
1189-- :}
1191-- >>> :{
1192-- main = do
1193-- f <- proportionately 2 1
1194-- r <- Stream.fold (Fold.partitionByM f Fold.length Fold.length) (Stream.enumerateFromTo (1 :: Int) 100)
1195-- print r
1196-- :}
1198-- >>> main
1199-- (67,33)
1202-- This is the consumer side dual of the producer side 'mergeBy' operation.
1204-- When one fold is done, any input meant for it is ignored until the other
1205-- fold is also done.
1207-- Stops when both the folds stop.
1209-- /See also: 'partitionByFstM' and 'partitionByMinM'./
1211-- /Pre-release/
1212{-# INLINE partitionByM #-}
1213partitionByM :: Monad m
1214 => (a -> m (Either b c)) -> Fold m b x -> Fold m c y -> Fold m a (x, y)
1215partitionByM = partitionByMUsing teeWith
1217-- | Similar to 'partitionByM' but terminates when the first fold terminates.
1220{-# INLINE partitionByFstM #-}
1221partitionByFstM :: Monad m
1222 => (a -> m (Either b c)) -> Fold m b x -> Fold m c y -> Fold m a (x, y)
1223partitionByFstM = partitionByMUsing teeWithFst
1225-- | Similar to 'partitionByM' but terminates when any fold terminates.
1228{-# INLINE partitionByMinM #-}
1229partitionByMinM :: Monad m =>
1230 (a -> m (Either b c)) -> Fold m b x -> Fold m c y -> Fold m a (x, y)
1231partitionByMinM = partitionByMUsing teeWithMin
1233-- Note: we could use (a -> Bool) instead of (a -> Either b c), but the latter
1234-- makes the signature clearer as to which case belongs to which fold.
1235-- XXX need to check the performance in both cases.
1236-- | Same as 'partitionByM' but with a pure partition function.
1238-- Count even and odd numbers in a stream:
1240-- >>> :{
1241-- let f = Fold.partitionBy (\n -> if even n then Left n else Right n)
1242-- (fmap (("Even " ++) . show) Fold.length)
1243-- (fmap (("Odd " ++) . show) Fold.length)
1244-- in Stream.fold f (Stream.enumerateFromTo 1 100)
1245-- :}
1246-- ("Even 50","Odd 50")
1248-- /Pre-release/
1249{-# INLINE partitionBy #-}
1250partitionBy :: Monad m
1251 => (a -> Either b c) -> Fold m b x -> Fold m c y -> Fold m a (x, y)
1252partitionBy f = partitionByM (return . f)
1254-- | Compose two folds such that the combined fold accepts a stream of 'Either'
1255-- and routes the 'Left' values to the first fold and 'Right' values to the
1256-- second fold.
1258-- > partition = partitionBy id
1260-- @since 0.7.0
1261{-# INLINE partition #-}
1262partition :: Monad m
1263 => Fold m b x -> Fold m c y -> Fold m (Either b c) (x, y)
1264partition = partitionBy id
1267-- | Send one item to each fold in a round-robin fashion. This is the consumer
1268-- side dual of producer side 'mergeN' operation.
1270-- partitionN :: Monad m => [Fold m a b] -> Fold m a [b]
1271-- partitionN fs = Fold step begin done
1274-- TODO Demultiplex an input element into a number of typed variants. We want
1275-- to statically restrict the target values within a set of predefined types,
1276-- an enumeration of a GADT. We also want to make sure that the Map contains
1277-- only those types and the full set of those types.
1279-- TODO Instead of the input Map it should probably be a lookup-table using an
1280-- array and not in GC memory. The same applies to the output Map as well.
1281-- However, that would only be helpful if we have a very large data structure,
1282-- need to measure and see how it scales.
1284-- This is the consumer side dual of the producer side 'mux' operation (XXX to
1285-- be implemented).
1287-- | Split the input stream based on a key field and fold each split using a
1288-- specific fold collecting the results in a map from the keys to the results.
1289-- Useful for cases like protocol handlers to handle different type of packets
1290-- using different handlers.
1292-- @
1294-- |-------Fold m a b
1295-- -----stream m a-----Map-----|
1296-- |-------Fold m a b
1297-- |
1298-- ...
1299-- @
1301-- Any input that does not map to a fold in the input Map is silently ignored.
1303-- > demuxWith f kv = fmap fst $ demuxDefaultWith f kv drain
1305-- /Pre-release/
1307{-# INLINE demuxWith #-}
1308demuxWith :: (Monad m, Ord k)
1309 => (a -> (k, a')) -> Map k (Fold m a' b) -> Fold m a (Map k b)
1310demuxWith f kv = fmap fst $ demuxDefaultWith f kv drain
1312-- | Fold a stream of key value pairs using a map of specific folds for each
1313-- key into a map from keys to the results of fold outputs of the corresponding
1314-- values.
1316-- >>> import qualified Data.Map
1317-- >>> :{
1318-- let table = Data.Map.fromList [("SUM", Fold.sum), ("PRODUCT", Fold.product)]
1319-- input = Stream.fromList [("SUM",1),("PRODUCT",2),("SUM",3),("PRODUCT",4)]
1320-- in Stream.fold (Fold.demux table) input
1321-- :}
1322-- fromList [("PRODUCT",8),("SUM",4)]
1324-- > demux = demuxWith id
1326-- /Pre-release/
1327{-# INLINE demux #-}
1328demux :: (Monad m, Ord k)
1329 => Map k (Fold m a b) -> Fold m (k, a) (Map k b)
1330demux = demuxWith id
1332data DemuxState s b doneMap runMap =
1333 DemuxMapAndDefault !s !doneMap !runMap
1334 | DemuxOnlyMap b !doneMap !runMap
1335 | DemuxOnlyDefault s !doneMap
1337-- | Like 'demuxWith' but uses a default catchall fold to handle inputs which
1338-- do not have a specific fold in the map to handle them.
1340-- If any fold in the map stops, inputs meant for that fold are sent to the
1341-- catchall fold. If the catchall fold stops then inputs that do not match any
1342-- fold are ignored.
1344-- Stops when all the folds, including the catchall fold, stop.
1346-- /Pre-release/
1348{-# INLINE demuxDefaultWith #-}
1349demuxDefaultWith :: (Monad m, Ord k)
1350 => (a -> (k, a'))
1351 -> Map k (Fold m a' b)
1352 -> Fold m (k, a') c
1353 -> Fold m a (Map k b, c)
1354demuxDefaultWith f kv (Fold dstep dinitial dextract) =
1355 Fold step initial extract
1357 where
1359 initial = do
1360 let runInit (Fold step1 initial1 done1) = do
1361 r <- initial1
1362 return
1363 $ case r of
1364 Partial _ -> Right' (Fold step1 (return r) done1)
1365 Done b -> Left' b
1367 -- initialize folds in the kv map and separate the ones that are done
1368 -- from running ones
1369 kv1 <- Prelude.mapM runInit kv
1370 let runMap = Map.map fromRight' $ Map.filter isRight' kv1
1371 doneMap = Map.map fromLeft' $ Map.filter isLeft' kv1
1373 -- Run the default fold, and decide the next state based on its result
1374 dres <- dinitial
1375 return
1376 $ case dres of
1377 Partial s ->
1378 Partial
1379 $ if Map.size runMap > 0
1380 then DemuxMapAndDefault s doneMap runMap
1381 else DemuxOnlyDefault s doneMap
1382 Done b ->
1383 if Map.size runMap > 0
1384 then Partial $ DemuxOnlyMap b doneMap runMap
1385 else Done (doneMap, b)
1387 {-# INLINE runFold #-}
1388 runFold fPartial fDone doneMap runMap (Fold step1 initial1 done1) k a1 = do
1389 resi <- initial1
1390 case resi of
1391 Partial st -> do
1392 res <- step1 st a1
1393 return $ case res of
1394 Partial s ->
1395 let fld = Fold step1 (return $ Partial s) done1
1396 runMap1 = Map.insert k fld runMap
1397 in Partial $ fPartial doneMap runMap1
1398 Done b -> do
1399 let runMap1 = Map.delete k runMap
1400 doneMap1 = Map.insert k b doneMap
1401 if Map.size runMap1 == 0
1402 then fDone doneMap1
1403 else Partial $ fPartial doneMap1 runMap1
1404 Done _ -> error "Bug: demuxDefaultWith: Done fold"
1406 step (DemuxMapAndDefault dacc doneMap runMap) a = do
1407 let (k, a1) = f a
1408 case Map.lookup k runMap of
1409 Nothing -> do
1410 res <- dstep dacc (k, a1)
1411 return
1412 $ Partial
1413 $ case res of
1414 Partial s -> DemuxMapAndDefault s doneMap runMap
1415 Done b -> DemuxOnlyMap b doneMap runMap
1416 Just fld ->
1417 runFold
1418 (DemuxMapAndDefault dacc)
1419 (Partial . DemuxOnlyDefault dacc)
1420 doneMap runMap fld k a1
1422 step (DemuxOnlyMap dval doneMap runMap) a = do
1423 let (k, a1) = f a
1424 case Map.lookup k runMap of
1425 Nothing -> return $ Partial $ DemuxOnlyMap dval doneMap runMap
1426 Just fld ->
1427 runFold
1428 (DemuxOnlyMap dval)
1429 (Done . (, dval))
1430 doneMap runMap fld k a1
1431 step (DemuxOnlyDefault dacc doneMap) a = do
1432 let (k, a1) = f a
1433 res <- dstep dacc (k, a1)
1434 return
1435 $ case res of
1436 Partial s -> Partial $ DemuxOnlyDefault s doneMap
1437 Done b -> Done (doneMap, b)
1439 runExtract (Fold _ initial1 done1) = do
1440 res <- initial1
1441 case res of
1442 Partial s -> done1 s
1443 Done b -> return b
1445 extract (DemuxMapAndDefault dacc doneMap runMap) = do
1446 b <- dextract dacc
1447 runMap1 <- Prelude.mapM runExtract runMap
1448 return (doneMap `Map.union` runMap1, b)
1449 extract (DemuxOnlyMap dval doneMap runMap) = do
1450 runMap1 <- Prelude.mapM runExtract runMap
1451 return (doneMap `Map.union` runMap1, dval)
1452 extract (DemuxOnlyDefault dacc doneMap) = do
1453 b <- dextract dacc
1454 return (doneMap, b)
1456-- |
1457-- > demuxDefault = demuxDefaultWith id
1459-- /Pre-release/
1460{-# INLINE demuxDefault #-}
1461demuxDefault :: (Monad m, Ord k)
1462 => Map k (Fold m a b) -> Fold m (k, a) b -> Fold m (k, a) (Map k b, b)
1463demuxDefault = demuxDefaultWith id
1465-- TODO If the data is large we may need a map/hashmap in pinned memory instead
1466-- of a regular Map. That may require a serializable constraint though. We can
1467-- have another API for that.
1469-- | Split the input stream based on a key field and fold each split using the
1470-- given fold. Useful for map/reduce, bucketizing the input in different bins
1471-- or for generating histograms.
1473-- >>> :{
1474-- let input = Stream.fromList [("ONE",1),("ONE",1.1),("TWO",2), ("TWO",2.2)]
1475-- in Stream.fold (Fold.classifyWith fst (Fold.map snd Fold.toList)) input
1476-- :}
1477-- fromList [("ONE",[1.0,1.1]),("TWO",[2.0,2.2])]
1479-- If the classifier fold stops for a particular key any further inputs in that
1480-- bucket are ignored.
1482-- /Stops: never/
1484-- /Pre-release/
1486{-# INLINE classifyWith #-}
1487classifyWith :: (Monad m, Ord k) => (a -> k) -> Fold m a b -> Fold m a (Map k b)
1488classifyWith f (Fold step1 initial1 extract1) =
1489 rmapM extract $ foldlM' step initial
1491 where
1493 initial = return Map.empty
1495 step kv a =
1496 case Map.lookup k kv of
1497 Nothing -> do
1498 x <- initial1
1499 case x of
1500 Partial s -> do
1501 r <- step1 s a
1502 return
1503 $ flip (Map.insert k) kv
1504 $ case r of
1505 Partial s1 -> Left' s1
1506 Done b -> Right' b
1507 Done b -> return $ Map.insert k (Right' b) kv
1508 Just x -> do
1509 case x of
1510 Left' s -> do
1511 r <- step1 s a
1512 return
1513 $ flip (Map.insert k) kv
1514 $ case r of
1515 Partial s1 -> Left' s1
1516 Done b -> Right' b
1517 Right' _ -> return kv
1519 where
1521 k = f a
1523 extract =
1524 Prelude.mapM
1525 (\case
1526 Left' s -> extract1 s
1527 Right' b -> return b)
1529-- | Given an input stream of key value pairs and a fold for values, fold all
1530-- the values belonging to each key. Useful for map/reduce, bucketizing the
1531-- input in different bins or for generating histograms.
1533-- >>> :{
1534-- let input = Stream.fromList [("ONE",1),("ONE",1.1),("TWO",2), ("TWO",2.2)]
1535-- in Stream.fold (Fold.classify Fold.toList) input
1536-- :}
1537-- fromList [("ONE",[1.0,1.1]),("TWO",[2.0,2.2])]
1539-- Same as:
1541-- > classify fld = Fold.classifyWith fst (lmap snd fld)
1543-- /Pre-release/
1544{-# INLINE classify #-}
1545classify :: (Monad m, Ord k) => Fold m a b -> Fold m (k, a) (Map k b)
1546classify fld = classifyWith fst (lmap snd fld)
1548------------------------------------------------------------------------------
1549-- Unzipping
1550------------------------------------------------------------------------------
1552{-# INLINE unzipWithMUsing #-}
1553unzipWithMUsing :: Monad m =>
1554 ( (x -> y -> (x, y))
1555 -> Fold m (b, c) x
1556 -> Fold m (b, c) y
1557 -> Fold m (b, c) (x, y)
1559 -> (a -> m (b, c))
1560 -> Fold m b x
1561 -> Fold m c y
1562 -> Fold m a (x, y)
1563unzipWithMUsing t f fld1 fld2 =
1564 let f1 = lmap fst fld1 -- :: Fold m (b, c) b
1565 f2 = lmap snd fld2 -- :: Fold m (b, c) c
1566 in lmapM f (t (,) f1 f2)
1568-- | Like 'unzipWith' but with a monadic splitter function.
1570-- @unzipWithM k f1 f2 = lmapM k (unzip f1 f2)@
1572-- /Pre-release/
1573{-# INLINE unzipWithM #-}
1574unzipWithM :: Monad m
1575 => (a -> m (b,c)) -> Fold m b x -> Fold m c y -> Fold m a (x,y)
1576unzipWithM = unzipWithMUsing teeWith
1578-- | Similar to 'unzipWithM' but terminates when the first fold terminates.
1581{-# INLINE unzipWithFstM #-}
1582unzipWithFstM :: Monad m =>
1583 (a -> m (b, c)) -> Fold m b x -> Fold m c y -> Fold m a (x, y)
1584unzipWithFstM = unzipWithMUsing teeWithFst
1586-- | Similar to 'unzipWithM' but terminates when any fold terminates.
1589{-# INLINE unzipWithMinM #-}
1590unzipWithMinM :: Monad m =>
1591 (a -> m (b,c)) -> Fold m b x -> Fold m c y -> Fold m a (x,y)
1592unzipWithMinM = unzipWithMUsing teeWithMin
1594-- | Split elements in the input stream into two parts using a pure splitter
1595-- function, direct each part to a different fold and zip the results.
1597-- @unzipWith f fld1 fld2 = Fold.lmap f (Fold.unzip fld1 fld2)@
1599-- This fold terminates when both the input folds terminate.
1601-- /Pre-release/
1602{-# INLINE unzipWith #-}
1603unzipWith :: Monad m
1604 => (a -> (b,c)) -> Fold m b x -> Fold m c y -> Fold m a (x,y)
1605unzipWith f = unzipWithM (return . f)
1607-- | Send the elements of tuples in a stream of tuples through two different
1608-- folds.
1610-- @
1612-- |-------Fold m a x--------|
1613-- ---------stream of (a,b)--| |----m (x,y)
1614-- |-------Fold m b y--------|
1616-- @
1618-- > unzip = Fold.unzipWith id
1620-- This is the consumer side dual of the producer side 'zip' operation.
1622-- @since 0.7.0
1623{-# INLINE unzip #-}
1624unzip :: Monad m => Fold m a x -> Fold m b y -> Fold m (a,b) (x,y)
1625unzip = unzipWith id
1627------------------------------------------------------------------------------
1628-- Combining streams and folds - Zipping
1629------------------------------------------------------------------------------
1631-- | Zip a stream with the input of a fold using the supplied function.
1633-- /Unimplemented/
1635{-# INLINE zipWithM #-}
1636zipWithM :: -- Monad m =>
1637 (a -> b -> m c) -> t m a -> Fold m c x -> Fold m b x
1638zipWithM = undefined
1640-- | Zip a stream with the input of a fold.
1642-- /Unimplemented/
1644{-# INLINE zip #-}
1645zip :: Monad m => t m a -> Fold m (a, b) x -> Fold m b x
1646zip = zipWithM (curry return)
1648-- | Pair each element of a fold input with its index, starting from index 0.
1650-- /Unimplemented/
1651{-# INLINE indexed #-}
1652indexed :: -- forall m a b. Monad m =>
1653 Fold m (Int, a) b -> Fold m a b
1654indexed = undefined -- zip (Stream.enumerateFrom 0 :: SerialT m Int)
1656-- | Change the predicate function of a Fold from @a -> b@ to accept an
1657-- additional state input @(s, a) -> b@. Convenient to filter with an
1658-- addiitonal index or time input.
1660-- @
1661-- filterWithIndex = with indexed filter
1662-- filterWithAbsTime = with timestamped filter
1663-- filterWithRelTime = with timeIndexed filter
1664-- @
1666-- /Pre-release/
1667{-# INLINE with #-}
1668with ::
1669 (Fold m (s, a) b -> Fold m a b)
1670 -> (((s, a) -> c) -> Fold m (s, a) b -> Fold m (s, a) b)
1671 -> (((s, a) -> c) -> Fold m a b -> Fold m a b)
1672with f comb g = f . comb g . lmap snd
1674-- | @sampleFromthen offset stride@ samples the element at @offset@ index and
1675-- then every element at strides of @stride@.
1677-- /Unimplemented/
1678{-# INLINE sampleFromthen #-}
1679sampleFromthen :: Monad m => Int -> Int -> Fold m a b -> Fold m a b
1680sampleFromthen offset size =
1681 with indexed filter (\(i, _) -> (i + offset) `mod` size == 0)
1683------------------------------------------------------------------------------
1684-- Nesting
1685------------------------------------------------------------------------------
1687-- | @concatSequence f t@ applies folds from stream @t@ sequentially and
1688-- collects the results using the fold @f@.
1690-- /Unimplemented/
1692{-# INLINE concatSequence #-}
1693concatSequence ::
1694 -- IsStream t =>
1695 Fold m b c -> t (Fold m a b) -> Fold m a c
1696concatSequence _f _p = undefined
1698-- | Group the input stream into groups of elements between @low@ and @high@.
1699-- Collection starts in chunks of @low@ and then keeps doubling until we reach
1700-- @high@. Each chunk is folded using the provided fold function.
1702-- This could be useful, for example, when we are folding a stream of unknown
1703-- size to a stream of arrays and we want to minimize the number of
1704-- allocations.
1706-- NOTE: this would be an application of "many" using a terminating fold.
1708-- /Unimplemented/
1710{-# INLINE chunksBetween #-}
1711chunksBetween :: -- Monad m =>
1712 Int -> Int -> Fold m a b -> Fold m b c -> Fold m a c
1713chunksBetween _low _high _f1 _f2 = undefined
1715-- | A fold that buffers its input to a pure stream.
1717-- /Warning!/ working on large streams accumulated as buffers in memory could
1718-- be very inefficient, consider using "Streamly.Data.Array" instead.
1720-- >>> toStream = fmap SerialT Fold.toStreamK
1722-- /Pre-release/
1723{-# INLINE toStream #-}
1724toStream :: Monad m => Fold m a (SerialT n a)
1725toStream = fmap SerialT toStreamK
1727-- This is more efficient than 'toStream'. toStream is exactly the same as
1728-- reversing the stream after toStreamRev.
1730-- | Buffers the input stream to a pure stream in the reverse order of the
1731-- input.
1733-- >>> toStreamRev = fmap SerialT Fold.toStreamKRev
1735-- /Warning!/ working on large streams accumulated as buffers in memory could
1736-- be very inefficient, consider using "Streamly.Data.Array" instead.
1738-- /Pre-release/
1740-- xn : ... : x2 : x1 : []
1741{-# INLINABLE toStreamRev #-}
1742toStreamRev :: Monad m => Fold m a (SerialT n a)
1743toStreamRev = fmap SerialT toStreamKRev