on master help sign in
Organize the export list of Streamly.Data.Stream (#1799)
e576de8Harendra Kumar
core/src/Streamly/Data/Stream.hs+196−190
@@ -48,7 +48,7 @@
48-- 2
48-- 2
49-- [1,2]
49-- [1,2]
50--
50--
51−-- == Console Echo Program
51+-- == Console Echo Example
52--
52--
53-- In the following example, 'repeatM' generates an infinite stream of 'String'
53-- In the following example, 'repeatM' generates an infinite stream of 'String'
54-- by repeatedly performing the 'getLine' IO action. 'mapM' then applies
54-- by repeatedly performing the 'getLine' IO action. 'mapM' then applies
@@ -73,38 +73,11 @@
73-- Hopefully, this gives you an idea how we can program declaratively by
73-- Hopefully, this gives you an idea how we can program declaratively by
74-- representing loops using streams. In this module, you can find all
74-- representing loops using streams. In this module, you can find all
75-- "Data.List" like functions and many more powerful combinators to perform
75-- "Data.List" like functions and many more powerful combinators to perform
76−-- common programming tasks. Also see "Streamly.Internal.Data.Stream"
76+-- common programming tasks.
77−-- module for many more @Pre-release@ combinators. See the
78−-- <https://github.com/composewell/streamly-examples> repository for many more
79−-- real world examples of stream programming.
80--
77--
81−-- == Combining two streams
78+-- Also see "Streamly.Internal.Data.Stream" module for many more @Pre-release@
82−--
79+-- combinators. See the <https://github.com/composewell/streamly-examples>
83−-- Two streams can be combined to form a single stream in several ways.
80+-- repository for many more real world examples of stream programming.
84−-- 'append', 'interleave', 'zipWith', 'mergeBy', are some ways of combining two
85−-- streams.
86−--
87−-- == Combining many streams
88−--
89−-- The 'concatMapWith' combinator can be used to generalize the two stream
90−-- combining combinators to @n@ streams.
91−--
92−-- See the @streamly-examples@ repository for a full working example.
93−--
94−-- == Semigroup Instance
95−--
96−-- The 'Semigroup' operation '<>' has an appending behavior i.e. it executes
97−-- the actions from the second stream after executing actions from the first
98−-- stream:
99−--
100−-- >>> stream1 = Stream.sequence $ Stream.fromList [effect 1, effect 2]
101−-- >>> stream2 = Stream.sequence $ Stream.fromList [effect 3, effect 4]
102−-- >>> Stream.fold Fold.toList $ stream1 <> stream2
103−-- 1
104−-- 2
105−-- 3
106−-- 4
107−-- [1,2,3,4]
108--
81--
109module Streamly.Data.Stream
82module Streamly.Data.Stream
110 (
83 (
@@ -122,14 +95,9 @@ module Streamly.Data.Stream
122 -- versions provided in this module can be much more efficient in most
95 -- versions provided in this module can be much more efficient in most
123 -- cases. Users can create custom combinators using these primitives.
96 -- cases. Users can create custom combinators using these primitives.
124 , nil
97 , nil
125− , cons
126− , consM
127− -- , cons2 -- fused version
128− -- , consM2 -- fused version
129
98
130 -- ** Unfolding
99 -- ** Unfolding
131 -- | Generalized way of generating a stream efficiently.
100 -- | Generalized way of generating a stream efficiently.
132− , unfold -- XXX rename to fromUnfold?
133 , unfoldr
101 , unfoldr
134 , unfoldrM
102 , unfoldrM
135
103
@@ -169,19 +137,149 @@ module Streamly.Data.Stream
169 , fromList
137 , fromList
170 , fromFoldable
138 , fromFoldable
171
139
172− -- * Elimination
140+ -- ** From Unfolds
173− -- | Functions ending in the general shape @Stream m a -> m b@
141+ -- | Most of the above stream generation operations can also be expressed
142+ -- using the corresponding unfolds in the "Streamly.Data.Unfold" module.
143+ , unfold -- XXX rename to fromUnfold?
144+
145+ -- * Expanding
146+ -- | Operations that increase the size of a stream by adding one or more
147+ -- elements to it.
174 --
148 --
175− -- See also: "Streamly.Internal.Data.Stream.Eliminate" for
149+ -- See also: "Streamly.Internal.Data.Stream.Expand" for
176 -- @Pre-release@ functions.
150 -- @Pre-release@ functions.
177
151
178− -- ** Deconstruction
152+ -- ** Consing Elements
179− -- | Functions ending in the general shape @Stream m a -> m (b, Stream m a)@
153+ , cons
180− , uncons
154+ , consM
181− -- , foldBreak
155+ -- , cons2 -- fused version
182− -- , parseBreak
156+ -- , consM2 -- fused version
157+
158+ -- ** Inserting Elements
159+ -- | Inserting elements is a special case of interleaving/merging streams.
160+
161+ , insertBy
162+ , intersperseM
163+ , intersperse
164+
165+ -- ** Appending
166+ , append
167+ , append2
168+
169+ -- ** Interleaving
170+ -- , interleave
171+ -- , interleave2
172+ , wSerial -- XXX rename to interleaveWeighted
173+
174+ -- ** Merging
175+ -- | Merging of @n@ streams can be performed by combining the streams pair
176+ -- wise using
177+ -- 'Streamly.Internal.Data.Stream.IsStream.Expand.concatPairsWith' to give
178+ -- O(n * log n) time complexity.
179+ -- If used with 'concatMapWith' it will have O(n^2) performance.
180+
181+ , mergeBy
182+ , mergeByM
183+ -- , mergeBy2
184+ -- , mergeByM2
185+
186+ -- ** Nested Unfolds
187+ , unfoldMany
188+ , intercalate
189+ , intercalateSuffix
190+
191+ -- ** Nested Streams
192+ -- | Stream operations like map and filter represent loop processing in
193+ -- imperative programming terms. Similarly, the imperative concept of
194+ -- nested loops are represented by streams of streams. The 'concatMap'
195+ -- operation represents nested looping.
196+ -- A 'concatMap' operation loops over the input stream and then for each
197+ -- element of the input stream generates another stream and then loops over
198+ -- that inner stream as well producing effects and generating a single
199+ -- output stream.
200+ -- The 'Monad' instances of different stream types provide a more
201+ -- convenient way of writing nested loops. Note that the monad bind
202+ -- operation is just @flip concatMap@.
203+ --
204+ -- One dimension loops are just a special case of nested loops. For
205+ -- example, 'concatMap' can degenerate to a simple map operation:
206+ --
207+ -- > map f m = S.concatMap (\x -> S.fromPure (f x)) m
208+ --
209+ -- Similarly, 'concatMap' can perform filtering by mapping an element to a
210+ -- 'nil' stream:
211+ --
212+ -- > filter p m = S.concatMap (\x -> if p x then S.fromPure x else S.nil) m
213+ --
214+
215+ , concatMapWith
216+ , concatMap
217+ , concatMapM
218+
219+ -- * Scanning
220+ -- | One-to-one transformations not changing the size (almost) of the
221+ -- stream.
222+ --
223+ -- See also: "Streamly.Internal.Data.Stream.Transform" for
224+ -- @Pre-release@ functions.
225+
226+ -- ** Mapping
227+ -- | Stateless one-to-one transformations. Use 'fmap' for mapping a pure
228+ -- function on a stream.
229+
230+ -- EXPLANATION:
231+ -- In imperative terms a map operation can be considered as a loop over
232+ -- the stream that transforms the stream into another stream by performing
233+ -- an operation on each element of the stream.
234+ --
235+ -- 'map' is the least powerful transformation operation with strictest
236+ -- guarantees. A map, (1) is a stateless loop which means that no state is
237+ -- allowed to be carried from one iteration to another, therefore,
238+ -- operations on different elements are guaranteed to not affect each
239+ -- other, (2) is a strictly one-to-one transformation of stream elements
240+ -- which means it guarantees that no elements can be added or removed from
241+ -- the stream, it can merely transform them.
242+ , sequence
243+ , mapM
244+
245+ -- ** Mapping Side Effects
246+ -- , trace -- XXX Use "tracing" map instead?
247+ , tap
248+ , delay
249+
250+ -- ** Scanning
251+ -- | Stateful one-to-one transformations.
252+ , scan
253+ , postscan
254+ -- XXX postscan1 can be implemented using Monoids or Refolds.
255+
256+ -- ** Indexing
257+ -- | Indexing can be considered as a special type of zipping where we zip a
258+ -- stream with an index stream.
259+ , indexed
260+ , indexedR
261+
262+ -- ** Reordering Elements
263+ , reverse
264+
265+ -- ** Zipping
266+ -- | Zipping of @n@ streams can be performed by combining the streams pair
267+ -- wise using
268+ -- 'Streamly.Internal.Data.Stream.IsStream.Expand.concatPairsWith' with
269+ -- O(n * log n) time complexity.
270+ -- If used with 'concatMapWith' it will have O(n^2) performance.
271+ , zipWith
272+ , zipWithM
273+ -- , zipWith2
274+ -- , zipWithM2
275+
276+ -- * Reducing
277+ -- | Operations that reduce the size of a stream by removing some or all
278+ -- elements from it.
279+ --
280+ -- See also: "Streamly.Internal.Data.Stream.Reduce" and
281+ -- "Streamly.Internal.Data.Stream.Eliminate" for @Pre-release@ functions.
183
282
184− -- -- ** General Folds
185-- EXPLANATION: In imperative terms a fold can be considered as a loop over the stream
283-- EXPLANATION: In imperative terms a fold can be considered as a loop over the stream
186-- that reduces the stream to a single value.
284-- that reduces the stream to a single value.
187-- Left and right folds both use a fold function @f@ and an identity element
285-- Left and right folds both use a fold function @f@ and an identity element
@@ -249,90 +347,32 @@ module Streamly.Data.Stream
249-- the previous step. However, it is possible to fold parts of the stream in
347-- the previous step. However, it is possible to fold parts of the stream in
250-- parallel and then combine the results using a monoid.
348-- parallel and then combine the results using a monoid.
251
349
252− -- ** Left folds
350+ -- ** Unconsing
253− -- $runningfolds
351+ , uncons
254− , fold -- XXX rename to run? We can have a Stream.run and Fold.run.
255− -- XXX fold1 can be achieved using Monoids or Refolds.
256−
257− -- ** Right Folds
258− -- $rightfolds
259− , foldrM
260− , foldr
261−
262− -- ** Multi-Stream folds
263− , eqBy
264− , cmpBy
265− , isPrefixOf
266− , isSubsequenceOf
267−
268− -- trimming sequences
269− , stripPrefix
270−
271− -- * Transformation
272− -- | See also: "Streamly.Internal.Data.Stream.Transform" for
273− -- @Pre-release@ functions.
274
352
275− -- ** Mapping
353+ -- ** Filter Map
276− -- | In imperative terms a map operation can be considered as a loop over
354+ -- | Stateless filters. Remove some elements from the stream based on a
277− -- the stream that transforms the stream into another stream by performing
355+ -- predicate.
278− -- an operation on each element of the stream. Use 'fmap' for mapping a
279− -- pure function on a stream.
280
356
281 -- EXPLANATION:
357 -- EXPLANATION:
282− -- 'map' is the least powerful transformation operation with strictest
283− -- guarantees. A map, (1) is a stateless loop which means that no state is
284− -- allowed to be carried from one iteration to another, therefore,
285− -- operations on different elements are guaranteed to not affect each
286− -- other, (2) is a strictly one-to-one transformation of stream elements
287− -- which means it guarantees that no elements can be added or removed from
288− -- the stream, it can merely transform them.
289− , sequence
290− , mapM
291−
292− -- ** Mapping Side Effects
293− -- , trace -- XXX Use "tracing" map instead?
294− , tap
295− , delay
296−
297− -- ** Scanning (Stateful Transformation)
298− , scan
299− , postscan
300− -- XXX postscan1 can be implemented using Monoids or Refolds.
301−
302− -- ** Filtering
303− -- | Remove some elements from the stream based on a predicate. In
304− -- imperative terms a filter over a stream corresponds to a loop with a
358+ -- In imperative terms a filter over a stream corresponds to a loop with a
305 -- @continue@ clause for the cases when the predicate fails.
359 -- @continue@ clause for the cases when the predicate fails.
306
360
307− , deleteBy
361+ , mapMaybe
362+ , mapMaybeM
308 , filter
363 , filter
309 , filterM
364 , filterM
310− , uniq
311
365
312− -- ** Trimming
366+ -- ** Filter Scans
313− -- | Take or remove elements from one or both ends of a stream.
367+ -- | Stateful filters.
314 , take
368 , take
315 , takeWhile
369 , takeWhile
316 , takeWhileM
370 , takeWhileM
317 , drop
371 , drop
318 , dropWhile
372 , dropWhile
319 , dropWhileM
373 , dropWhileM
320−
374+ , deleteBy
321− -- ** Inserting Elements
375+ , uniq
322− -- | Inserting elements is a special case of interleaving/merging streams.
323−
324− , insertBy
325− , intersperseM
326− , intersperse
327−
328− -- ** Reordering Elements
329− , reverse
330−
331− -- ** Indexing
332− -- | Indexing can be considered as a special type of zipping where we zip a
333− -- stream with an index stream.
334− , indexed
335− , indexedR
336
376
337 -- ** Searching
377 -- ** Searching
338 -- | Finding the presence or location of an element, a sequence of elements
378 -- | Finding the presence or location of an element, a sequence of elements
@@ -342,88 +382,54 @@ module Streamly.Data.Stream
342 , findIndices
382 , findIndices
343 , elemIndices
383 , elemIndices
344
384
345− -- ** Maybe Streams
385+ -- ** Splitting
346− , mapMaybe
386+ -- | Consuming a part of the stream and returning the rest. Functions
347− , mapMaybeM
387+ -- ending in the general shape @Stream m a -> m (b, Stream m a)@
348−
388+ , foldBreak
349− -- * Combining Streams
389+ , parseBreak
350− -- | New streams can be constructed by appending, merging or zipping
351− -- existing streams.
352− --
353− -- See also: "Streamly.Internal.Data.Stream.Expand" for
354− -- @Pre-release@ functions.
355−
356− -- ** Appending
357− , append
358− , append2
359
390
360− -- ** Interleaving
391+ -- ** Elimination
361− -- , interleave
392+ -- | Functions ending in the general shape @Stream m a -> m b@
362− -- , interleave2
393+ -- Consuming the stream entirely or partially, discarding the rest.
363− , wSerial -- XXX rename to interleaveWeighted
364−
365− -- ** Merging
366− -- | Merging of @n@ streams can be performed by combining the streams pair
367− -- wise using
368− -- 'Streamly.Internal.Data.Stream.IsStream.Expand.concatPairsWith' to give
369− -- O(n * log n) time complexity.
370− -- If used with 'concatMapWith' it will have O(n^2) performance.
371−
372− , mergeBy
373− , mergeByM
374− -- , mergeBy2
375− -- , mergeByM2
376−
377− -- ** Zipping
378− -- | Zipping of @n@ streams can be performed by combining the streams pair
379− -- wise using
380− -- 'Streamly.Internal.Data.Stream.IsStream.Expand.concatPairsWith' with
381− -- O(n * log n) time complexity.
382− -- If used with 'concatMapWith' it will have O(n^2) performance.
383− , zipWith
384− , zipWithM
385− -- , zipWith2
386− -- , zipWithM2
387−
388− -- * Nested Unfolds
389− , unfoldMany
390− , intercalate
391− , intercalateSuffix
392−
393− -- * Nested Streams
394− -- | Stream operations like map and filter represent loop processing in
395− -- imperative programming terms. Similarly, the imperative concept of
396− -- nested loops are represented by streams of streams. The 'concatMap'
397− -- operation represents nested looping.
398− -- A 'concatMap' operation loops over the input stream and then for each
399− -- element of the input stream generates another stream and then loops over
400− -- that inner stream as well producing effects and generating a single
401− -- output stream.
402− -- The 'Monad' instances of different stream types provide a more
403− -- convenient way of writing nested loops. Note that the monad bind
404− -- operation is just @flip concatMap@.
405− --
406− -- One dimension loops are just a special case of nested loops. For
407− -- example, 'concatMap' can degenerate to a simple map operation:
408− --
409− -- > map f m = S.concatMap (\x -> S.fromPure (f x)) m
410 --
394 --
411− -- Similarly, 'concatMap' can perform filtering by mapping an element to a
395+ -- Strict left folds consume a stream and build a left associated
412− -- 'nil' stream:
396+ -- expression, suitable for incremental/strict evaluation. Evaluation of
397+ -- the input happens when the fold runs, the fold output is fully
398+ -- evaluated. A fold can terminate without consuming the entire stream.
413 --
399 --
414− -- > filter p m = S.concatMap (\x -> if p x then S.fromPure x else S.nil) m
400+ -- This is suitable for reduction operations, for example, operations like
401+ -- summing the stream. See "Streamly.Data.Fold" for an overview of
402+ -- composable left folds. Parsers (See "Streamly.Internal.Data.Parser") are
403+ -- more powerful folds that add backtracking and error functionality to
404+ -- terminating folds.
415 --
405 --
406+ , fold -- XXX rename to run? We can have a Stream.run and Fold.run.
407+ -- XXX fold1 can be achieved using Monoids or Refolds.
408+ , parse
416
409
417− , concatMapWith
410+ -- -- ** Lazy Right Folds
418− , concatMap
411+ -- Consuming a stream to build a right associated expression, suitable
419− , concatMapM
412+ -- for lazy evaluation. Evaluation of the input happens when the output of
413+ -- the fold is evaluated, the fold output is a lazy thunk.
414+ --
415+ -- This is suitable for stream transformation operations, for example,
416+ -- operations like mapping a function over the stream.
417+ -- , foldrM
418+ -- , foldr
420
419
421− -- * Nested Folds
420+ -- ** Nested Folds
422− -- |
423− -- See also: "Streamly.Internal.Data.Stream.Reduce" for
424− -- @Pre-release@ functions.
425 , foldMany
421 , foldMany
426
422
423+ -- ** Multi-Stream folds
424+ -- | Operations that consume multiple streams at the same time.
425+ , eqBy
426+ , cmpBy
427+ , isPrefixOf
428+ , isSubsequenceOf
429+
430+ -- trimming sequences
431+ , stripPrefix
432+
427 -- * Exceptions
433 -- * Exceptions
428 -- | Most of these combinators inhibit stream fusion, therefore, when
434 -- | Most of these combinators inhibit stream fusion, therefore, when
429 -- possible, they should be called in an outer loop to mitigate the cost.
435 -- possible, they should be called in an outer loop to mitigate the cost.
core/src/Streamly/Internal/Data/Stream/Bottom.hs+1−1
@@ -208,7 +208,7 @@ fold fl strm = D.fold fl $ D.fromStreamK $ toStreamK strm
208
208
209-- | Like 'fold' but also returns the remaining stream.
209-- | Like 'fold' but also returns the remaining stream.
210--
210--
211−-- /Inhibits stream fusion/
211+-- /Not fused/
212--
212--
213{-# INLINE foldBreak #-}
213{-# INLINE foldBreak #-}
214foldBreak :: Monad m => Fold m a b -> Stream m a -> m (b, Stream m a)
214foldBreak :: Monad m => Fold m a b -> Stream m a -> m (b, Stream m a)
core/src/Streamly/Internal/Data/Stream/Eliminate.hs+1−1
@@ -244,7 +244,7 @@ parseBreakD parser strm = do
244
244
245-- | Parse a stream using the supplied 'Parser'.
245-- | Parse a stream using the supplied 'Parser'.
246--
246--
247−-- /Internal/
247+-- /Not fused/
248--
248--
249{-# INLINE parseBreak #-}
249{-# INLINE parseBreak #-}
250parseBreak :: MonadThrow m => Parser m a b -> Stream m a -> m (b, Stream m a)
250parseBreak :: MonadThrow m => Parser m a b -> Stream m a -> m (b, Stream m a)
core/src/Streamly/Internal/Data/Stream/Expand.hs+36−3
@@ -55,9 +55,11 @@ module Streamly.Internal.Data.Stream.Expand
55 --
55 --
56 -- @Unfold m a b -> Stream m a -> Stream m b@
56 -- @Unfold m a b -> Stream m a -> Stream m b@
57
57
58− -- ** Append Many (Unfold)
58+ -- ** Unfold and combine streams
59 -- | Unfold and flatten streams.
59 -- | Unfold and flatten streams.
60− , unfoldMany
60+ , unfoldMany -- XXX Rename to unfoldAppend
61+ , unfoldInterleave
62+ , unfoldRoundRobin
61
63
62 -- ** Interpose
64 -- ** Interpose
63 -- | Insert effects between streams. Like unfoldMany but intersperses an
65 -- | Insert effects between streams. Like unfoldMany but intersperses an
@@ -75,7 +77,7 @@ module Streamly.Internal.Data.Stream.Expand
75 , gintercalate
77 , gintercalate
76 , gintercalateSuffix
78 , gintercalateSuffix
77
79
78− -- * Append Many (concatMap)
80+ -- * Combine Streams of Streams
79 -- | Map and serially append streams. 'concatMapM' is a generalization of
81 -- | Map and serially append streams. 'concatMapM' is a generalization of
80 -- the binary append operation to append many streams.
82 -- the binary append operation to append many streams.
81 , concatMapM
83 , concatMapM
@@ -285,6 +287,37 @@ mergeFstBy _f _m1 _m2 = undefined
285unfoldMany ::Monad m => Unfold m a b -> Stream m a -> Stream m b
287unfoldMany ::Monad m => Unfold m a b -> Stream m a -> Stream m b
286unfoldMany u m = fromStreamD $ D.unfoldMany u (toStreamD m)
288unfoldMany u m = fromStreamD $ D.unfoldMany u (toStreamD m)
287
289
290+-- | This does not pair streams like concatPairsWith, instead, it goes through
291+-- each stream one by one and yields one element from each stream. After it
292+-- goes to the last stream it reverses the traversal to come back to the first
293+-- stream yielding elements from each stream on its way back to the first
294+-- stream and so on.
295+--
296+-- >>> lists = Stream.fromList [[1,1],[2,2],[3,3],[4,4],[5,5]]
297+-- >>> interleaved = Stream.unfoldInterleave Unfold.fromList lists
298+-- >>> Stream.fold Fold.toList interleaved
299+-- [1,2,3,4,5,5,4,3,2,1]
300+--
301+-- Note that this is order of magnitude more efficient than "concatPairsWith
302+-- wSerial" because of fusion.
303+--
304+-- /Fused/
305+{-# INLINE unfoldInterleave #-}
306+unfoldInterleave ::Monad m => Unfold m a b -> Stream m a -> Stream m b
307+unfoldInterleave u m =
308+ fromStreamD $ D.unfoldManyInterleave u (toStreamD m)
309+
310+-- | 'unfoldInterleave' switches to the next stream whenever a value from a
311+-- stream is yielded, it does not switch on a 'Skip'. So if a stream keeps
312+-- skipping for long time other streams won't get a chance to run.
313+-- 'unfoldRoundRobin' switches on Skip as well. So it basically schedules each
314+-- stream fairly irrespective of whether it produces a value or not.
315+--
316+{-# INLINE unfoldRoundRobin #-}
317+unfoldRoundRobin ::Monad m => Unfold m a b -> Stream m a -> Stream m b
318+unfoldRoundRobin u m =
319+ fromStreamD $ D.unfoldManyInterleave u (toStreamD m)
320+
288------------------------------------------------------------------------------
321------------------------------------------------------------------------------
289-- Combine N Streams - interpose
322-- Combine N Streams - interpose
290------------------------------------------------------------------------------
323------------------------------------------------------------------------------
core/src/Streamly/Internal/Data/Stream/StreamD/Nesting.hs+3−15
@@ -551,23 +551,11 @@ data ConcatUnfoldInterleaveState o i =
551-- Maybe we can configure the behavior.
551-- Maybe we can configure the behavior.
552--
552--
553-- XXX Instead of using "concatPairsWith wSerial" we can implement an N-way
553-- XXX Instead of using "concatPairsWith wSerial" we can implement an N-way
554−-- interleaving CPS combinator which behaves like unfoldManyInterleave. Intead
554+-- interleaving CPS combinator which behaves like unfoldManyInterleave. Instead
555−-- of pairing up the streams We just need to go yielding one element from each
555+-- of pairing up the streams we just need to go yielding one element from each
556-- stream and storing the remaining streams and then keep doing rounds through
556-- stream and storing the remaining streams and then keep doing rounds through
557-- those in a round robin fashion. This would be much like wAsync.
557-- those in a round robin fashion. This would be much like wAsync.
558−--
558+
559−-- | This does not pair streams like concatPairsWith, instead, it goes through
560−-- each stream one by one and yields one element from each stream. After it
561−-- goes to the last stream it reverses the traversal to come back to the first
562−-- stream yielding elements from each stream on its way back to the first
563−-- stream and so on.
564−--
565−-- >>> input = Stream.fromList [[1,1],[2,2],[3,3],[4,4],[5,5]]
566−-- >>> Stream.toList $ Stream.unfoldManyInterleave Unfold.fromList input
567−-- [1,2,3,4,5,5,4,3,2,1]
568−--
569−-- Note that this is order of magnitude more efficient than "concatPairsWith
570−-- wSerial"
571{-# INLINE_NORMAL unfoldManyInterleave #-}
559{-# INLINE_NORMAL unfoldManyInterleave #-}
572unfoldManyInterleave :: Monad m => Unfold m a b -> Stream m a -> Stream m b
560unfoldManyInterleave :: Monad m => Unfold m a b -> Stream m a -> Stream m b
573unfoldManyInterleave (Unfold istep inject) (Stream ostep ost) =
561unfoldManyInterleave (Unfold istep inject) (Stream ostep ost) =
src/Streamly/Prelude.hs+1−1
@@ -989,7 +989,7 @@ import Streamly.Internal.Data.Stream.IsStream
989
989
990-- $rightfolds
990-- $rightfolds
991--
991--
992−-- Let's take a closer look at the @foldr@ definition for lists, as given3
992+-- Let's take a closer look at the @foldr@ definition for lists, as given
993-- earlier:
993-- earlier:
994--
994--
995-- @
995-- @