@@ -209,6 +209,7 @@ module Streamly.Internal.Data.Fold.Type
209209 -- * Folds
210210 , fromPure
211211 , fromEffect
212+ , fromConsumer
212213 , drain
213214 , toList
214215 , toStreamK
@@ -248,6 +249,8 @@ module Streamly.Internal.Data.Fold.Type
248249 , ManyState
249250 , many
250251 , manyPost
252+ , consumeMany
253+ , consumeMany1
251254 , chunksOf
252255
253256 -- ** Nesting
@@ -258,10 +261,6 @@ module Streamly.Internal.Data.Fold.Type
258261 , snoc
259262 , duplicate
260263 , finish
261−
262− -- * Consumer
263− , simplify
264− , chunksOf2
265264 )
266265where
267266
@@ -271,7 +270,7 @@ import Data.Maybe (isJust, fromJust)
271270import Fusion.Plugin.Types (Fuse(..))
272271import Streamly.Internal.Data.Fold.Step (Step(..), mapMStep, chainStepM)
273272import Streamly.Internal.Data.Maybe.Strict (Maybe'(..), toMaybe)
274−import Streamly.Internal.Data.Tuple.Strict (Tuple'(..), Tuple3'(..))
273+import Streamly.Internal.Data.Tuple.Strict (Tuple'(..))
275274import Streamly.Internal.Data.Consumer.Type (Consumer(..))
276275
277276import qualified Streamly.Internal.Data.Stream.StreamK.Type as K
@@ -505,18 +504,18 @@ mkFoldM_ :: Monad m => (b -> a -> m (Step b b)) -> m (Step b b) -> Fold m a b
505504mkFoldM_ step initial = mkFoldM step initial return
506505
507506------------------------------------------------------------------------------
508−-- Fold2
507+-- Consumer
509508------------------------------------------------------------------------------
510509
511510-- This is similar to how we run an Unfold to generate a Stream. A Fold is like
512511-- a Stream and a Fold2 is like an Unfold.
513512--
514−-- | Convert more general type 'Fold2' into a simpler type 'Fold'
513+-- | Make a fold from a consumer.
515514--
516515-- /Internal/
517−simplify :: Functor m => Consumer m c a b -> c -> Fold m a b
518−simplify (Consumer step inject extract) c =
519− Fold (\x a -> Partial <$> step x a) (Partial <$> inject c) extract
516+fromConsumer :: Consumer m c a b -> c -> Fold m a b
517+fromConsumer (Consumer step inject extract) c =
518+ Fold step (inject c) extract
520519
521520------------------------------------------------------------------------------
522521-- Basic Folds
@@ -1312,32 +1311,102 @@ manyPost (Fold sstep sinitial sextract) (Fold cstep cinitial cextract) =
13121311chunksOf :: Monad m => Int -> Fold m a b -> Fold m b c -> Fold m a c
13131312chunksOf n split = many (take n split)
13141313
1315−-- |
1314+-- | Like 'many' but uses a 'Consumer' for collecting.
1315+--
1316+{-# INLINE consumeMany #-}
1317+consumeMany :: Monad m => Fold m a b -> Consumer m x b c -> Consumer m x a c
1318+consumeMany (Fold sstep sinitial sextract) (Consumer cstep cinject cextract) =
1319+ Consumer step inject extract
1320+
1321+ where
1322+
1323+ -- cs = collect state
1324+ -- ss = split state
1325+ -- cres = collect state result
1326+ -- sres = split state result
1327+ -- cb = collect done
1328+ -- sb = split done
1329+
1330+ -- Caution! There is mutual recursion here, inlining the right functions is
1331+ -- important.
1332+
1333+ {-# INLINE split #-}
1334+ split cs f sres =
1335+ case sres of
1336+ Partial ss -> return $ Partial $ Tuple' cs (f ss)
1337+ Done sb -> cstep cs sb >>= collect
1338+
1339+ {-# INLINE collect #-}
1340+ collect cres =
1341+ case cres of
1342+ Partial cs -> sinitial >>= split cs Left
1343+ Done cb -> return $ Done cb
1344+
1345+ inject x = cinject x >>= collect
1346+
1347+ {-# INLINE step_ #-}
1348+ step_ ss cs a = sstep ss a >>= split cs Right
1349+
1350+ {-# INLINE step #-}
1351+ step (Tuple' cs (Left ss)) a = step_ ss cs a
1352+ step (Tuple' cs (Right ss)) a = step_ ss cs a
1353+
1354+ -- Do not extract the split fold if no item was consumed.
1355+ extract (Tuple' cs (Left _)) = cextract cs
1356+ extract (Tuple' cs (Right ss )) = do
1357+ cres <- sextract ss >>= cstep cs
1358+ case cres of
1359+ Partial s -> cextract s
1360+ Done b -> return b
1361+
1362+{-# ANN type ConsumeManyState Fuse #-}
1363+data ConsumeManyState x cs ss = ConsumeMany x cs (Either ss ss)
1364+
1365+-- | Like 'many' but uses a 'Consumer' for splitting.
13161366--
13171367-- /Internal/
1318−{-# INLINE chunksOf2 #-}
1319−chunksOf2 :: Monad m =>
1320− Int -> Fold m a b -> Consumer m x b c -> Consumer m x a c
1321−chunksOf2 n (Fold step1 initial1 extract1) (Consumer step2 inject2 extract2) =
1322− Consumer step' inject' extract'
1368+{-# INLINE consumeMany1 #-}
1369+consumeMany1 :: Monad m => Consumer m x a b -> Fold m b c -> Consumer m x a c
1370+consumeMany1 (Consumer sstep sinject sextract) (Fold cstep cinitial cextract) =
1371+ Consumer step inject extract
13231372
13241373 where
13251374
1326− loopUntilPartial s = do
1327− res <- initial1
1328− case res of
1329− Partial fs -> return $ Tuple3' 0 fs s
1330− Done _ -> loopUntilPartial s
1375+ -- cs = collect state
1376+ -- ss = split state
1377+ -- cres = collect state result
1378+ -- sres = split state result
1379+ -- cb = collect done
1380+ -- sb = split done
1381+
1382+ -- Caution! There is mutual recursion here, inlining the right functions is
1383+ -- important.
13311384
1332− inject' x = inject2 x >>= loopUntilPartial
1385+ {-# INLINE split #-}
1386+ split x cs f sres =
1387+ case sres of
1388+ Partial ss -> return $ Partial $ ConsumeMany x cs (f ss)
1389+ Done sb -> cstep cs sb >>= collect x
13331390
1334− step' (Tuple3' i r1 r2) a =
1335− if i < n
1336− then do
1337− res <- step1 r1 a
1338− case res of
1339− Partial s -> return $ Tuple3' (i + 1) s r2
1340− Done b -> step2 r2 b >>= loopUntilPartial
1341− else extract1 r1 >>= step2 r2 >>= loopUntilPartial
1391+ {-# INLINE collect #-}
1392+ collect x cres =
1393+ case cres of
1394+ Partial cs -> sinject x >>= split x cs Left
1395+ Done cb -> return $ Done cb
1396+
1397+ inject x = cinitial >>= collect x
13421398
1343− extract' (Tuple3' _ r1 r2) = extract1 r1 >>= step2 r2 >>= extract2
1399+ {-# INLINE step_ #-}
1400+ step_ x ss cs a = sstep ss a >>= split x cs Right
1401+
1402+ {-# INLINE step #-}
1403+ step (ConsumeMany x cs (Left ss)) a = step_ x ss cs a
1404+ step (ConsumeMany x cs (Right ss)) a = step_ x ss cs a
1405+
1406+ -- Do not extract the split fold if no item was consumed.
1407+ extract (ConsumeMany _ cs (Left _)) = cextract cs
1408+ extract (ConsumeMany _ cs (Right ss )) = do
1409+ cres <- sextract ss >>= cstep cs
1410+ case cres of
1411+ Partial s -> cextract s
1412+ Done b -> return b