@@ -48,7 +48,7 @@
4848-- 2
4949-- [1,2]
5050--
51−-- == Console Echo Program
51+-- == Console Echo Example
5252--
5353-- In the following example, 'repeatM' generates an infinite stream of 'String'
5454-- by repeatedly performing the 'getLine' IO action. 'mapM' then applies
@@ -73,38 +73,11 @@
7373-- Hopefully, this gives you an idea how we can program declaratively by
7474-- representing loops using streams. In this module, you can find all
7575-- "Data.List" like functions and many more powerful combinators to perform
76−-- common programming tasks. Also see "Streamly.Internal.Data.Stream"
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.
76+-- common programming tasks.
8077--
81−-- == Combining two streams
82−--
83−-- Two streams can be combined to form a single stream in several ways.
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]
78+-- Also see "Streamly.Internal.Data.Stream" module for many more @Pre-release@
79+-- combinators. See the <https://github.com/composewell/streamly-examples>
80+-- repository for many more real world examples of stream programming.
10881--
10982module Streamly.Data.Stream
11083 (
@@ -122,14 +95,9 @@ module Streamly.Data.Stream
12295 -- versions provided in this module can be much more efficient in most
12396 -- cases. Users can create custom combinators using these primitives.
12497 , nil
125− , cons
126− , consM
127− -- , cons2 -- fused version
128− -- , consM2 -- fused version
12998
13099 -- ** Unfolding
131100 -- | Generalized way of generating a stream efficiently.
132− , unfold -- XXX rename to fromUnfold?
133101 , unfoldr
134102 , unfoldrM
135103
@@ -169,19 +137,149 @@ module Streamly.Data.Stream
169137 , fromList
170138 , fromFoldable
171139
172− -- * Elimination
173− -- | Functions ending in the general shape @Stream m a -> m b@
140+ -- ** From Unfolds
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.
174148 --
175− -- See also: "Streamly.Internal.Data.Stream.Eliminate" for
149+ -- See also: "Streamly.Internal.Data.Stream.Expand" for
176150 -- @Pre-release@ functions.
177151
178− -- ** Deconstruction
179− -- | Functions ending in the general shape @Stream m a -> m (b, Stream m a)@
180− , uncons
181− -- , foldBreak
182− -- , parseBreak
152+ -- ** Consing Elements
153+ , cons
154+ , consM
155+ -- , cons2 -- fused version
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.
183282
184− -- -- ** General Folds
185283-- EXPLANATION: In imperative terms a fold can be considered as a loop over the stream
186284-- that reduces the stream to a single value.
187285-- Left and right folds both use a fold function @f@ and an identity element
@@ -249,90 +347,32 @@ module Streamly.Data.Stream
249347-- the previous step. However, it is possible to fold parts of the stream in
250348-- parallel and then combine the results using a monoid.
251349
252− -- ** Left folds
253− -- $runningfolds
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.
350+ -- ** Unconsing
351+ , uncons
274352
275− -- ** Mapping
276− -- | In imperative terms a map operation can be considered as a loop over
277− -- the stream that transforms the stream into another stream by performing
278− -- an operation on each element of the stream. Use 'fmap' for mapping a
279− -- pure function on a stream.
353+ -- ** Filter Map
354+ -- | Stateless filters. Remove some elements from the stream based on a
355+ -- predicate.
280356
281357 -- 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
305359 -- @continue@ clause for the cases when the predicate fails.
306360
307− , deleteBy
361+ , mapMaybe
362+ , mapMaybeM
308363 , filter
309364 , filterM
310− , uniq
311365
312− -- ** Trimming
313− -- | Take or remove elements from one or both ends of a stream.
366+ -- ** Filter Scans
367+ -- | Stateful filters.
314368 , take
315369 , takeWhile
316370 , takeWhileM
317371 , drop
318372 , dropWhile
319373 , dropWhileM
320−
321− -- ** Inserting Elements
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
374+ , deleteBy
375+ , uniq
336376
337377 -- ** Searching
338378 -- | Finding the presence or location of an element, a sequence of elements
@@ -342,88 +382,54 @@ module Streamly.Data.Stream
342382 , findIndices
343383 , elemIndices
344384
345− -- ** Maybe Streams
346− , mapMaybe
347− , mapMaybeM
348−
349− -- * Combining Streams
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
385+ -- ** Splitting
386+ -- | Consuming a part of the stream and returning the rest. Functions
387+ -- ending in the general shape @Stream m a -> m (b, Stream m a)@
388+ , foldBreak
389+ , parseBreak
359390
360− -- ** Interleaving
361− -- , interleave
362− -- , interleave2
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
391+ -- ** Elimination
392+ -- | Functions ending in the general shape @Stream m a -> m b@
393+ -- Consuming the stream entirely or partially, discarding the rest.
410394 --
411− -- Similarly, 'concatMap' can perform filtering by mapping an element to a
412− -- 'nil' stream:
395+ -- Strict left folds consume a stream and build a left associated
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.
413399 --
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.
415405 --
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
416409
417− , concatMapWith
418− , concatMap
419− , concatMapM
410+ -- -- ** Lazy Right Folds
411+ -- Consuming a stream to build a right associated expression, suitable
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
420419
421− -- * Nested Folds
422− -- |
423− -- See also: "Streamly.Internal.Data.Stream.Reduce" for
424− -- @Pre-release@ functions.
420+ -- ** Nested Folds
425421 , foldMany
426422
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+
427433 -- * Exceptions
428434 -- | Most of these combinators inhibit stream fusion, therefore, when
429435 -- possible, they should be called in an outer loop to mitigate the cost.