@@ -10,6 +10,9 @@
10-- 'Monoid' whereas the 'Consumer' type has to be supplied with an initial
10-- 'Monoid' whereas the 'Consumer' type has to be supplied with an initial
11-- value, therefore, it is more like a 'Semigroup' operation.
11-- value, therefore, it is more like a 'Semigroup' operation.
13+-- Consumers can be appended to each other or to a fold to build the fold
14+-- incrementally. This is useful in incremental builder like use cases.
13-- See the file splitting example in the @streamly-examples@ repository for an
16-- See the file splitting example in the @streamly-examples@ repository for an
14-- application of the 'Consumer' type. The 'Fold' type does not perform as well
17-- application of the 'Consumer' type. The 'Fold' type does not perform as well
15-- in this situation.
18-- in this situation.
@@ -30,10 +33,12 @@ module Streamly.Internal.Data.Consumer.Type
30 -- ** Accumulators
33 -- ** Accumulators
34 -- * Combinators
38 -- * Combinators
@@ -45,7 +50,7 @@ import Data.Semigroup (Semigroup((<>)))
45import Fusion.Plugin.Types (Fuse(..))
50import Fusion.Plugin.Types (Fuse(..))
46import Streamly.Internal.Data.Fold.Step (Step(..), mapMStep)
51import Streamly.Internal.Data.Fold.Step (Step(..), mapMStep)
48−import Prelude hiding (take)
53+import Prelude hiding (take, iterate)
@@ -153,6 +158,61 @@ drainBy f = Consumer step inject extract
153sconcat :: (Monad m, Semigroup a) => Consumer m a a a
158sconcat :: (Monad m, Semigroup a) => Consumer m a a a
154sconcat = foldl' (<>)
159sconcat = foldl' (<>)
161+------------------------------------------------------------------------------
163+------------------------------------------------------------------------------
165+-- | Supply the output of the first consumer as input to the second consumer.
168+{-# INLINE append #-}
169+append :: Monad m => Consumer m x a b -> Consumer m b a b -> Consumer m x a b
170+append (Consumer step1 inject1 extract1) (Consumer step2 inject2 extract2) =
171+ Consumer step inject extract
177+ Partial s -> return $ Partial $ Left s
181+ Partial s -> Partial $ Right s
184+ inject x = inject1 x >>= goLeft
186+ step (Left s) a = step1 s a >>= goLeft
188+ step (Right s) a = do
191+ Partial s1 -> return $ Partial (Right s1)
192+ Done b -> return $ Done b
194+ extract (Left s) = extract1 s
195+ extract (Right s) = extract2 s
197+-- | Keep running the same consumer over and over again on the input, feeding
198+-- the output of the previous run to the next.
201+iterate :: Monad m => Consumer m b a b -> Consumer m b a b
202+iterate (Consumer step1 inject1 extract1) =
203+ Consumer step inject extract1
209+ Partial s -> return $ Partial s
212+ inject x = inject1 x >>= go
214+ step s a = step1 s a >>= go
156------------------------------------------------------------------------------
216------------------------------------------------------------------------------
157-- Transformation
217-- Transformation
158------------------------------------------------------------------------------
218------------------------------------------------------------------------------