@@ -7,7 +7,8 @@
77-- Stability : experimental
88-- Portability : GHC
99--
10−-- See "Streamly.Data.Fold" for an overview.
10+-- See "Streamly.Data.Fold" for an overview and
11+-- "Streamly.Internal.Data.Fold.Types" for design notes.
1112--
1213-- IMPORTANT: keep the signatures consistent with the folds in Streamly.Prelude
1314
@@ -17,9 +18,10 @@ module Streamly.Internal.Data.Fold
1718 Step (..)
1819 , Fold (..)
1920
20− -- * Creating
21+ -- * Constructors
2122 , mkFoldl
2223 , mkFoldlM
24+ , mkFoldl1
2325 , mkFoldr
2426 , mkFoldrM
2527 , mkFold
@@ -27,21 +29,21 @@ module Streamly.Internal.Data.Fold
2729 , mkFoldM
2830 , mkFoldM_
2931
30− -- * Generators
32+ -- * Folds
33+ -- ** Identity
3134 , yield
3235 , yieldM
3336
34− -- * Accumulators
35− -- ** Semigroups and Monoids
37+ -- ** Accumulators
38+ -- *** Semigroups and Monoids
3639 , sconcat
3740 , mconcat
3841 , foldMap
3942 , foldMapM
4043
41− -- ** Reducers
44+ -- *** Reducers
4245 , drain
4346 , drainBy
44− , drainBy2
4547 , last
4648 , length
4749 , mean
@@ -52,7 +54,7 @@ module Streamly.Internal.Data.Fold
5254 , rollingHashFirstN
5355 -- , rollingHashLastN
5456
55− -- ** Saturating Reducers
57+ -- *** Saturating Reducers
5658 -- | 'product' terminates if it becomes 0. Other folds can theoretically
5759 -- saturate on bounded types, and therefore terminate, however, they will
5860 -- run forever on unbounded types like Integer/Double.
@@ -63,14 +65,17 @@ module Streamly.Internal.Data.Fold
6365 , minimumBy
6466 , minimum
6567
66− -- ** Collectors
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.
6772 , toList
6873 , toListRev
6974 -- $toListRev
7075 , toStream
7176 , toStreamRev
7277
73− -- * Terminating Folds
78+ -- ** Terminating Folds
7479 , drainN
7580 -- , lastN
7681 -- , (!!)
@@ -91,26 +96,21 @@ module Streamly.Internal.Data.Fold
9196 , or
9297 -- , the
9398
94− -- * Adapting
99+ -- * Combinators
100+ -- ** Utilities
101+ , with
102+
103+ -- ** Transforming the Monad
95104 , hoist
96105 , generally
97106
98− -- * Running Incrementally
99− , initialize
100− , runStep
101−
102− -- * Output Transformations
103− , sequence
107+ -- ** Mapping on output
104108 , rmapM
105− , mapM
106109
107− -- * Input Transformations
108−
109− -- ** Mapping
110+ -- ** Mapping on Input
110111 , transform
111112 , map
112113 , lmap
113−
114114 --, lsequence
115115 , lmapM
116116 , indexed
@@ -125,63 +125,67 @@ module Streamly.Internal.Data.Fold
125125 -- ** Mapping Filters
126126 , catMaybes
127127 , mapMaybe
128+ -- , mapMaybeM
128129
129130 {-
130131 -- ** Scanning Filters
131− , lfindIndices
132− , lelemIndices
132+ , findIndices
133+ , elemIndices
133134
134135 -- ** Insertion
135136 -- | Insertion adds more elements to the stream.
136137
137− , linsertBy
138− , lintersperseM
138+ , insertBy
139+ , intersperseM
139140
140141 -- ** Reordering
141− , lreverse
142+ , reverse
142143 -}
143144
144145 -- ** Trimming
145146 , take
146147 , takeInterval
148+
147149 -- By elements
148− , takeEndBy_
149150 , takeEndBy
151+ , takeEndBy_
150152 -- , takeEndBySeq
151153 {-
152− , ldrop
153− , ldropWhile
154− , ldropWhileM
154+ , drop
155+ , dropWhile
156+ , dropWhileM
155157 -}
156158
157− -- * Splitting
158−
159− -- Binary
159+ -- ** Serial Append
160+ , serialWith
160161 -- , tail
161162 -- , init
162163 , splitAt -- spanN
163164 -- , splitIn -- sessionN
164165
165− -- * Distributing
166−
167− , tee
166+ -- ** Parallel Distribution
168167 , teeWith
168+ , tee
169169 , teeWithFst
170170 , teeWithMin
171171 , distribute
172172 -- , distributeFst
173173 -- , distributeMin
174174
175− -- * Partitioning
175+ -- ** Parallel Alternative
176+ , shortest
177+ , longest
176178
179+ -- ** Partitioning
177180 , partitionByM
178181 , partitionByFstM
179182 , partitionByMinM
180183 , partitionBy
181184 , partition
182185
183− -- * Demultiplexing
184−
186+ -- ** Demultiplexing
187+ -- | Direct values in the input stream to different folds using an n-ary
188+ -- fold selector.
185189 , demux -- XXX rename this to demux_
186190 , demuxWith
187191 , demuxDefault -- XXX rename this to demux
@@ -189,31 +193,47 @@ module Streamly.Internal.Data.Fold
189193 -- , demuxWithSel
190194 -- , demuxWithMin
191195
192− -- * Classifying
193−
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.
194199 , classify
195200 , classifyWith
196201 -- , classifyWithSel
197202 -- , classifyWithMin
198203
199− -- * Unzipping
204+ -- ** Unzipping
200205 , unzip
206+ -- These two can be expressed using lmap/lmapM and unzip
201207 , unzipWith
202208 , unzipWithM
203209 , unzipWithFstM
204210 , unzipWithMinM
205211
206− -- * Nesting
212+ -- ** Zipping
213+ , zipWithM
214+ , zip
215+
216+ -- ** Splitting
207217 , many
208218 , intervalsOf
209219 , chunksOf
210220 , chunksBetween
211− , zipWithM
212− , zip
213221
222+ -- ** Nesting
214223 , concatSequence
215224 , concatMap
225+
226+ -- * Running Partially
227+ , initialize
228+ , runStep
216229 , duplicate
230+
231+ -- * Fold2
232+ , drainBy2
233+
234+ -- * Deprecated
235+ , sequence
236+ , mapM
217237 )
218238where
219239
@@ -228,7 +248,6 @@ import Data.Semigroup (Semigroup((<>)))
228248#endif
229249import Streamly.Internal.Data.Either.Strict
230250 (Either'(..), fromLeft', fromRight', isLeft', isRight')
231−import Streamly.Internal.Data.Maybe.Strict (Maybe'(..), toMaybe)
232251import Streamly.Internal.Data.Pipe.Type (Pipe (..), PipeState(..))
233252import Streamly.Internal.Data.Tuple.Strict (Tuple'(..), Tuple3'(..))
234253import Streamly.Internal.Data.Stream.Serial (SerialT)
@@ -270,7 +289,7 @@ hoist f (Fold step initial extract) =
270289
271290-- | Adapt a pure fold to any monad
272291--
273−-- > generally = hoist (return . runIdentity)
292+-- > generally = Fold.hoist (return . runIdentity)
274293--
275294-- /Pre-release/
276295generally :: Monad m => Fold Identity a b -> Fold m a b
@@ -305,7 +324,7 @@ mapM = rmapM
305324-- >>> Stream.fold fld (Stream.enumerateFromTo 1 10)
306325-- [2,4,6,8,10]
307326--
308−-- /Pre-release/
327+-- @since 0.8.0
309328{-# INLINE mapMaybe #-}
310329mapMaybe :: (Monad m) => (a -> Maybe b) -> Fold m b r -> Fold m a r
311330mapMaybe f = map f . filter isJust . map fromJust
@@ -318,7 +337,7 @@ mapMaybe f = map f . filter isJust . map fromJust
318337--
319338-- | Apply a transformation on a 'Fold' using a 'Pipe'.
320339--
321−-- @since 0.7.0
340+-- /Pre-release/
322341{-# INLINE transform #-}
323342transform :: Monad m => Pipe m a b -> Fold m b c -> Fold m a c
324343transform (Pipe pstep1 pstep2 pinitial) (Fold fstep finitial fextract) =
@@ -355,23 +374,6 @@ transform (Pipe pstep1 pstep2 pinitial) (Fold fstep finitial fextract) =
355374
356375 extract (Tuple' _ fs) = fextract fs
357376
358−------------------------------------------------------------------------------
359−-- Utilities
360−------------------------------------------------------------------------------
361−
362−-- | @_Fold1 step@ returns a new 'Fold' using just a step function that has the
363−-- same type for the accumulator and the element. The result type is the
364−-- accumulator type wrapped in 'Maybe'. The initial accumulator is retrieved
365−-- from the 'Foldable', the result is 'None' for empty containers.
366−{-# INLINABLE _Fold1 #-}
367−_Fold1 :: Monad m => (a -> a -> a) -> Fold m a (Maybe a)
368−_Fold1 step = fmap toMaybe $ mkFoldl step_ Nothing'
369−
370− where
371−
372− step_ Nothing' a = Just' a
373− step_ (Just' x) a = Just' $ step x a
374−
375377------------------------------------------------------------------------------
376378-- Left folds
377379------------------------------------------------------------------------------
@@ -382,11 +384,13 @@ _Fold1 step = fmap toMaybe $ mkFoldl step_ Nothing'
382384
383385-- |
384386-- > drainBy f = lmapM f drain
385−-- > drainBy = FL.foldMapM (void . f)
387+-- > drainBy = Fold.foldMapM (void . f)
386388--
387389-- Drain all input after passing it through a monadic function. This is the
388390-- dual of mapM_ on stream producers.
389391--
392+-- See also: "Streamly.Prelude.mapM_"
393+--
390394-- @since 0.7.0
391395{-# INLINABLE drainBy #-}
392396drainBy :: Monad m => (a -> m b) -> Fold m a ()
@@ -401,12 +405,12 @@ drainBy2 f = Fold2 (const (void . f)) (\_ -> return ()) return
401405
402406-- | Extract the last element of the input stream, if any.
403407--
404−-- > last = fmap getLast $ FL.foldMap (Last . Just)
408+-- > last = fmap getLast $ Fold.foldMap (Last . Just)
405409--
406410-- @since 0.7.0
407411{-# INLINABLE last #-}
408412last :: Monad m => Fold m a (Maybe a)
409−last = _Fold1 (\_ x -> x)
413+last = mkFoldl1 (\_ x -> x)
410414
411415------------------------------------------------------------------------------
412416-- To Summary
@@ -416,14 +420,14 @@ last = _Fold1 (\_ x -> x)
416420--
417421-- > genericLength = fmap getSum $ foldMap (Sum . const 1)
418422--
419−-- @since 0.7.0
423+-- /Pre-release/
420424{-# INLINE genericLength #-}
421425genericLength :: (Monad m, Num b) => Fold m a b
422426genericLength = mkFoldl (\n _ -> n + 1) 0
423427
424428-- | Determine the length of the input stream.
425429--
426−-- > length = fmap getSum $ foldMap (Sum . const 1)
430+-- > length = fmap getSum $ Fold.foldMap (Sum . const 1)
427431--
428432-- @since 0.7.0
429433{-# INLINE length #-}
@@ -434,7 +438,7 @@ length = genericLength
434438-- identity (@0@) when the stream is empty. Note that this is not numerically
435439-- stable for floating point numbers.
436440--
437−-- > sum = fmap getSum $ FL.foldMap Sum
441+-- > sum = fmap getSum $ Fold.foldMap Sum
438442--
439443-- @since 0.7.0
440444{-# INLINE sum #-}
@@ -445,7 +449,7 @@ sum = mkFoldl (+) 0
445449-- multiplicative identity (@1@) when the stream is empty. The fold terminates
446450-- when it encounters (@0@) in its input.
447451--
448−-- > product = fmap getProduct $ FL.foldMap Product
452+-- Compare with @Fold.foldMap Product@.
449453--
450454-- @since 0.7.0
451455-- /Since 0.8.0 (Added 'Eq' constraint)/
@@ -470,7 +474,7 @@ product = mkFold_ step (Partial 1)
470474-- @since 0.7.0
471475{-# INLINE maximumBy #-}
472476maximumBy :: Monad m => (a -> a -> Ordering) -> Fold m a (Maybe a)
473−maximumBy cmp = _Fold1 max'
477+maximumBy cmp = mkFoldl1 max'
474478
475479 where
476480
@@ -481,24 +485,24 @@ maximumBy cmp = _Fold1 max'
481485
482486-- |
483487-- @
484−-- maximum = 'maximumBy' compare
488+-- maximum = Fold.maximumBy compare
485489-- @
486490--
487491-- Determine the maximum element in a stream.
488492--
489−-- Compare with @FL.foldMap Max@.
493+-- Compare with @Fold.foldMap Max@.
490494--
491495-- @since 0.7.0
492496{-# INLINE maximum #-}
493497maximum :: (Monad m, Ord a) => Fold m a (Maybe a)
494−maximum = _Fold1 max
498+maximum = mkFoldl1 max
495499
496500-- | Computes the minimum element with respect to the given comparison function
497501--
498502-- @since 0.7.0
499503{-# INLINE minimumBy #-}
500504minimumBy :: Monad m => (a -> a -> Ordering) -> Fold m a (Maybe a)
501−minimumBy cmp = _Fold1 min'
505+minimumBy cmp = mkFoldl1 min'
502506
503507 where
504508
@@ -514,12 +518,12 @@ minimumBy cmp = _Fold1 min'
514518-- minimum = 'minimumBy' compare
515519-- @
516520--
517−-- Compare with @FL.foldMap Min@.
521+-- Compare with @Fold.foldMap Min@.
518522--
519523-- @since 0.7.0
520524{-# INLINE minimum #-}
521525minimum :: (Monad m, Ord a) => Fold m a (Maybe a)
522−minimum = _Fold1 min
526+minimum = mkFoldl1 min
523527
524528------------------------------------------------------------------------------
525529-- To Summary (Statistical)
@@ -603,7 +607,7 @@ defaultSalt = -2578643520546668380
603607
604608-- | Compute an 'Int' sized polynomial rolling hash of a stream.
605609--
606−-- > rollingHash = rollingHashWithSalt defaultSalt
610+-- > rollingHash = Fold.rollingHashWithSalt defaultSalt
607611--
608612-- /Pre-release/
609613{-# INLINABLE rollingHash #-}
@@ -613,7 +617,7 @@ rollingHash = rollingHashWithSalt defaultSalt
613617-- | Compute an 'Int' sized polynomial rolling hash of the first n elements of
614618-- a stream.
615619--
616−-- > rollingHashFirstN = take n rollingHash
620+-- > rollingHashFirstN = Fold.take n Fold.rollingHash
617621--
618622-- /Pre-release/
619623{-# INLINABLE rollingHashFirstN #-}
@@ -626,10 +630,14 @@ rollingHashFirstN n = take n rollingHash
626630
627631-- | Append the elements of an input stream to a provided starting value.
628632--
629−-- > S.fold (FL.sconcat 10) (S.map Sum $ S.enumerateFromTo 1 10)
633+-- >>> Stream.fold (Fold.sconcat 10) (Stream.map Data.Monoid.Sum $ Stream.enumerateFromTo 1 10)
634+-- Sum {getSum = 65}
630635--
631−-- /Pre-release/
636+-- @
637+-- sconcat = Fold.mkFoldl (<>)
638+-- @
632639--
640+-- @since 0.8.0
633641{-# INLINE sconcat #-}
634642sconcat :: (Monad m, Semigroup a) => a -> Fold m a a
635643sconcat = mkFoldl (<>)
@@ -637,7 +645,10 @@ sconcat = mkFoldl (<>)
637645-- | Fold an input stream consisting of monoidal elements using 'mappend'
638646-- and 'mempty'.
639647--
640−-- > S.fold FL.mconcat (S.map Sum $ S.enumerateFromTo 1 10)
648+-- >>> Stream.fold Fold.mconcat (Stream.map Data.Monoid.Sum $ Stream.enumerateFromTo 1 10)
649+-- Sum {getSum = 55}
650+--
651+-- > mconcat = Fold.sconcat mempty
641652--
642653-- @since 0.7.0
643654{-# INLINE mconcat #-}
@@ -650,12 +661,13 @@ mconcat ::
650661mconcat = sconcat mempty
651662
652663-- |
653−-- > foldMap f = map f mconcat
664+-- > foldMap f = Fold.lmap f Fold.mconcat
654665--
655666-- Make a fold from a pure function that folds the output of the function
656667-- using 'mappend' and 'mempty'.
657668--
658−-- > S.fold (FL.foldMap Sum) $ S.enumerateFromTo 1 10
669+-- >>> Stream.fold (Fold.foldMap Data.Monoid.Sum) $ Stream.enumerateFromTo 1 10
670+-- Sum {getSum = 55}
659671--
660672-- @since 0.7.0
661673{-# INLINABLE foldMap #-}
@@ -664,15 +676,16 @@ foldMap :: (Monad m, Monoid b
664676 , Semigroup b
665677#endif
666678 ) => (a -> b) -> Fold m a b
667−foldMap f = map f mconcat
679+foldMap f = lmap f mconcat
668680
669681-- |
670−-- > foldMapM f = lmapM f mconcat
682+-- > foldMapM f = Fold.lmapM f Fold.mconcat
671683--
672684-- Make a fold from a monadic function that folds the output of the function
673685-- using 'mappend' and 'mempty'.
674686--
675−-- > S.fold (FL.foldMapM (return . Sum)) $ S.enumerateFromTo 1 10
687+-- >>> Stream.fold (Fold.foldMapM (return . Data.Monoid.Sum)) $ Stream.enumerateFromTo 1 10
688+-- Sum {getSum = 55}
676689--
677690-- @since 0.7.0
678691{-# INLINABLE foldMapM #-}
@@ -695,10 +708,12 @@ foldMapM act = mkFoldlM step (pure mempty)
695708
696709-- | Buffers the input stream to a list in the reverse order of the input.
697710--
711+-- > toListRev = Fold.mkFoldl (flip (:)) []
712+--
698713-- /Warning!/ working on large lists accumulated as buffers in memory could be
699714-- very inefficient, consider using "Streamly.Array" instead.
700715--
701−-- @since 0.7.0
716+-- @since 0.8.0
702717
703718-- xn : ... : x2 : x1 : []
704719{-# INLINABLE toListRev #-}
@@ -711,6 +726,10 @@ toListRev = mkFoldl (flip (:)) []
711726
712727-- | A fold that drains the first n elements of its input, running the effects
713728-- and discarding the results.
729+--
730+-- > drainN n = Fold.take n Fold.drain
731+--
732+-- /Pre-release/
714733{-# INLINABLE drainN #-}
715734drainN :: Monad m => Int -> Fold m a ()
716735drainN n = take n drain
@@ -735,6 +754,8 @@ genericIndex i = mkFold step (Partial 0) (const Nothing)
735754
736755-- | Lookup the element at the given index.
737756--
757+-- See also: "Streamly.Prelude.!!"
758+--
738759-- @since 0.7.0
739760{-# INLINABLE index #-}
740761index :: Monad m => Int -> Fold m a (Maybe a)
@@ -742,8 +763,6 @@ index = genericIndex
742763
743764-- | Extract the first element of the stream, if any.
744765--
745−-- > head = fmap getFirst $ FL.foldMap (First . Just)
746−--
747766-- @since 0.7.0
748767{-# INLINABLE head #-}
749768head :: Monad m => Fold m a (Maybe a)
@@ -751,11 +770,6 @@ head = mkFold_ (const (Done . Just)) (Partial Nothing)
751770
752771-- | Returns the first element that satisfies the given predicate.
753772--
754−-- @
755−-- find p = fmap getFirst $
756−-- FL.foldMap (\x -> First (if p x then Just x else Nothing))
757−-- @
758−--
759773-- @since 0.7.0
760774{-# INLINABLE find #-}
761775find :: Monad m => (a -> Bool) -> Fold m a (Maybe a)
@@ -771,7 +785,7 @@ find predicate = mkFold step (Partial ()) (const Nothing)
771785-- | In a stream of (key-value) pairs @(a, b)@, return the value @b@ of the
772786-- first pair where the key equals the given value @a@.
773787--
774−-- > lookup = snd <$> find ((==) . fst)
788+-- > lookup = snd <$> Fold.find ((==) . fst)
775789--
776790-- @since 0.7.0
777791{-# INLINABLE lookup #-}
@@ -801,7 +815,7 @@ findIndex predicate = mkFold step (Partial 0) (const Nothing)
801815
802816-- | Returns the first index where a given value is found in the stream.
803817--
804−-- > elemIndex a = findIndex (== a)
818+-- > elemIndex a = Fold.findIndex (== a)
805819--
806820-- @since 0.7.0
807821{-# INLINABLE elemIndex #-}
@@ -814,22 +828,20 @@ elemIndex a = findIndex (a ==)
814828
815829-- | Return 'True' if the input stream is empty.
816830--
817−-- > null = fmap isJust head
831+-- > null = fmap isJust Fold.head
818832--
819833-- @since 0.7.0
820834{-# INLINABLE null #-}
821835null :: Monad m => Fold m a Bool
822836null = mkFold (\() _ -> Done False) (Partial ()) (const True)
823837
824−--
825−-- > any p = map p or
826−-- > any p = fmap getAny . FL.foldMap (Any . p)
827−--
828838-- | Returns 'True' if any of the elements of a stream satisfies a predicate.
829839--
830840-- >>> Stream.fold (Fold.any (== 0)) $ Stream.fromList [1,0,1]
831841-- True
832842--
843+-- > any p = Fold.lmap p Fold.or
844+--
833845-- @since 0.7.0
834846{-# INLINE any #-}
835847any :: Monad m => (a -> Bool) -> Fold m a Bool
@@ -846,22 +858,20 @@ any predicate = mkFold_ step initial
846858
847859-- | Return 'True' if the given element is present in the stream.
848860--
849−-- > elem a = any (== a)
861+-- > elem a = Fold.any (== a)
850862--
851863-- @since 0.7.0
852864{-# INLINABLE elem #-}
853865elem :: (Eq a, Monad m) => a -> Fold m a Bool
854866elem a = any (a ==)
855867
856−--
857−-- > all p = map p and
858−-- > all p = fmap getAll . FL.foldMap (All . p)
859−--
860868-- | Returns 'True' if all elements of a stream satisfy a predicate.
861869--
862870-- >>> Stream.fold (Fold.all (== 0)) $ Stream.fromList [1,0,1]
863871-- False
864872--
873+-- > all p = Fold.lmap p Fold.and
874+--
865875-- @since 0.7.0
866876{-# INLINABLE all #-}
867877all :: Monad m => (a -> Bool) -> Fold m a Bool
@@ -878,7 +888,7 @@ all predicate = mkFold_ step initial
878888
879889-- | Returns 'True' if the given element is not present in the stream.
880890--
881−-- > notElem a = all (/= a)
891+-- > notElem a = Fold.all (/= a)
882892--
883893-- @since 0.7.0
884894{-# INLINABLE notElem #-}
@@ -887,8 +897,7 @@ notElem a = all (a /=)
887897
888898-- | Returns 'True' if all elements are 'True', 'False' otherwise
889899--
890−-- > and = all (== True)
891−-- > and = fmap getAll . FL.foldMap All
900+-- > and = Fold.all (== True)
892901--
893902-- @since 0.7.0
894903{-# INLINE and #-}
@@ -897,8 +906,7 @@ and = all (== True)
897906
898907-- | Returns 'True' if any element is 'True', 'False' otherwise
899908--
900−-- > or = any (== True)
901−-- > or = fmap getAny . FL.foldMap Any
909+-- > or = Fold.any (== True)
902910--
903911-- @since 0.7.0
904912{-# INLINE or #-}
@@ -917,8 +925,6 @@ or = any (== True)
917925-- Binary APIs
918926------------------------------------------------------------------------------
919927
920−-- XXX These would just be applicative compositions of terminating folds.
921−
922928-- | @splitAt n f1 f2@ composes folds @f1@ and @f2@ such that first @n@
923929-- elements of its input are consumed by fold @f1@ and the rest of the stream
924930-- is consumed by fold @f2@.
@@ -943,7 +949,7 @@ or = any (== True)
943949-- >>> splitAt_ 4 [1,2,3]
944950-- ([1,2,3],[])
945951--
946−-- > splitAt n f1 f2 = serialWith (,) (take n f1) f2
952+-- > splitAt n f1 f2 = Fold.serialWith (,) (Fold.take n f1) f2
947953--
948954-- /Internal/
949955
@@ -967,53 +973,22 @@ splitAt n fld = serialWith (,) (take n fld)
967973-- Note: Keep this consistent with S.splitOn. In fact we should eliminate
968974-- S.splitOn in favor of the fold.
969975--
970−-- | Consume the input until it encounters an infixed separator element (i.e.
971−-- when the supplied predicate succeeds), dropping the separator.
972−--
973−-- Repeated applications of 'takeEndBy_' splits the stream on separator
974−-- elements determined by the supplied predicate, separator is considered as
975−-- infixed between two segments, if one side of the separator is missing then
976−-- it is parsed as an empty stream. The supplied 'Fold' is applied on the
977−-- split segments. With '-' representing non-separator elements and '.' as
978−-- separator, repeated 'takeEndBy_' splits the stream as follows:
979−--
980−-- @
981−-- "--.--" => "--" "--"
982−-- "--." => "--" ""
983−-- ".--" => "" "--"
984−-- @
985−--
986−-- Repeated applications of @Fold.takeEndBy_ (== x)@ on the input stream gives us
987−-- an inverse of @Stream.intercalate (Stream.yield x)@
988−--
989−-- > Stream.splitOn pred f = Stream.foldMany (Fold.takeEndBy_ pred f)
990−--
991−-- Let's use the following definition for illustration:
992−--
993−-- >>> splitOn p = Stream.foldMany (Fold.takeEndBy_ pred Fold.toList)
994−-- >>> splitOn' p = Stream.toList . splitOn p . Stream.fromList
995−
996−-- >>> splitOn' (== '.') ""
997−-- [""]
998−--
999−-- >>> splitOn' (== '.') "."
1000−-- ["",""]
976+-- XXX Use Fold.many instead once it is fixed.
1001977--
1002−-- >>> splitOn' (== '.') ".a"
1003−-- ["","a"]
978+-- | Like 'takeEndBy' but drops the element on which the predicate succeeds.
1004979--
1005−-- >>> splitOn' (== '.') "a."
1006−-- ["a",""]
980+-- >>> Stream.fold (Fold.takeEndBy_ (== '\n') Fold.toList) $ Stream.fromList "hello\nthere\n"
981+-- "hello"
1007982--
1008−-- >>> splitOn' (== '.') "a.b"
1009−-- ["a","b"]
983+-- >>> Stream.toList $ Stream.foldMany (Fold.takeEndBy_ (== '\n') Fold.toList) $ Stream.fromList "hello\nthere\n"
984+-- ["hello","there"]
1010985--
1011−-- >>> splitOn' (== '.') "a..b"
1012−-- ["a","","b"]
986+-- > Stream.splitOnSuffix p f = Stream.foldMany (Fold.takeEndBy_ p f)
1013987--
1014−-- Stops - when the predicate succeeds.
988+-- See 'Streamly.Prelude.splitOnSuffix' for more details on splitting a
989+-- stream using 'takeEndBy_'.
1015990--
1016−-- /Pre-release/
991+-- @since 0.8.0
1017992{-# INLINE takeEndBy_ #-}
1018993takeEndBy_ :: Monad m => (a -> Bool) -> Fold m a b -> Fold m a b
1019994takeEndBy_ predicate (Fold fstep finitial fextract) =
@@ -1026,16 +1001,21 @@ takeEndBy_ predicate (Fold fstep finitial fextract) =
10261001 then fstep s a
10271002 else Done <$> fextract s
10281003
1029−-- | Collect stream elements until an element succeeds the predicate. Also take
1030−-- the element on which the predicate succeeded. The succeeding element is
1031−-- treated as a suffix separator which is kept in the output segement.
1004+-- | Take the input, stop when the predicate succeeds taking the succeeding
1005+-- element as well.
10321006--
1033−-- * Stops - when the predicate succeeds.
1007+-- >>> Stream.fold (Fold.takeEndBy (== '\n') Fold.toList) $ Stream.fromList "hello\nthere\n"
1008+-- "hello\n"
10341009--
1035−-- > Stream.splitWithSuffix pred f = Stream.foldMany (Fold.takeEndBy pred f)
1010+-- >>> Stream.toList $ Stream.foldMany (Fold.takeEndBy (== '\n') Fold.toList) $ Stream.fromList "hello\nthere\n"
1011+-- ["hello\n","there\n"]
10361012--
1037−-- /Pre-release/
1013+-- > Stream.splitWithSuffix p f = Stream.foldMany (Fold.takeEndBy p f)
10381014--
1015+-- See 'Streamly.Prelude.splitWithSuffix' for more details on splitting a
1016+-- stream using 'takeEndBy'.
1017+--
1018+-- @since 0.8.0
10391019{-# INLINE takeEndBy #-}
10401020takeEndBy :: Monad m => (a -> Bool) -> Fold m a b -> Fold m a b
10411021takeEndBy predicate (Fold fstep finitial fextract) =
@@ -1086,6 +1066,8 @@ breakOn pat f m = undefined
10861066-- >>> Stream.fold (Fold.tee Fold.sum Fold.length) (Stream.enumerateFromTo 1.0 100.0)
10871067-- (5050.0,100)
10881068--
1069+-- > tee = teeWith (,)
1070+--
10891071-- @since 0.7.0
10901072{-# INLINE tee #-}
10911073tee :: Monad m => Fold m a b -> Fold m a c -> Fold m a (b,c)
@@ -1110,6 +1092,8 @@ tee = teeWith (,)
11101092-- >>> Stream.fold (Fold.distribute [Fold.sum, Fold.length]) (Stream.enumerateFromTo 1 5)
11111093-- [15,5]
11121094--
1095+-- > distribute = Prelude.foldr (Fold.teeWith (:)) (Fold.yield [])
1096+--
11131097-- This is the consumer side dual of the producer side 'sequence' operation.
11141098--
11151099-- Stops when all the folds stop.
@@ -1171,7 +1155,7 @@ distribute = foldr (teeWith (:)) (yield [])
11711155--
11721156-- /See also: 'partitionByFstM' and 'partitionByMinM'./
11731157--
1174−-- @since 0.7.0
1158+-- /Pre-release/
11751159{-# INLINE partitionByM #-}
11761160partitionByM :: Monad m
11771161 => (a -> m (Either b c)) -> Fold m b x -> Fold m c y -> Fold m a (x, y)
@@ -1270,7 +1254,7 @@ partitionByMinM = undefined
12701254-- :}
12711255-- ("Even 50","Odd 50")
12721256--
1273−-- @since 0.7.0
1257+-- /Pre-release/
12741258{-# INLINE partitionBy #-}
12751259partitionBy :: Monad m
12761260 => (a -> Either b c) -> Fold m b x -> Fold m c y -> Fold m a (x, y)
@@ -1346,7 +1330,9 @@ demuxWith f kv = fmap fst $ demuxDefaultWith f kv drain
13461330-- :}
13471331-- fromList [("PRODUCT",8),("SUM",4)]
13481332--
1349−-- @since 0.7.0
1333+-- > demux = demuxWith id
1334+--
1335+-- /Pre-release/
13501336{-# INLINE demux #-}
13511337demux :: (Monad m, Ord k)
13521338 => Map k (Fold m a b) -> Fold m (k, a) (Map k b)
@@ -1476,6 +1462,10 @@ demuxDefaultWith f kv (Fold dstep dinitial dextract) =
14761462 b <- dextract dacc
14771463 return (doneMap, b)
14781464
1465+-- |
1466+-- > demuxDefault = demuxDefaultWith id
1467+--
1468+-- /Pre-release/
14791469{-# INLINE demuxDefault #-}
14801470demuxDefault :: (Monad m, Ord k)
14811471 => Map k (Fold m a b) -> Fold m (k, a) b -> Fold m (k, a) (Map k b, b)
@@ -1555,12 +1545,11 @@ classifyWith f (Fold step1 initial1 extract1) =
15551545-- :}
15561546-- fromList [("ONE",[1.0,1.1]),("TWO",[2.0,2.2])]
15571547--
1558−-- @since 0.7.0
1559−--
15601548-- Same as:
15611549--
1562−-- > classify fld = classifyWith fst (map snd fld)
1550+-- > classify fld = Fold.classifyWith fst (map snd fld)
15631551--
1552+-- /Pre-release/
15641553{-# INLINE classify #-}
15651554classify :: (Monad m, Ord k) => Fold m a b -> Fold m (k, a) (Map k b)
15661555classify fld = classifyWith fst (map snd fld)
@@ -1571,9 +1560,9 @@ classify fld = classifyWith fst (map snd fld)
15711560
15721561-- | Like 'unzipWith' but with a monadic splitter function.
15731562--
1574−-- -- @unzipWithM k f1 f2 = lmapM k (unzip f1 f2)@
1563+-- @unzipWithM k f1 f2 = lmapM k (unzip f1 f2)@
15751564--
1576−-- @since 0.7.0
1565+-- /Pre-release/
15771566{-# INLINE unzipWithM #-}
15781567unzipWithM :: Monad m
15791568 => (a -> m (b,c)) -> Fold m b x -> Fold m c y -> Fold m a (x,y)
@@ -1653,11 +1642,11 @@ unzipWithMinM = undefined
16531642-- | Split elements in the input stream into two parts using a pure splitter
16541643-- function, direct each part to a different fold and zip the results.
16551644--
1656−-- @unzipWith f fld1 fld2 = map f (unzip fld1 fld2)@
1645+-- @unzipWith f fld1 fld2 = Fold.lmap f (Fold.unzip fld1 fld2)@
16571646--
16581647-- This fold terminates when both the input folds terminate.
16591648--
1660−-- @since 0.7.0
1649+-- /Pre-release/
16611650{-# INLINE unzipWith #-}
16621651unzipWith :: Monad m
16631652 => (a -> (b,c)) -> Fold m b x -> Fold m c y -> Fold m a (x,y)
@@ -1674,6 +1663,8 @@ unzipWith f = unzipWithM (return . f)
16741663--
16751664-- @
16761665--
1666+-- > unzip = Fold.unzipWith id
1667+--
16771668-- This is the consumer side dual of the producer side 'zip' operation.
16781669--
16791670-- @since 0.7.0
@@ -1773,6 +1764,8 @@ chunksBetween _low _high _f1 _f2 = undefined
17731764-- /Warning!/ working on large streams accumulated as buffers in memory could
17741765-- be very inefficient, consider using "Streamly.Data.Array" instead.
17751766--
1767+-- > toStream = mkFoldr K.cons K.nil
1768+--
17761769-- /Pre-release/
17771770{-# INLINE toStream #-}
17781771toStream :: Monad m => Fold m a (SerialT Identity a)
@@ -1784,6 +1777,8 @@ toStream = mkFoldr K.cons K.nil
17841777-- | Buffers the input stream to a pure stream in the reverse order of the
17851778-- input.
17861779--
1780+-- > toStreamRev = mkFoldl (flip K.cons) K.nil
1781+--
17871782-- /Warning!/ working on large streams accumulated as buffers in memory could
17881783-- be very inefficient, consider using "Streamly.Data.Array" instead.
17891784--