on master help sign in
Add foldOn
commitf393b15fc5310a0bde807919c2b70064f63ea3a0 authorHarendra Kumar <harendra@composewell.com> dateSat 16 Oct 2021, 00:15 (5 years ago) parenta096f77
3 files changed+43−1
src/Streamly/Internal/Data/Stream/IsStream/Common.hs+15 src/Streamly/Internal/Data/Stream/IsStream/Eliminate.hs+2−1 src/Streamly/Internal/Data/Stream/StreamD/Type.hs+26
src/Streamly/Internal/Data/Stream/IsStream/Common.hs+15
@@ -22,6 +22,7 @@ module Streamly.Internal.Data.Stream.IsStream.Common
2222 , relTimesWith
2323
2424 -- * Elimination
25+ , foldOn
2526 , fold
2627 , fold_
2728
@@ -104,6 +105,7 @@ import Prelude hiding (take, takeWhile, drop, reverse, concatMap, map, zipWith)
104105-- >>> import Streamly.Internal.Data.Stream.IsStream as Stream
105106-- >>> import qualified Streamly.Data.Array.Foreign as Array
106107-- >>> import qualified Streamly.Data.Fold as Fold
108+-- >>> import qualified Streamly.Internal.Data.Fold as Fold
107109-- >>> import qualified Streamly.Data.Unfold as Unfold
108110
109111------------------------------------------------------------------------------
@@ -266,6 +268,19 @@ relTimesWith = fmap snd . timesWith
266268-- Elimination - Running a Fold
267269------------------------------------------------------------------------------
268270
271+-- | We can create higher order folds using 'foldOn'. We can fold a number of
272+-- streams to a given fold efficiently with full stream fusion. For example, to
273+-- fold a list of streams on the same sum fold:
274+--
275+-- >>> concatFold = Prelude.foldl Stream.foldOn Fold.sum
276+--
277+-- >>> fold f = Fold.finish . Stream.foldOn f
278+--
279+-- /Internal/
280+{-# INLINE foldOn #-}
281+foldOn :: Monad m => Fold m a b -> SerialT m a -> Fold m a b
282+foldOn f s = D.foldOn f $ IsStream.toStreamD s
283+
269284-- | Fold a stream using the supplied left 'Fold' and reducing the resulting
270285-- expression strictly at each step. The behavior is similar to 'foldl''. A
271286-- 'Fold' can terminate early without consuming the full stream. See the
src/Streamly/Internal/Data/Stream/IsStream/Eliminate.hs+2−1
@@ -24,6 +24,7 @@ module Streamly.Internal.Data.Stream.IsStream.Eliminate
2424 -- See "Streamly.Internal.Data.Fold".
2525 fold
2626 , fold_
27+ , foldOn
2728
2829 -- * Running a 'Parser'
2930 -- "Streamly.Internal.Data.Parser".
@@ -161,7 +162,7 @@ import Streamly.Internal.Control.Concurrent (MonadAsync)
161162import Streamly.Internal.Data.Parser (Parser (..))
162163import Streamly.Internal.Data.SVar (defState)
163164import Streamly.Internal.Data.Stream.IsStream.Common
164− ( fold, fold_, drop, findIndices, reverse, splitOnSeq, take
165+ ( fold, fold_, foldOn, drop, findIndices, reverse, splitOnSeq, take
165166 , takeWhile, mkParallel)
166167import Streamly.Internal.Data.Stream.IsStream.Type
167168 (IsStream, toStreamS, fromStreamD, toStreamD)
src/Streamly/Internal/Data/Stream/StreamD/Type.hs+26
@@ -43,6 +43,7 @@ module Streamly.Internal.Data.Stream.StreamD.Type
4343 -- * Running a 'Fold'
4444 , fold
4545 , fold_
46+ , foldOn
4647
4748 -- * Right Folds
4849 , foldrT
@@ -294,6 +295,31 @@ fold_ (Fold fstep begin done) (Stream step state) = do
294295 b <- done fs
295296 return $! (b, Stream (\ _ _ -> return Stop) ())
296297
298+{-# INLINE_NORMAL foldOn #-}
299+foldOn :: Monad m => Fold m a b -> Stream m a -> Fold m a b
300+foldOn (Fold fstep finitial fextract) (Stream sstep state) =
301+ Fold fstep initial fextract
302+
303+ where
304+
305+ initial = do
306+ res <- finitial
307+ case res of
308+ FL.Partial fs -> go SPEC fs state
309+ FL.Done fb -> return $ FL.Done fb
310+
311+ {-# INLINE go #-}
312+ go !_ !fs st = do
313+ r <- sstep defState st
314+ case r of
315+ Yield x s -> do
316+ res <- fstep fs x
317+ case res of
318+ FL.Done b -> return $ FL.Done b
319+ FL.Partial fs1 -> go SPEC fs1 s
320+ Skip s -> go SPEC fs s
321+ Stop -> return $ FL.Partial fs
322+
297323------------------------------------------------------------------------------
298324-- Right Folds
299325------------------------------------------------------------------------------