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