on 89b95bd help sign in
472 lines 15 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 like lists, except that they use 'nil' instead of
33-- '[]' and 'cons' instead of ':'.
34--
35-- `cons` adds a pure value at the head of the stream:
36--
37-- >>> import Streamly.Data.Stream (Stream, cons, consM, nil)
38-- >>> stream = 1 `cons` 2 `cons` nil :: Stream IO Int
39-- >>> Stream.fold Fold.toList stream -- IO [Int]
40-- [1,2]
41--
42-- `consM` adds an effect at the head of the stream:
43--
44-- >>> stream = effect 1 `consM` effect 2 `consM` nil
45-- >>> Stream.fold Fold.toList stream
46-- 1
47-- 2
48-- [1,2]
49--
50-- == Console Echo Example
51--
52-- In the following example, 'repeatM' generates an infinite stream of 'String'
53-- by repeatedly performing the 'getLine' IO action. 'mapM' then applies
54-- 'putStrLn' on each element in the stream converting it to stream of '()'.
55-- Finally, 'drain' folds the stream to IO discarding the () values, thus
56-- producing only effects.
57--
58-- >>> import Data.Function ((&))
59--
60-- >>> :{
61-- echo =
62-- Stream.repeatM getLine -- Stream IO String
63-- & Stream.mapM putStrLn -- Stream IO ()
64-- & Stream.fold Fold.drain -- IO ()
65-- :}
66--
67-- This is a console echo program. It is an example of a declarative loop
68-- written using streaming combinators. Compare it with an imperative @while@
69-- loop.
70--
71-- Hopefully, this gives you an idea how we can program declaratively by
72-- representing loops using streams. In this module, you can find all
73-- "Data.List" like functions and many more powerful combinators to perform
74-- common programming tasks.
75--
76-- == Useful Idioms
77--
78-- >>> fromListM = Stream.sequence . Stream.fromList
79-- >>> fromFoldableM = Stream.sequence . Stream.fromFoldable
80-- >>> fromIndices f = fmap f $ Stream.enumerateFrom 0
81--
82-- Also see "Streamly.Internal.Data.Stream" module for many more @Pre-release@
83-- combinators. See the <https://github.com/composewell/streamly-examples>
84-- repository for many more real world examples of stream programming.
85--
86module Streamly.Data.Stream
87 (
88 Stream
89 -- * Construction
90 -- | Functions ending in the general shape @b -> Stream m a@.
91 --
92 -- See also: "Streamly.Internal.Data.Stream.Generate" for
93 -- @Pre-release@ functions.
95 -- ** Primitives
96 -- | Primitives to construct a stream from pure values or monadic actions.
97 -- All other stream construction and generation combinators described later
98 -- can be expressed in terms of these primitives. However, the special
99 -- versions provided in this module can be much more efficient in most
100 -- cases. Users can create custom combinators using these primitives.
101 , nil
102 , nilM
103 , cons
104 , consM
105 -- , cons2 -- fused version
106 -- , consM2 -- fused version
108 -- ** Unfolding
109 -- | 'unfoldrM' is the most general way of generating a stream efficiently.
110 -- All other generation operations can be expressed using it.
111 , unfoldr
112 , unfoldrM
114 -- ** From Values
115 -- | Generate a monadic stream from a seed value or values.
116 , fromPure
117 , fromEffect
118 , repeat
119 , repeatM
120 , replicate
121 , replicateM
123 -- Note: Using enumeration functions e.g. 'Prelude.enumFromThen' turns out
124 -- to be slightly faster than the idioms like @[from, then..]@.
125 --
126 -- ** Enumeration
127 -- | We can use the 'Enum' type class to enumerate a type producing a list
128 -- and then convert it to a stream:
129 --
130 -- @
131 -- 'fromList' $ 'Prelude.enumFromThen' from then
132 -- @
133 --
134 -- However, this is not particularly efficient.
135 -- The 'Enumerable' type class provides corresponding functions that
136 -- generate a stream instead of a list, efficiently.
138 , Enumerable (..)
139 , enumerate
140 , enumerateTo
142 -- ** Iteration
143 , iterate
144 , iterateM
146 -- ** From Containers
147 -- | Convert an input structure, container or source into a stream. All of
148 -- these can be expressed in terms of primitives.
149 , fromList
150 , fromFoldable
152 -- ** From Unfolds
153 -- | Most of the above stream generation operations can also be expressed
154 -- using the corresponding unfolds in the "Streamly.Data.Unfold" module.
155 , unfold -- XXX rename to fromUnfold?
157 -- * Elimination
158 -- | Functions ending in the general shape @Stream m a -> m b@ or @Stream m
159 -- a -> m (b, Stream m a)@
160 --
161 -- See also: "Streamly.Internal.Data.Stream.Eliminate" for @Pre-release@
162 -- functions.
164-- EXPLANATION: In imperative terms a fold can be considered as a loop over the stream
165-- that reduces the stream to a single value.
166-- Left and right folds both use a fold function @f@ and an identity element
167-- @z@ (@zero@) to deconstruct a recursive data structure and reconstruct a
168-- new data structure. The new structure may be a recursive construction (a
169-- container) or a non-recursive single value reduction of the original
170-- structure.
171--
172-- Both right and left folds are mathematical duals of each other, they are
173-- functionally equivalent. Operationally, a left fold on a left associated
174-- structure behaves exactly in the same way as a right fold on a right
175-- associated structure. Similarly, a left fold on a right associated structure
176-- behaves in the same way as a right fold on a left associated structure.
177-- However, the behavior of a right fold on a right associated structure is
178-- operationally different (even though functionally equivalent) than a left
179-- fold on the same structure.
180--
181-- On right associated structures like Haskell @cons@ lists or Streamly
182-- streams, a lazy right fold is naturally suitable for lazy recursive
183-- reconstruction of a new structure, while a strict left fold is naturally
184-- suitable for efficient reduction. In right folds control is in the hand of
185-- the @puller@ whereas in left folds the control is in the hand of the
186-- @pusher@.
187--
188-- The behavior of right and left folds are described in detail in the
189-- individual fold's documentation. To illustrate the two folds for right
190-- associated @cons@ lists:
191--
192-- > foldr :: (a -> b -> b) -> b -> [a] -> b
193-- > foldr f z [] = z
194-- > foldr f z (x:xs) = x `f` foldr f z xs
195-- >
196-- > foldl :: (b -> a -> b) -> b -> [a] -> b
197-- > foldl f z [] = z
198-- > foldl f z (x:xs) = foldl f (z `f` x) xs
199--
200-- @foldr@ is conceptually equivalent to:
201--
202-- > foldr f z [] = z
203-- > foldr f z [x] = f x z
204-- > foldr f z xs = foldr f (foldr f z (tail xs)) [head xs]
205--
206-- @foldl@ is conceptually equivalent to:
207--
208-- > foldl f z [] = z
209-- > foldl f z [x] = f z x
210-- > foldl f z xs = foldl f (foldl f z (init xs)) [last xs]
211--
212-- Left and right folds are duals of each other.
213--
214-- @
215-- foldr f z xs = foldl (flip f) z (reverse xs)
216-- foldl f z xs = foldr (flip f) z (reverse xs)
217-- @
218--
219-- More generally:
220--
221-- @
222-- foldr f z xs = foldl g id xs z where g k x = k . f x
223-- foldl f z xs = foldr g id xs z where g x k = k . flip f x
224-- @
225--
227-- NOTE: Folds are inherently serial as each step needs to use the result of
228-- the previous step. However, it is possible to fold parts of the stream in
229-- parallel and then combine the results using a monoid.
231 -- ** Primitives
232 -- Consuming a part of the stream and returning the rest. Functions
233 -- ending in the general shape @Stream m a -> m (b, Stream m a)@
234 , uncons
236 -- ** Folding
237 -- XXX Need to have a general parse operation here which can be used to
238 -- express all others.
239 , fold -- XXX rename to run? We can have a Stream.run and Fold.run.
240 -- XXX fold1 can be achieved using Monoids or Refolds.
241 , foldBreak
243 -- * Builders
244 , build
245 -- , buildl
247 -- ** Parsing
248 , parse
249 , parseBreak
251 -- -- ** Lazy Right Folds
252 -- Consuming a stream to build a right associated expression, suitable
253 -- for lazy evaluation. Evaluation of the input happens when the output of
254 -- the fold is evaluated, the fold output is a lazy thunk.
255 --
256 -- This is suitable for stream transformation operations, for example,
257 -- operations like mapping a function over the stream.
258 -- , foldrM
259 -- , foldr
261 -- * Mapping
262 -- | Stateless one-to-one transformations. Use 'fmap' for mapping a pure
263 -- function on a stream.
265 -- EXPLANATION:
266 -- In imperative terms a map operation can be considered as a loop over
267 -- the stream that transforms the stream into another stream by performing
268 -- an operation on each element of the stream.
269 --
270 -- 'map' is the least powerful transformation operation with strictest
271 -- guarantees. A map, (1) is a stateless loop which means that no state is
272 -- allowed to be carried from one iteration to another, therefore,
273 -- operations on different elements are guaranteed to not affect each
274 -- other, (2) is a strictly one-to-one transformation of stream elements
275 -- which means it guarantees that no elements can be added or removed from
276 -- the stream, it can merely transform them.
277 , sequence
278 , mapM
279 -- , trace -- XXX Use "tracing" map instead?
280 , tap
281 , delay
283 -- * Scanning
284 -- | Stateful one-to-one transformations.
285 --
286 -- See also: "Streamly.Internal.Data.Stream.Transform" for
287 -- @Pre-release@ functions.
288 , scan
289 , postscan
290 -- XXX postscan1 can be implemented using Monoids or Refolds.
291 -- Indexing can be considered as a special type of zipping where we zip a
292 -- stream with an index stream.
293 , indexed
295 -- * Insertion
296 -- | Add elements to the stream.
298 -- Inserting elements is a special case of interleaving/merging streams.
299 , insertBy
300 , intersperseM
301 , intersperseM_
302 , intersperse
304 -- * Filtering
305 -- | Remove elements from the stream.
307 -- ** Stateless Filters
308 -- | 'mapMaybeM' is the most general stateless filtering operation. All
309 -- other filtering operations can be expressed using it.
311 -- EXPLANATION:
312 -- In imperative terms a filter over a stream corresponds to a loop with a
313 -- @continue@ clause for the cases when the predicate fails.
315 , mapMaybe
316 , mapMaybeM
317 , filter
318 , filterM
319 , catMaybes
321 -- ** Stateful Filters
322 -- | 'scanMaybe' is the most general stateful filtering operation. The
323 -- filtering folds (folds returning a 'Maybe' type) in
324 -- "Streamly.Internal.Data.Fold" can be used along with 'scanMaybe' to
325 -- perform stateful filtering operations in general.
326 , scanMaybe
327 , take
328 , takeWhile
329 , takeWhileM
330 , drop
331 , dropWhile
332 , dropWhileM
333 , deleteBy
334 , uniq
336 -- * Either Streams
337 , catLefts
338 , catRights
339 , catEithers
341 -- ** Searching
342 -- Finding the presence or location of an element, a sequence of elements
343 -- or another stream within a stream.
345 -- -- ** Searching Elements
346 , findIndices
347 , elemIndices
349 -- * Combining Two Streams
350 -- ** Appending
351 , append
353 -- ** Interleaving
354 , interleave
355 -- , interleave2
357 -- ** Merging
358 -- | Merging of @n@ streams can be performed by combining the streams pair
359 -- wise using
360 -- 'Streamly.Internal.Data.Stream.IsStream.Expand.concatPairsWith' to give
361 -- O(n * log n) time complexity.
362 -- If used with 'concatMapWith' it will have O(n^2) performance.
364 , mergeBy
365 , mergeByM
366 -- , mergeBy2
367 -- , mergeByM2
369 -- ** Zipping
370 -- | Zipping of @n@ streams can be performed by combining the streams pair
371 -- wise using
372 -- 'Streamly.Internal.Data.Stream.IsStream.Expand.concatPairsWith' with
373 -- O(n * log n) time complexity.
374 -- If used with 'concatMapWith' it will have O(n^2) performance.
375 , zipWith
376 , zipWithM
377 -- , zipWith2
378 -- , zipWithM2
380 -- * Unfold Each
381 , unfoldMany
382 , intercalate
383 , intercalateSuffix
385 -- * Stream of streams
386 -- | Stream operations like map and filter represent loop processing in
387 -- imperative programming terms. Similarly, the imperative concept of
388 -- nested loops are represented by streams of streams. The 'concatMap'
389 -- operation represents nested looping.
390 -- A 'concatMap' operation loops over the input stream and then for each
391 -- element of the input stream generates another stream and then loops over
392 -- that inner stream as well producing effects and generating a single
393 -- output stream.
394 --
395 -- One dimension loops are just a special case of nested loops. For
396 -- example, 'concatMap' can degenerate to a simple map operation:
397 --
398 -- > map f m = S.concatMap (\x -> S.fromPure (f x)) m
399 --
400 -- Similarly, 'concatMap' can perform filtering by mapping an element to a
401 -- 'nil' stream:
402 --
403 -- > filter p m = S.concatMap (\x -> if p x then S.fromPure x else S.nil) m
404 --
406 , concatEffect
407 , concatMapWith
408 , concatMap
409 , concatMapM
411 -- * Repeated Fold
412 , foldMany -- XXX Rename to foldRepeat
413 , parseMany
415 -- * Buffered Operations
416 -- | Operations that require buffering of the stream.
417 -- Reverse is essentially a left fold followed by an unfold.
418 , reverse
420 -- * Multi-Stream folds
421 -- | Operations that consume multiple streams at the same time.
422 , eqBy
423 , cmpBy
424 , isPrefixOf
425 , isSubsequenceOf
427 -- trimming sequences
428 , stripPrefix
430 -- * Exceptions
431 -- | Most of these combinators inhibit stream fusion, therefore, when
432 -- possible, they should be called in an outer loop to mitigate the cost.
433 -- For example, instead of calling them on a stream of chars call them on a
434 -- stream of arrays before flattening it to a stream of chars.
435 --
436 -- See also: "Streamly.Internal.Data.Stream.Exception" for
437 -- @Pre-release@ functions.
439 , onException
440 , handle
442 -- * Resource Management
443 -- | 'bracket' is the most general resource management operation, all other
444 -- operations can be expressed using it.
445 , before
446 , afterIO
447 , finallyIO
448 , bracketIO
449 , bracket3IO
451 -- * Lifting Inner Monad
452 -- | See also: "Streamly.Internal.Data.Stream.Lift" for
453 -- @Pre-release@ functions.
455 , liftInner
456 , runReaderT
457 , runStateT
459 -- -- * Stream Types
460 -- $serial
461 -- , Interleave
462 -- , Zip
463 )
464where
466import Streamly.Internal.Data.Stream
467import Prelude
468 hiding (filter, drop, dropWhile, take, takeWhile, zipWith, foldr,
469 foldl, map, mapM, mapM_, sequence, all, any, sum, product, elem,
470 notElem, maximum, minimum, head, last, tail, length, null,
471 reverse, iterate, init, and, or, lookup, foldr1, (!!),
472 scanl, scanl1, repeat, replicate, concatMap, span)