on cd67584 help sign in
443 lines 14 kB history raw
1{-# OPTIONS_GHC -Wno-orphans #-}
3#include "inline.hs"
5-- |
6-- Module : Streamly.Data.Stream
7-- Copyright : (c) 2017 Composewell Technologies
8--
9-- License : BSD3
10-- Maintainer : streamly@composewell.com
11-- Stability : released
12-- Portability : GHC
13--
14-- To run examples in this module:
15--
16-- >>> import qualified Streamly.Data.Fold as Fold
17-- >>> import qualified Streamly.Data.Stream as Stream
18--
19-- We will add some more imports in the examples as needed.
20--
21-- For effectful streams we will use the following IO action:
22--
23-- >>> effect n = print n >> return n
24--
25-- = Overview
26--
27-- Streamly is a framework for modular data flow based programming and
28-- declarative concurrency. Powerful stream fusion framework in streamly
29-- allows high performance combinatorial programming even when using byte level
30-- streams. Streamly API is similar to Haskell lists.
31--
32-- Streams can be constructed
33-- like lists, except that they use 'nil' instead of '[]' and 'cons' instead of
34-- ':'.
35--
36-- `cons` constructs a pure stream which is more or less the same as a list:
37--
38-- >>> import Streamly.Data.Stream (Stream, cons, consM, nil)
39-- >>> stream = 1 `cons` 2 `cons` nil :: Stream IO Int
40-- >>> Stream.fold Fold.toList stream -- IO [Int]
41-- [1,2]
42--
43-- 'consM' constructs a stream from effectful actions:
44--
45-- >>> stream = effect 1 `consM` effect 2 `consM` nil
46-- >>> Stream.fold Fold.toList stream
47-- 1
48-- 2
49-- [1,2]
50--
51-- == Console Echo Example
52--
53-- In the following example, 'repeatM' generates an infinite stream of 'String'
54-- by repeatedly performing the 'getLine' IO action. 'mapM' then applies
55-- 'putStrLn' on each element in the stream converting it to stream of '()'.
56-- Finally, 'drain' folds the stream to IO discarding the () values, thus
57-- producing only effects.
58--
59-- >>> import Data.Function ((&))
60--
61-- >>> :{
62-- echo =
63-- Stream.repeat getLine -- Stream IO (IO String)
64-- & Stream.sequence -- Stream IO String
65-- & Stream.mapM putStrLn -- Stream IO ()
66-- & Stream.fold Fold.drain -- IO ()
67-- :}
68--
69-- This is a console echo program. It is an example of a declarative loop
70-- written using streaming combinators. Compare it with an imperative @while@
71-- loop.
72--
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
75-- "Data.List" like functions and many more powerful combinators to perform
76-- common programming tasks.
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--
82module Streamly.Data.Stream
83 (
84 Stream
85 -- * Construction
86 -- | Functions ending in the general shape @b -> Stream m a@.
87 --
88 -- See also: "Streamly.Internal.Data.Stream.Generate" for
89 -- @Pre-release@ functions.
91 -- ** Primitives
92 -- | Primitives to construct a stream from pure values or monadic actions.
93 -- All other stream construction and generation combinators described later
94 -- can be expressed in terms of these primitives. However, the special
95 -- versions provided in this module can be much more efficient in most
96 -- cases. Users can create custom combinators using these primitives.
97 , nil
98 , cons
99 , consM
100 -- , cons2 -- fused version
101 -- , consM2 -- fused version
103 -- ** Unfolding
104 -- | Generalized way of generating a stream efficiently.
105 , unfoldr
106 , unfoldrM
108 -- ** From Values
109 -- | Generate a monadic stream from a seed value or values.
110 , fromPure
111 , fromEffect
112 , repeat
113 , replicate
115 -- Note: Using enumeration functions e.g. 'Prelude.enumFromThen' turns out
116 -- to be slightly faster than the idioms like @[from, then..]@.
117 --
118 -- ** Enumeration
119 -- | We can use the 'Enum' type class to enumerate a type producing a list
120 -- and then convert it to a stream:
121 --
122 -- @
123 -- 'fromList' $ 'Prelude.enumFromThen' from then
124 -- @
125 --
126 -- However, this is not particularly efficient.
127 -- The 'Enumerable' type class provides corresponding functions that
128 -- generate a stream instead of a list, efficiently.
130 , Enumerable (..)
131 , enumerate
132 , enumerateTo
134 -- ** Iteration
135 , iterate
136 , iterateM
138 -- ** From Containers
139 -- | Convert an input structure, container or source into a stream. All of
140 -- these can be expressed in terms of primitives.
141 , fromList
142 , fromFoldable
144 -- ** From Unfolds
145 -- | Most of the above stream generation operations can also be expressed
146 -- using the corresponding unfolds in the "Streamly.Data.Unfold" module.
147 , unfold -- XXX rename to fromUnfold?
149 -- * Elimination
150 -- | Functions ending in the general shape @Stream m a -> m b@ or @Stream m
151 -- a -> m (b, Stream m a)@
152 --
153 -- See also: "Streamly.Internal.Data.Stream.Eliminate" for @Pre-release@
154 -- functions.
156-- EXPLANATION: In imperative terms a fold can be considered as a loop over the stream
157-- that reduces the stream to a single value.
158-- Left and right folds both use a fold function @f@ and an identity element
159-- @z@ (@zero@) to deconstruct a recursive data structure and reconstruct a
160-- new data structure. The new structure may be a recursive construction (a
161-- container) or a non-recursive single value reduction of the original
162-- structure.
163--
164-- Both right and left folds are mathematical duals of each other, they are
165-- functionally equivalent. Operationally, a left fold on a left associated
166-- structure behaves exactly in the same way as a right fold on a right
167-- associated structure. Similarly, a left fold on a right associated structure
168-- behaves in the same way as a right fold on a left associated structure.
169-- However, the behavior of a right fold on a right associated structure is
170-- operationally different (even though functionally equivalent) than a left
171-- fold on the same structure.
172--
173-- On right associated structures like Haskell @cons@ lists or Streamly
174-- streams, a lazy right fold is naturally suitable for lazy recursive
175-- reconstruction of a new structure, while a strict left fold is naturally
176-- suitable for efficient reduction. In right folds control is in the hand of
177-- the @puller@ whereas in left folds the control is in the hand of the
178-- @pusher@.
179--
180-- The behavior of right and left folds are described in detail in the
181-- individual fold's documentation. To illustrate the two folds for right
182-- associated @cons@ lists:
183--
184-- > foldr :: (a -> b -> b) -> b -> [a] -> b
185-- > foldr f z [] = z
186-- > foldr f z (x:xs) = x `f` foldr f z xs
187-- >
188-- > foldl :: (b -> a -> b) -> b -> [a] -> b
189-- > foldl f z [] = z
190-- > foldl f z (x:xs) = foldl f (z `f` x) xs
191--
192-- @foldr@ is conceptually equivalent to:
193--
194-- > foldr f z [] = z
195-- > foldr f z [x] = f x z
196-- > foldr f z xs = foldr f (foldr f z (tail xs)) [head xs]
197--
198-- @foldl@ is conceptually equivalent to:
199--
200-- > foldl f z [] = z
201-- > foldl f z [x] = f z x
202-- > foldl f z xs = foldl f (foldl f z (init xs)) [last xs]
203--
204-- Left and right folds are duals of each other.
205--
206-- @
207-- foldr f z xs = foldl (flip f) z (reverse xs)
208-- foldl f z xs = foldr (flip f) z (reverse xs)
209-- @
210--
211-- More generally:
212--
213-- @
214-- foldr f z xs = foldl g id xs z where g k x = k . f x
215-- foldl f z xs = foldr g id xs z where g x k = k . flip f x
216-- @
217--
219-- NOTE: Folds are inherently serial as each step needs to use the result of
220-- the previous step. However, it is possible to fold parts of the stream in
221-- parallel and then combine the results using a monoid.
223 -- ** Primitives
224 -- Consuming a part of the stream and returning the rest. Functions
225 -- ending in the general shape @Stream m a -> m (b, Stream m a)@
226 , uncons
228 -- ** Folding
229 , fold -- XXX rename to run? We can have a Stream.run and Fold.run.
230 -- XXX fold1 can be achieved using Monoids or Refolds.
231 , foldBreak
232 , foldContinue
234 -- ** Parsing
235 , parse
236 , parseBreak
238 -- -- ** Lazy Right Folds
239 -- Consuming a stream to build a right associated expression, suitable
240 -- for lazy evaluation. Evaluation of the input happens when the output of
241 -- the fold is evaluated, the fold output is a lazy thunk.
242 --
243 -- This is suitable for stream transformation operations, for example,
244 -- operations like mapping a function over the stream.
245 -- , foldrM
246 -- , foldr
248 -- * Mapping
249 -- | Stateless one-to-one transformations. Use 'fmap' for mapping a pure
250 -- function on a stream.
252 -- EXPLANATION:
253 -- In imperative terms a map operation can be considered as a loop over
254 -- the stream that transforms the stream into another stream by performing
255 -- an operation on each element of the stream.
256 --
257 -- 'map' is the least powerful transformation operation with strictest
258 -- guarantees. A map, (1) is a stateless loop which means that no state is
259 -- allowed to be carried from one iteration to another, therefore,
260 -- operations on different elements are guaranteed to not affect each
261 -- other, (2) is a strictly one-to-one transformation of stream elements
262 -- which means it guarantees that no elements can be added or removed from
263 -- the stream, it can merely transform them.
264 , sequence
265 , mapM
266 -- , trace -- XXX Use "tracing" map instead?
267 , tap
268 , delay
270 -- * Scanning
271 -- | Stateful one-to-one transformations.
272 --
273 -- See also: "Streamly.Internal.Data.Stream.Transform" for
274 -- @Pre-release@ functions.
275 , scan
276 , postscan
277 -- XXX postscan1 can be implemented using Monoids or Refolds.
278 -- Indexing can be considered as a special type of zipping where we zip a
279 -- stream with an index stream.
280 , indexed
281 , indexedR
283 -- * Insertion
284 -- | Add elements to the stream.
286 -- Inserting elements is a special case of interleaving/merging streams.
287 , insertBy
288 , intersperseM
289 , intersperse
291 -- * Filtering
292 -- | Remove elements from the stream.
294 -- ** Stateless Filters
295 -- EXPLANATION:
296 -- In imperative terms a filter over a stream corresponds to a loop with a
297 -- @continue@ clause for the cases when the predicate fails.
299 , mapMaybe
300 , mapMaybeM
301 , filter
302 , filterM
304 -- ** Stateful Filters
305 , take
306 , takeWhile
307 , takeWhileM
308 , drop
309 , dropWhile
310 , dropWhileM
311 , deleteBy
312 , uniq
314 -- ** Searching
315 -- Finding the presence or location of an element, a sequence of elements
316 -- or another stream within a stream.
318 -- -- ** Searching Elements
319 , findIndices
320 , elemIndices
322 -- * Combining Two Streams
323 -- ** Appending
324 , append
325 , append2
327 -- ** Interleaving
328 , interleave
329 -- , interleave2
331 -- ** Merging
332 -- | Merging of @n@ streams can be performed by combining the streams pair
333 -- wise using
334 -- 'Streamly.Internal.Data.Stream.IsStream.Expand.concatPairsWith' to give
335 -- O(n * log n) time complexity.
336 -- If used with 'concatMapWith' it will have O(n^2) performance.
338 , mergeBy
339 , mergeByM
340 -- , mergeBy2
341 -- , mergeByM2
343 -- ** Zipping
344 -- | Zipping of @n@ streams can be performed by combining the streams pair
345 -- wise using
346 -- 'Streamly.Internal.Data.Stream.IsStream.Expand.concatPairsWith' with
347 -- O(n * log n) time complexity.
348 -- If used with 'concatMapWith' it will have O(n^2) performance.
349 , zipWith
350 , zipWithM
351 -- , zipWith2
352 -- , zipWithM2
354 -- * Unfold Each
355 , unfoldMany
356 , intercalate
357 , intercalateSuffix
359 -- * Stream of streams
360 -- | Stream operations like map and filter represent loop processing in
361 -- imperative programming terms. Similarly, the imperative concept of
362 -- nested loops are represented by streams of streams. The 'concatMap'
363 -- operation represents nested looping.
364 -- A 'concatMap' operation loops over the input stream and then for each
365 -- element of the input stream generates another stream and then loops over
366 -- that inner stream as well producing effects and generating a single
367 -- output stream.
368 -- The 'Monad' instances of different stream types provide a more
369 -- convenient way of writing nested loops. Note that the monad bind
370 -- operation is just @flip concatMap@.
371 --
372 -- One dimension loops are just a special case of nested loops. For
373 -- example, 'concatMap' can degenerate to a simple map operation:
374 --
375 -- > map f m = S.concatMap (\x -> S.fromPure (f x)) m
376 --
377 -- Similarly, 'concatMap' can perform filtering by mapping an element to a
378 -- 'nil' stream:
379 --
380 -- > filter p m = S.concatMap (\x -> if p x then S.fromPure x else S.nil) m
381 --
383 , concatMapWith
384 , concatMap
385 , concatMapM
387 -- * Repeated Fold
388 , foldMany -- XXX Rename to foldRepeat
390 -- * Buffered Operations
391 -- | Operations that require buffering of the stream.
392 , reverse
394 -- * Multi-Stream folds
395 -- | Operations that consume multiple streams at the same time.
396 , eqBy
397 , cmpBy
398 , isPrefixOf
399 , isSubsequenceOf
401 -- trimming sequences
402 , stripPrefix
404 -- * Exceptions
405 -- | Most of these combinators inhibit stream fusion, therefore, when
406 -- possible, they should be called in an outer loop to mitigate the cost.
407 -- For example, instead of calling them on a stream of chars call them on a
408 -- stream of arrays before flattening it to a stream of chars.
409 --
410 -- See also: "Streamly.Internal.Data.Stream.Exception" for
411 -- @Pre-release@ functions.
413 , onException
414 , handle
416 -- * Resource Management
417 , before
418 , after
419 , finally
420 , bracket
422 -- * Lifting Inner Monad
423 -- | See also: "Streamly.Internal.Data.Stream.Lift" for
424 -- @Pre-release@ functions.
426 , liftInner
427 , runReaderT
428 , runStateT
430 -- -- * Stream Types
431 -- $serial
432 -- , Interleave
433 -- , Zip
434 )
435where
437import Streamly.Internal.Data.Stream
438import Prelude
439 hiding (filter, drop, dropWhile, take, takeWhile, zipWith, foldr,
440 foldl, map, mapM, mapM_, sequence, all, any, sum, product, elem,
441 notElem, maximum, minimum, head, last, tail, length, null,
442 reverse, iterate, init, and, or, lookup, foldr1, (!!),
443 scanl, scanl1, repeat, replicate, concatMap, span)