on 81bfdec help sign in
505 lines 17 kB history raw
1-- |
2-- Module : Streamly.Data.Stream
3-- Copyright : (c) 2017 Composewell Technologies
4--
5-- License : BSD3
6-- Maintainer : streamly@composewell.com
7-- Stability : released
8-- Portability : GHC
9--
10-- To run examples in this module:
11--
12-- >>> import qualified Streamly.Data.Fold as Fold
13-- >>> import qualified Streamly.Data.Stream as Stream
14--
15-- We will add some more imports in the examples as needed.
16--
17-- For effectful streams we will use the following IO action:
18--
19-- >>> effect n = print n >> return n
20--
21-- = Overview
22--
23-- Streamly is a framework for modular data flow based programming and
24-- declarative concurrency. Powerful stream fusion framework in streamly
25-- allows high performance combinatorial programming even when using byte level
26-- streams. Streamly API is similar to Haskell lists.
27--
28-- Streams can be constructed like lists, except that they use 'nil' instead of
29-- '[]' and 'cons' instead of ':'.
30--
31-- `cons` adds a pure value at the head of the stream:
32--
33-- >>> import Streamly.Data.Stream (Stream, cons, consM, nil)
34-- >>> stream = 1 `cons` 2 `cons` nil :: Stream IO Int
35-- >>> Stream.fold Fold.toList stream -- IO [Int]
36-- [1,2]
37--
38-- `consM` adds an effect at the head of the stream:
39--
40-- >>> stream = effect 1 `consM` effect 2 `consM` nil
41-- >>> Stream.fold Fold.toList stream
42-- 1
43-- 2
44-- [1,2]
45--
46-- == Console Echo Example
47--
48-- In the following example, 'repeatM' generates an infinite stream of 'String'
49-- by repeatedly performing the 'getLine' IO action. 'mapM' then applies
50-- 'putStrLn' on each element in the stream converting it to stream of '()'.
51-- Finally, 'drain' folds the stream to IO discarding the () values, thus
52-- producing only effects.
53--
54-- >>> import Data.Function ((&))
55--
56-- >>> :{
57-- echo =
58-- Stream.repeatM getLine -- Stream IO String
59-- & Stream.mapM putStrLn -- Stream IO ()
60-- & Stream.fold Fold.drain -- IO ()
61-- :}
62--
63-- This is a console echo program. It is an example of a declarative loop
64-- written using streaming combinators. Compare it with an imperative @while@
65-- loop.
66--
67-- Hopefully, this gives you an idea how we can program declaratively by
68-- representing loops using streams. In this module, you can find all
69-- "Data.List" like functions and many more powerful combinators to perform
70-- common programming tasks.
71--
72-- == Useful Idioms
73--
74-- >>> fromListM = Stream.sequence . Stream.fromList
75-- >>> fromFoldableM = Stream.sequence . Stream.fromFoldable
76-- >>> fromIndices f = fmap f $ Stream.enumerateFrom 0
77--
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.
81--
82-- == Performance Notes
83--
84-- Operations annotated as /CPS/ force the use of continuation passing style
85-- streams. Therefore, such operations are not subjected to stream fusion.
86-- However, for some of these operations you can find fusible alternatives in
87-- the internal modules, which are perfectly fine to use but you need to
88-- understand the implications especially the O(n^2) nature of those
89-- operations..
90--
91module Streamly.Data.Stream
92 (
93 Stream
94 -- * Construction
95 -- | Functions ending in the general shape @b -> Stream m a@.
96 --
97 -- See also: "Streamly.Internal.Data.Stream.Generate" for
98 -- @Pre-release@ functions.
100 -- ** Primitives
101 -- | Primitives to construct a stream from pure values or monadic actions.
102 -- All other stream construction and generation combinators described later
103 -- can be expressed in terms of these primitives. However, the special
104 -- versions provided in this module can be much more efficient in most
105 -- cases. Users can create custom combinators using these primitives.
106 , nil
107 , nilM
108 , cons
109 , consM
110 -- , cons2 -- fused version
111 -- , consM2 -- fused version
113 -- ** Unfolding
114 -- | 'unfoldrM' is the most general way of generating a stream efficiently.
115 -- All other generation operations can be expressed using it.
116 , unfoldr
117 , unfoldrM
119 -- ** From Values
120 -- | Generate a monadic stream from a seed value or values.
121 , fromPure
122 , fromEffect
123 , repeat
124 , repeatM
125 , replicate
126 , replicateM
128 -- Note: Using enumeration functions e.g. 'Prelude.enumFromThen' turns out
129 -- to be slightly faster than the idioms like @[from, then..]@.
130 --
131 -- ** Enumeration
132 -- | We can use the 'Enum' type class to enumerate a type producing a list
133 -- and then convert it to a stream:
134 --
135 -- @
136 -- 'fromList' $ 'Prelude.enumFromThen' from then
137 -- @
138 --
139 -- However, this is not particularly efficient.
140 -- The 'Enumerable' type class provides corresponding functions that
141 -- generate a stream instead of a list, efficiently.
143 , Enumerable (..)
144 , enumerate
145 , enumerateTo
147 -- ** Iteration
148 , iterate
149 , iterateM
151 -- ** From Containers
152 -- | Convert an input structure, container or source into a stream. All of
153 -- these can be expressed in terms of primitives.
154 , fromList
155 , fromFoldable
157 -- ** From Unfolds
158 -- | Most of the above stream generation operations can also be expressed
159 -- using the corresponding unfolds in the "Streamly.Data.Unfold" module.
160 , unfold -- XXX rename to fromUnfold?
162 -- * Elimination
163 -- | Functions ending in the general shape @Stream m a -> m b@ or @Stream m
164 -- a -> m (b, Stream m a)@
165 --
166 -- See also: "Streamly.Internal.Data.Stream.Eliminate" for @Pre-release@
167 -- functions.
169-- EXPLANATION: In imperative terms a fold can be considered as a loop over the stream
170-- that reduces the stream to a single value.
171-- Left and right folds both use a fold function @f@ and an identity element
172-- @z@ (@zero@) to deconstruct a recursive data structure and reconstruct a
173-- new data structure. The new structure may be a recursive construction (a
174-- container) or a non-recursive single value reduction of the original
175-- structure.
176--
177-- Both right and left folds are mathematical duals of each other, they are
178-- functionally equivalent. Operationally, a left fold on a left associated
179-- structure behaves exactly in the same way as a right fold on a right
180-- associated structure. Similarly, a left fold on a right associated structure
181-- behaves in the same way as a right fold on a left associated structure.
182-- However, the behavior of a right fold on a right associated structure is
183-- operationally different (even though functionally equivalent) than a left
184-- fold on the same structure.
185--
186-- On right associated structures like Haskell @cons@ lists or Streamly
187-- streams, a lazy right fold is naturally suitable for lazy recursive
188-- reconstruction of a new structure, while a strict left fold is naturally
189-- suitable for efficient reduction. In right folds control is in the hand of
190-- the @puller@ whereas in left folds the control is in the hand of the
191-- @pusher@.
192--
193-- The behavior of right and left folds are described in detail in the
194-- individual fold's documentation. To illustrate the two folds for right
195-- associated @cons@ lists:
196--
197-- > foldr :: (a -> b -> b) -> b -> [a] -> b
198-- > foldr f z [] = z
199-- > foldr f z (x:xs) = x `f` foldr f z xs
200-- >
201-- > foldl :: (b -> a -> b) -> b -> [a] -> b
202-- > foldl f z [] = z
203-- > foldl f z (x:xs) = foldl f (z `f` x) xs
204--
205-- @foldr@ is conceptually equivalent to:
206--
207-- > foldr f z [] = z
208-- > foldr f z [x] = f x z
209-- > foldr f z xs = foldr f (foldr f z (tail xs)) [head xs]
210--
211-- @foldl@ is conceptually equivalent to:
212--
213-- > foldl f z [] = z
214-- > foldl f z [x] = f z x
215-- > foldl f z xs = foldl f (foldl f z (init xs)) [last xs]
216--
217-- Left and right folds are duals of each other.
218--
219-- @
220-- foldr f z xs = foldl (flip f) z (reverse xs)
221-- foldl f z xs = foldr (flip f) z (reverse xs)
222-- @
223--
224-- More generally:
225--
226-- @
227-- foldr f z xs = foldl g id xs z where g k x = k . f x
228-- foldl f z xs = foldr g id xs z where g x k = k . flip f x
229-- @
230--
232-- NOTE: Folds are inherently serial as each step needs to use the result of
233-- the previous step. However, it is possible to fold parts of the stream in
234-- parallel and then combine the results using a monoid.
236 -- ** Primitives
237 -- Consuming a part of the stream and returning the rest. Functions
238 -- ending in the general shape @Stream m a -> m (b, Stream m a)@
239 , uncons
241 -- ** Folding
242 -- XXX Need to have a general parse operation here which can be used to
243 -- express all others.
244 , fold -- XXX rename to run? We can have a Stream.run and Fold.run.
245 -- XXX fold1 can be achieved using Monoids or Refolds.
246 -- XXX We can call this just "break" and parseBreak as "munch"
247 , foldBreak
249 -- XXX should we have a Fold returning function in stream module?
250 -- , foldAdd
251 -- , buildl
253 -- ** Parsing
254 , parse
255 , parseBreak
257 -- -- ** Lazy Right Folds
258 -- Consuming a stream to build a right associated expression, suitable
259 -- for lazy evaluation. Evaluation of the input happens when the output of
260 -- the fold is evaluated, the fold output is a lazy thunk.
261 --
262 -- This is suitable for stream transformation operations, for example,
263 -- operations like mapping a function over the stream.
264 -- , foldrM
265 -- , foldr
267 -- * Mapping
268 -- | Stateless one-to-one transformations. Use 'fmap' for mapping a pure
269 -- function on a stream.
271 -- EXPLANATION:
272 -- In imperative terms a map operation can be considered as a loop over
273 -- the stream that transforms the stream into another stream by performing
274 -- an operation on each element of the stream.
275 --
276 -- 'map' is the least powerful transformation operation with strictest
277 -- guarantees. A map, (1) is a stateless loop which means that no state is
278 -- allowed to be carried from one iteration to another, therefore,
279 -- operations on different elements are guaranteed to not affect each
280 -- other, (2) is a strictly one-to-one transformation of stream elements
281 -- which means it guarantees that no elements can be added or removed from
282 -- the stream, it can merely transform them.
283 , sequence
284 , mapM
285 -- , trace -- XXX Use "tracing" map instead?
286 , tap
287 , delay
289 -- * Scanning
290 -- | Stateful one-to-one transformations.
291 --
292 -- See also: "Streamly.Internal.Data.Stream.Transform" for
293 -- @Pre-release@ functions.
294 , scan
295 , postscan
296 -- XXX postscan1 can be implemented using Monoids or Refolds.
297 -- Indexing can be considered as a special type of zipping where we zip a
298 -- stream with an index stream.
299 , indexed
301 -- * Insertion
302 -- | Add elements to the stream.
304 -- Inserting elements is a special case of interleaving/merging streams.
305 , insertBy
306 , intersperseM
307 , intersperseM_
308 , intersperse
310 -- * Filtering
311 -- | Remove elements from the stream.
313 -- ** Stateless Filters
314 -- | 'mapMaybeM' is the most general stateless filtering operation. All
315 -- other filtering operations can be expressed using it.
317 -- EXPLANATION:
318 -- In imperative terms a filter over a stream corresponds to a loop with a
319 -- @continue@ clause for the cases when the predicate fails.
321 , mapMaybe
322 , mapMaybeM
323 , filter
324 , filterM
326 -- Filter and concat
327 , catMaybes
328 , catLefts
329 , catRights
330 , catEithers
332 -- ** Stateful Filters
333 -- | 'scanMaybe' is the most general stateful filtering operation. The
334 -- filtering folds (folds returning a 'Maybe' type) in
335 -- "Streamly.Internal.Data.Fold" can be used along with 'scanMaybe' to
336 -- perform stateful filtering operations in general.
337 , scanMaybe
338 , take
339 , takeWhile
340 , takeWhileM
341 , drop
342 , dropWhile
343 , dropWhileM
345 -- XXX These are available as scans in folds. We need to check the
346 -- performance though. If these are common and we need convenient stream
347 -- ops then we can expose these.
349 -- , deleteBy
350 -- , uniq
351 -- , uniqBy
353 -- -- ** Sampling
354 -- , strideFromThen
356 -- -- ** Searching
357 -- Finding the presence or location of an element, a sequence of elements
358 -- or another stream within a stream.
360 -- -- ** Searching Elements
361 -- , findIndices
362 -- , elemIndices
364 -- * Combining Two Streams
365 -- ** Appending
366 , append
368 -- ** Interleaving
369 , interleave
370 -- , interleave2
372 -- ** Merging
373 -- | Merging of @n@ streams can be performed by combining the streams pair
374 -- wise using 'mergeMapWith' to give O(n * log n) time complexity. If used
375 -- with 'concatMapWith' it will have O(n^2) performance.
377 , mergeBy
378 , mergeByM
379 -- , mergeBy2
380 -- , mergeByM2
382 -- ** Zipping
383 -- | Zipping of @n@ streams can be performed by combining the streams pair
384 -- wise using 'mergeMapWith' with O(n * log n) time complexity. If used
385 -- with 'concatMapWith' it will have O(n^2) performance.
386 , zipWith
387 , zipWithM
388 -- , zipWith2
389 -- , zipWithM2
390 , ZipStream (..)
392 -- ** Cross Product
393 -- XXX The argument order in this operation is such that it seems we are
394 -- transforming the first stream using the second stream because the second
395 -- stream is evaluated many times or buffered and better be finite, first
396 -- stream could potentially be infinite. In the tradition of using the
397 -- transformed stream at the end we can have a flipped version called
398 -- "crossMap" or "nestWith".
399 , crossWith
400 -- , cross
401 -- , joinInner
402 , CrossStream (..)
404 -- * Unfold Each
405 , unfoldMany
406 , intercalate
407 , intercalateSuffix
409 -- * Stream of streams
410 -- | Stream operations like map and filter represent loop processing in
411 -- imperative programming terms. Similarly, the imperative concept of
412 -- nested loops are represented by streams of streams. The 'concatMap'
413 -- operation represents nested looping.
414 -- A 'concatMap' operation loops over the input stream and then for each
415 -- element of the input stream generates another stream and then loops over
416 -- that inner stream as well producing effects and generating a single
417 -- output stream.
418 --
419 -- One dimension loops are just a special case of nested loops. For
420 -- example, 'concatMap' can degenerate to a simple map operation:
421 --
422 -- > map f m = S.concatMap (\x -> S.fromPure (f x)) m
423 --
424 -- Similarly, 'concatMap' can perform filtering by mapping an element to a
425 -- 'nil' stream:
426 --
427 -- > filter p m = S.concatMap (\x -> if p x then S.fromPure x else S.nil) m
428 --
430 , concatEffect
431 , concatMapWith
432 , concatMap
433 , concatMapM
434 , mergeMapWith
436 -- * Repeated Fold
437 , foldMany -- XXX Rename to foldRepeat
438 , parseMany
439 , arraysOf
441 -- * Buffered Operations
442 -- | Operations that require buffering of the stream.
443 -- Reverse is essentially a left fold followed by an unfold.
444 , reverse
445 , sortBy
447 -- * Multi-Stream folds
448 -- | Operations that consume multiple streams at the same time.
449 , eqBy
450 , cmpBy
451 , isPrefixOf
452 , isSubsequenceOf
454 -- trimming sequences
455 , stripPrefix
457 -- Exceptions and resource management depend on the "exceptions" package
458 -- XXX We can have IO Stream operations not depending on "exceptions"
459 -- in Exception.Base
461 -- * Exceptions
462 -- | Most of these combinators inhibit stream fusion, therefore, when
463 -- possible, they should be called in an outer loop to mitigate the cost.
464 -- For example, instead of calling them on a stream of chars call them on a
465 -- stream of arrays before flattening it to a stream of chars.
466 --
467 -- See also: "Streamly.Internal.Data.Stream.Exception" for
468 -- @Pre-release@ functions.
470 , onException
471 , handle
473 -- * Resource Management
474 -- | 'bracket' is the most general resource management operation, all other
475 -- operations can be expressed using it. These functions have IO suffix
476 -- because the allocation and cleanup functions are IO actions. For
477 -- generalized allocation and cleanup functions see the functions without
478 -- the IO suffix in the "streamly" package.
479 , before
480 , afterIO
481 , finallyIO
482 , bracketIO
483 , bracketIO3
485 -- * Transforming Inner Monad
487 , morphInner
488 , liftInner
489 , runReaderT
490 , runStateT
492 -- -- * Stream Types
493 -- $serial
494 -- , Interleave
495 -- , Zip
496 )
497where
499import Streamly.Internal.Data.Stream
500import Prelude
501 hiding (filter, drop, dropWhile, take, takeWhile, zipWith, foldr,
502 foldl, map, mapM, mapM_, sequence, all, any, sum, product, elem,
503 notElem, maximum, minimum, head, last, tail, length, null,
504 reverse, iterate, init, and, or, lookup, foldr1, (!!),
505 scanl, scanl1, repeat, replicate, concatMap, span)