on master help sign in
Fix foldMany documentation and behavior
f593770Harendra Kumar
core/src/Streamly/Internal/Data/Stream/Bottom.hs+25−8
@@ -211,9 +211,10 @@ build f = fold (Fold.duplicate f)
211-- Definitions:
211-- Definitions:
212--
212--
213-- >>> fold f = fmap fst . Stream.foldBreak f
213-- >>> fold f = fmap fst . Stream.foldBreak f
214+-- >>> fold f = Stream.parse (Parser.fromFold f)
215+-- >>> fold f = Stream.fold Fold.one . Stream.foldManyPost f
214-- >>> fold f = Fold.extractM . Stream.buildl f
216-- >>> fold f = Fold.extractM . Stream.buildl f
215-- >>> fold f = Fold.extractM <=< Stream.build f
217-- >>> fold f = Fold.extractM <=< Stream.build f
216−-- >>> fold f = Stream.parse (Parser.fromFold f)
217--
218--
218-- Example:
219-- Example:
219--
220--
@@ -594,16 +595,32 @@ concatMap f m = fromStreamD $ D.concatMap (toStreamD . f) (toStreamD m)
594concatM :: Monad m => m (Stream m a) -> Stream m a
595concatM :: Monad m => m (Stream m a) -> Stream m a
595concatM generator = concatMapM (\() -> generator) (fromPure ())
596concatM generator = concatMapM (\() -> generator) (fromPure ())
596
597
597−-- | Like 'foldMany' but appends empty fold output if the fold and stream
598+-- XXX Need a more intuitive name, and need to reconcile the names
598−-- termination aligns:
599+-- foldMany/fold/parse/parseMany/parseManyPost etc.
600+
601+-- | Like 'foldMany' but evaluates the fold before the stream, and yields its
602+-- output even if the stream is empty, therefore, always results in a non-empty
603+-- output even on an empty stream (default result of the fold).
604+--
605+-- Example, empty stream:
599--
606--
600-- >>> f = Fold.take 2 Fold.sum
607-- >>> f = Fold.take 2 Fold.sum
601−-- >>> Stream.fold Fold.toList $ Stream.foldManyPost f $ Stream.fromList []
608+-- >>> fmany = Stream.fold Fold.toList . Stream.foldManyPost f
609+-- >>> fmany $ Stream.fromList []
602-- [0]
610-- [0]
603−-- >>> Stream.fold Fold.toList $ Stream.foldManyPost f $ Stream.fromList [1..9]
611+--
612+-- Example, last fold empty:
613+--
614+-- >>> fmany $ Stream.fromList [1..4]
604−-- [3,7,11,15,9]
615+-- [3,7,0]
605−-- >>> Stream.fold Fold.toList $ Stream.foldManyPost f $ Stream.fromList [1..10]
616+--
606−-- [3,7,11,15,19,0]
617+-- Example, last fold non-empty:
618+--
619+-- >>> fmany $ Stream.fromList [1..5]
620+-- [3,7,5]
621+--
622+-- Note that using a closed fold e.g. @Fold.take 0@, would result in an
623+-- infinite stream without consuming the input.
607--
624--
608-- /Pre-release/
625-- /Pre-release/
609--
626--
core/src/Streamly/Internal/Data/Stream/Reduce.hs+19−17
@@ -125,31 +125,33 @@ dropSuffix = error "Not implemented yet!"
125-- Folding
125-- Folding
126------------------------------------------------------------------------------
126------------------------------------------------------------------------------
127
127
128−-- Splitting operations that take a predicate and a Fold can be
128+-- | Apply a 'Fold' repeatedly on a stream and emit the results in the
129−-- expressed using parseMany. Operations like chunksOf, intervalsOf, split*,
129+-- output stream. Unlike 'foldManyPost' it evaluates the fold after the stream,
130−-- can be expressed using parseMany when used with an appropriate Parser.
130+-- therefore, an empty input stream results in an empty output stream.
131--
131--
132−-- XXX We need takeGE/takeBetween to implement "some" using "many".
132+-- Definition:
133−
134−-- | Apply a 'Fold' repeatedly on a stream and emit the fold outputs in the
135−-- output stream.
136--
133--
137−-- To sum every two contiguous elements in a stream:
134+-- >>> foldMany f = Stream.parseMany (Parser.fromFold f)
135+--
136+-- Example, empty stream:
138--
137--
139-- >>> f = Fold.take 2 Fold.sum
138-- >>> f = Fold.take 2 Fold.sum
140−-- >>> Stream.fold Fold.toList $ Stream.foldMany f $ Stream.fromList [1..10]
139+-- >>> fmany = Stream.fold Fold.toList . Stream.foldMany f
140+-- >>> fmany $ Stream.fromList []
141−-- [3,7,11,15,19]
141+-- []
142--
142--
143−-- On an empty stream the output is empty:
143+-- Example, last fold empty:
144--
144--
145−-- >>> Stream.fold Fold.toList $ Stream.foldMany f $ Stream.fromList []
145+-- >>> fmany $ Stream.fromList [1..4]
146−-- []
146+-- [3,7]
147+--
148+-- Example, last fold non-empty:
147--
149--
148−-- Note @Stream.foldMany (Fold.take 0)@ would result in an infinite loop in a
150+-- >>> fmany $ Stream.fromList [1..5]
149−-- non-empty stream.
151+-- [3,7,5]
150--
152--
151−-- Note 'foldMany' on an empty stream results in an empty stream. Therefore,
153+-- Note that using a closed fold e.g. @Fold.take 0@, would result in an
152−-- @Stream.fold f@ is not the same as @Stream.head . Stream.foldMany f@.
154+-- infinite stream on a non-empty input stream.
153--
155--
154{-# INLINE foldMany #-}
156{-# INLINE foldMany #-}
155foldMany
157foldMany
core/src/Streamly/Internal/Data/Stream/StreamD/Type.hs+22−42
@@ -895,14 +895,7 @@ data FoldManyPost s fs b a
895 | FoldManyPostYield b (FoldManyPost s fs b a)
895 | FoldManyPostYield b (FoldManyPost s fs b a)
896 | FoldManyPostDone
896 | FoldManyPostDone
897
897
898−-- | Like foldMany but with the following differences:
898+-- | 'Streamly.Internal.Data.Stream.foldManyPost'.
899−--
900−-- * If the stream is empty the default value of the fold would still be
901−-- emitted in the output.
902−-- * At the end of the stream if the last application of the fold did not
903−-- receive any input it would still yield the default fold accumulator as the
904−-- last value.
905−--
906{-# INLINE_NORMAL foldManyPost #-}
899{-# INLINE_NORMAL foldManyPost #-}
907foldManyPost :: Monad m => Fold m a b -> Stream m a -> Stream m b
900foldManyPost :: Monad m => Fold m a b -> Stream m a -> Stream m b
908foldManyPost (Fold fstep initial extract) (Stream step state) =
901foldManyPost (Fold fstep initial extract) (Stream step state) =
@@ -941,23 +934,14 @@ foldManyPost (Fold fstep initial extract) (Stream step state) =
941{-# ANN type FoldMany Fuse #-}
934{-# ANN type FoldMany Fuse #-}
942data FoldMany s fs b a
935data FoldMany s fs b a
943 = FoldManyStart s
936 = FoldManyStart s
944− | FoldManyFirst fs s
937+ | FoldManyFirst a s
945 | FoldManyLoop s fs
938 | FoldManyLoop s fs
946 | FoldManyYield b (FoldMany s fs b a)
939 | FoldManyYield b (FoldMany s fs b a)
947 | FoldManyDone
940 | FoldManyDone
948
941
949-- XXX Nested foldMany does not fuse.
942-- XXX Nested foldMany does not fuse.
950−--
943+
951−-- | Apply a fold multiple times until the stream ends. If the stream is empty
944+-- | 'Streamly.Internal.Data.Stream.foldMany'.
952−-- the output would be empty.
953−--
954−-- @foldMany f = parseMany (fromFold f)@
955−--
956−-- A terminating fold may terminate even without accepting a single input. So
957−-- we run the fold's initial action before evaluating the stream. However, this
958−-- means that if later the stream does not yield anything we have to discard
959−-- the fold's initial result which could have generated an effect.
960−--
961{-# INLINE_NORMAL foldMany #-}
945{-# INLINE_NORMAL foldMany #-}
962foldMany :: Monad m => Fold m a b -> Stream m a -> Stream m b
946foldMany :: Monad m => Fold m a b -> Stream m a -> Stream m b
963foldMany (Fold fstep initial extract) (Stream step state) =
947foldMany (Fold fstep initial extract) (Stream step state) =
@@ -975,19 +959,17 @@ foldMany (Fold fstep initial extract) (Stream step state) =
975 FL.Partial ps -> FoldManyLoop s ps
959 FL.Partial ps -> FoldManyLoop s ps
976
960
977 {-# INLINE_LATE step' #-}
961 {-# INLINE_LATE step' #-}
978− step' _ (FoldManyStart st) = do
962+ step' gst (FoldManyStart st) = do
979− r <- initial
980− return
981− $ Skip
982− $ case r of
983− FL.Done b -> FoldManyYield b (FoldManyStart st)
984− FL.Partial fs -> FoldManyFirst fs st
985− step' gst (FoldManyFirst fs st) = do
986 r <- step (adaptState gst) st
963 r <- step (adaptState gst) st
987 case r of
964 case r of
988− Yield x s -> consume x s fs
965+ Yield x s -> return $ Skip (FoldManyFirst x s)
989− Skip s -> return $ Skip (FoldManyFirst fs s)
966+ Skip s -> return $ Skip (FoldManyStart s)
990 Stop -> return Stop
967 Stop -> return Stop
968+ step' _ (FoldManyFirst x st) = do
969+ r <- initial
970+ case r of
971+ FL.Done b -> return $ Skip $ FoldManyYield b (FoldManyFirst x st)
972+ FL.Partial fs -> consume x st fs
991 step' gst (FoldManyLoop st fs) = do
973 step' gst (FoldManyLoop st fs) = do
992 r <- step (adaptState gst) st
974 r <- step (adaptState gst) st
993 case r of
975 case r of
@@ -1003,8 +985,8 @@ foldMany (Fold fstep initial extract) (Stream step state) =
1003chunksOf :: Monad m => Int -> Fold m a b -> Stream m a -> Stream m b
985chunksOf :: Monad m => Int -> Fold m a b -> Stream m a -> Stream m b
1004chunksOf n f = foldMany (FL.take n f)
986chunksOf n f = foldMany (FL.take n f)
1005
987
1006−-- Keep the argument order consistent with consumeIterateM.
988+-- Keep the argument order consistent with refoldIterateM.
1007−--
989+
1008-- | Like 'foldMany' but for the 'Refold' type. The supplied action is used as
990-- | Like 'foldMany' but for the 'Refold' type. The supplied action is used as
1009-- the initial value for each refold.
991-- the initial value for each refold.
1010--
992--
@@ -1026,19 +1008,17 @@ refoldMany (Refold fstep inject extract) action (Stream step state) =
1026 FL.Partial ps -> FoldManyLoop s ps
1008 FL.Partial ps -> FoldManyLoop s ps
1027
1009
1028 {-# INLINE_LATE step' #-}
1010 {-# INLINE_LATE step' #-}
1029− step' _ (FoldManyStart st) = do
1011+ step' gst (FoldManyStart st) = do
1030− r <- action >>= inject
1031− return
1032− $ Skip
1033− $ case r of
1034− FL.Done b -> FoldManyYield b (FoldManyStart st)
1035− FL.Partial fs -> FoldManyFirst fs st
1036− step' gst (FoldManyFirst fs st) = do
1037 r <- step (adaptState gst) st
1012 r <- step (adaptState gst) st
1038 case r of
1013 case r of
1039− Yield x s -> consume x s fs
1014+ Yield x s -> return $ Skip (FoldManyFirst x s)
1040− Skip s -> return $ Skip (FoldManyFirst fs s)
1015+ Skip s -> return $ Skip (FoldManyStart s)
1041 Stop -> return Stop
1016 Stop -> return Stop
1017+ step' _ (FoldManyFirst x st) = do
1018+ r <- action >>= inject
1019+ case r of
1020+ FL.Done b -> return $ Skip $ FoldManyYield b (FoldManyFirst x st)
1021+ FL.Partial fs -> consume x st fs
1042 step' gst (FoldManyLoop st fs) = do
1022 step' gst (FoldManyLoop st fs) = do
1043 r <- step (adaptState gst) st
1023 r <- step (adaptState gst) st
1044 case r of
1024 case r of