on master help sign in
Add foldOn
f393b15Harendra Kumar
src/Streamly/Internal/Data/Stream/IsStream/Common.hs+15
@@ -22,6 +22,7 @@ module Streamly.Internal.Data.Stream.IsStream.Common
22 , relTimesWith
22 , relTimesWith
23
23
24 -- * Elimination
24 -- * Elimination
25+ , foldOn
25 , fold
26 , fold
26 , fold_
27 , fold_
27
28
@@ -104,6 +105,7 @@ import Prelude hiding (take, takeWhile, drop, reverse, concatMap, map, zipWith)
104-- >>> import Streamly.Internal.Data.Stream.IsStream as Stream
105-- >>> import Streamly.Internal.Data.Stream.IsStream as Stream
105-- >>> import qualified Streamly.Data.Array.Foreign as Array
106-- >>> import qualified Streamly.Data.Array.Foreign as Array
106-- >>> import qualified Streamly.Data.Fold as Fold
107-- >>> import qualified Streamly.Data.Fold as Fold
108+-- >>> import qualified Streamly.Internal.Data.Fold as Fold
107-- >>> import qualified Streamly.Data.Unfold as Unfold
109-- >>> import qualified Streamly.Data.Unfold as Unfold
108
110
109------------------------------------------------------------------------------
111------------------------------------------------------------------------------
@@ -266,6 +268,19 @@ relTimesWith = fmap snd . timesWith
266-- Elimination - Running a Fold
268-- Elimination - Running a Fold
267------------------------------------------------------------------------------
269------------------------------------------------------------------------------
268
270
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+
269-- | Fold a stream using the supplied left 'Fold' and reducing the resulting
284-- | Fold a stream using the supplied left 'Fold' and reducing the resulting
270-- expression strictly at each step. The behavior is similar to 'foldl''. A
285-- expression strictly at each step. The behavior is similar to 'foldl''. A
271-- 'Fold' can terminate early without consuming the full stream. See the
286-- '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
24 -- See "Streamly.Internal.Data.Fold".
24 -- See "Streamly.Internal.Data.Fold".
25 fold
25 fold
26 , fold_
26 , fold_
27+ , foldOn
27
28
28 -- * Running a 'Parser'
29 -- * Running a 'Parser'
29 -- "Streamly.Internal.Data.Parser".
30 -- "Streamly.Internal.Data.Parser".
@@ -161,7 +162,7 @@ import Streamly.Internal.Control.Concurrent (MonadAsync)
161import Streamly.Internal.Data.Parser (Parser (..))
162import Streamly.Internal.Data.Parser (Parser (..))
162import Streamly.Internal.Data.SVar (defState)
163import Streamly.Internal.Data.SVar (defState)
163import Streamly.Internal.Data.Stream.IsStream.Common
164import Streamly.Internal.Data.Stream.IsStream.Common
164− ( fold, fold_, drop, findIndices, reverse, splitOnSeq, take
165+ ( fold, fold_, foldOn, drop, findIndices, reverse, splitOnSeq, take
165 , takeWhile, mkParallel)
166 , takeWhile, mkParallel)
166import Streamly.Internal.Data.Stream.IsStream.Type
167import Streamly.Internal.Data.Stream.IsStream.Type
167 (IsStream, toStreamS, fromStreamD, toStreamD)
168 (IsStream, toStreamS, fromStreamD, toStreamD)
src/Streamly/Internal/Data/Stream/StreamD/Type.hs+26
@@ -43,6 +43,7 @@ module Streamly.Internal.Data.Stream.StreamD.Type
43 -- * Running a 'Fold'
43 -- * Running a 'Fold'
44 , fold
44 , fold
45 , fold_
45 , fold_
46+ , foldOn
46
47
47 -- * Right Folds
48 -- * Right Folds
48 , foldrT
49 , foldrT
@@ -294,6 +295,31 @@ fold_ (Fold fstep begin done) (Stream step state) = do
294 b <- done fs
295 b <- done fs
295 return $! (b, Stream (\ _ _ -> return Stop) ())
296 return $! (b, Stream (\ _ _ -> return Stop) ())
296
297
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+
297------------------------------------------------------------------------------
323------------------------------------------------------------------------------
298-- Right Folds
324-- Right Folds
299------------------------------------------------------------------------------
325------------------------------------------------------------------------------