on master help sign in
Add iterate and append
28fe29bHarendra Kumar
src/Streamly/Internal/Data/Consumer/Type.hs+61−1
@@ -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.
12--
12--
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.
15+--
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
31 , sconcat
34 , sconcat
32 , drainBy
35 , drainBy
36+ , iterate
33
37
34 -- * Combinators
38 -- * Combinators
35 , lmapM
39 , lmapM
36 , rmapM
40 , rmapM
41+ , append
37 , take
42 , take
38 )
43 )
39where
44where
@@ -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)
47
52
48−import Prelude hiding (take)
53+import Prelude hiding (take, iterate)
49
54
50-- $setup
55-- $setup
51-- >>> :m
56-- >>> :m
@@ -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' (<>)
155
160
161+------------------------------------------------------------------------------
162+-- append
163+------------------------------------------------------------------------------
164+
165+-- | Supply the output of the first consumer as input to the second consumer.
166+--
167+-- /Internal/
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
172+
173+ where
174+
175+ goLeft r = do
176+ case r of
177+ Partial s -> return $ Partial $ Left s
178+ Done b -> do
179+ r1 <- inject2 b
180+ return $ case r1 of
181+ Partial s -> Partial $ Right s
182+ Done b1 -> Done b1
183+
184+ inject x = inject1 x >>= goLeft
185+
186+ step (Left s) a = step1 s a >>= goLeft
187+
188+ step (Right s) a = do
189+ r <- step2 s a
190+ case r of
191+ Partial s1 -> return $ Partial (Right s1)
192+ Done b -> return $ Done b
193+
194+ extract (Left s) = extract1 s
195+ extract (Right s) = extract2 s
196+
197+-- | Keep running the same consumer over and over again on the input, feeding
198+-- the output of the previous run to the next.
199+--
200+-- /Internal/
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
204+
205+ where
206+
207+ go r =
208+ case r of
209+ Partial s -> return $ Partial s
210+ Done b -> inject b
211+
212+ inject x = inject1 x >>= go
213+
214+ step s a = step1 s a >>= go
215+
156------------------------------------------------------------------------------
216------------------------------------------------------------------------------
157-- Transformation
217-- Transformation
158------------------------------------------------------------------------------
218------------------------------------------------------------------------------