on e08ff86 help sign in
streamly/src/Streamly.hs
345 lines 11 kB history raw
1-- |
2-- Module : Streamly
3-- Copyright : (c) 2017 Harendra Kumar
4--
5-- License : BSD3
6-- Maintainer : harendra.kumar@gmail.com
7-- Stability : experimental
8-- Portability : GHC
9--
10-- The way a list represents a sequence of pure values, a stream represents a
11-- sequence of monadic actions. The monadic stream API offered by Streamly is
12-- very close to the Haskell "Prelude" pure lists' API, it can be considered as
13-- a natural extension of lists to monadic actions. Streamly streams provide
14-- concurrent composition and merging of streams. It can be considered as a
15-- concurrent list transformer. In contrast to the "Prelude" lists, merging or
16-- appending streams of arbitrary length is scalable and inexpensive.
17--
18-- The basic stream type is 'Serial', it represents a sequence of IO actions,
19-- and is a 'Monad'. The type 'SerialT' is a monad transformer that can
20-- represent a sequence of actions in an arbitrary monad. The type 'Serial' is
21-- in fact a synonym for @SerialT IO@. There are a few more types similar to
22-- 'SerialT', all of them represent a stream and differ only in the
23-- 'Semigroup', 'Applicative' and 'Monad' compositions of the stream. 'Serial'
24-- and 'WSerial' types compose serially whereas 'Async' and 'WAsync'
25-- types compose concurrently. All these types can be freely inter-converted
26-- using type combinators without any cost. You can freely switch to any type
27-- of composition at any point in the program. When no type annotation or
28-- explicit stream type combinators are used, the default stream type is
29-- inferred as 'Serial'.
30--
31-- Here is a simple console echo program example:
32--
33-- @
34-- > runStream $ S.repeatM getLine & S.mapM putStrLn
35-- @
36--
37-- For more details please see the "Streamly.Tutorial" module and the examples
38-- directory in this package.
39--
40-- This module exports stream types, instances and some basic operations.
41-- Functionality exported by this module include:
42--
43-- * Semigroup append ('<>') instances as well as explicit operations for merging streams
44-- * Monad and Applicative instances for looping over streams
45-- * Zip Applicatives for zipping streams
46-- * Stream type combinators to convert between different composition styles
47-- * Some basic utilities to run and fold streams
48--
49-- See the "Streamly.Prelude" module for comprehensive APIs for construction,
50-- generation, elimination and transformation of streams.
51--
52-- This module is designed to be imported unqualified:
53--
54-- @
55-- import Streamly
56-- @
58{-# LANGUAGE CPP #-}
60#if __GLASGOW_HASKELL__ >= 800
61{-# OPTIONS_GHC -Wno-orphans #-}
62#endif
64#include "Streamly/Streams/inline.hs"
66module Streamly
67 (
68 MonadAsync
70 -- * Stream transformers
71 -- ** Serial Streams
72 -- $serial
73 , SerialT
74 , WSerialT
76 -- ** Concurrent Lookahead Streams
77 -- $lookahead
78 , AheadT
80 -- ** Concurrent Asynchronous Streams
81 -- $async
82 , AsyncT
83 , WAsyncT
84 , ParallelT
86 -- ** Zipping Streams
87 -- $zipping
88 , ZipSerialM
89 , ZipAsyncM
91 -- * Running Streams
92 , runStream
94 -- * Parallel Function Application
95 -- $application
96 , (|$)
97 , (|&)
98 , (|$.)
99 , (|&.)
100 , mkAsync
102 -- * Merging Streams
103 -- $sum
104 , serial
105 , wSerial
106 , ahead
107 , async
108 , wAsync
109 , parallel
111 -- * Concurrency Control
112 -- $concurrency
113 , maxThreads
114 , maxBuffer
116 -- * Rate Limiting
117 , Rate (..)
118 , rate
119 , avgRate
120 , minRate
121 , maxRate
122 , constRate
124 -- * Folding Containers of Streams
125 -- $foldutils
126 , foldWith
127 , foldMapWith
128 , forEachWith
130 -- * Stream Type Adapters
131 -- $adapters
132 , IsStream ()
134 , serially
135 , wSerially
136 , asyncly
137 , aheadly
138 , wAsyncly
139 , parallely
140 , zipSerially
141 , zipAsyncly
142 , adapt
144 -- * IO Streams
145 , Serial
146 , WSerial
147 , Ahead
148 , Async
149 , WAsync
150 , Parallel
151 , ZipSerial
152 , ZipAsync
154 -- * Re-exports
155 , Semigroup (..)
156 -- * Deprecated
157 , Streaming
158 , runStreaming
159 , runStreamT
160 , runInterleavedT
161 , runAsyncT
162 , runParallelT
163 , runZipStream
164 , runZipAsync
165 , StreamT
166 , InterleavedT
167 , ZipStream
168 , interleaving
169 , zipping
170 , zippingAsync
171 , (<=>)
172 , (<|)
173 )
174where
176import Data.Semigroup (Semigroup(..))
177import Streamly.SVar (MonadAsync, Rate(..))
178import Streamly.Streams.Ahead
179import Streamly.Streams.Async
180import Streamly.Streams.Combinators
181import Streamly.Streams.Parallel
182import Streamly.Streams.Prelude
183import Streamly.Streams.Serial
184import Streamly.Streams.StreamK hiding (runStream, serial)
185import Streamly.Streams.Zip
187import qualified Streamly.Streams.StreamD as D
188import qualified Streamly.Streams.StreamK as K
190-- XXX This should perhaps be moved to Prelude.
192------------------------------------------------------------------------------
193-- Eliminating a stream
194------------------------------------------------------------------------------
196-- | Run a streaming composition, discard the results. By default it interprets
197-- the stream as 'SerialT', to run other types of streams use the type adapting
198-- combinators for example @runStream . 'asyncly'@.
199--
200-- @since 0.2.0
201{-# INLINE_EARLY runStream #-}
202runStream :: Monad m => SerialT m a -> m ()
203runStream m = D.runStream $ D.fromStreamK (toStream m)
204{-# RULES "runStream fallback to CPS" [1]
205 forall a. D.runStream (D.fromStreamK a) = K.runStream a #-}
207-- | Same as 'runStream'
208--
209-- @since 0.1.0
210{-# DEPRECATED runStreaming "Please use runStream instead." #-}
211runStreaming :: (Monad m, IsStream t) => t m a -> m ()
212runStreaming = runStream . K.adapt
214-- | Same as @runStream@.
215--
216-- @since 0.1.0
217{-# DEPRECATED runStreamT "Please use runStream instead." #-}
218runStreamT :: Monad m => SerialT m a -> m ()
219runStreamT = runStream
221-- | Same as @runStream . wSerially@.
222--
223-- @since 0.1.0
224{-# DEPRECATED runInterleavedT "Please use 'runStream . interleaving' instead." #-}
225runInterleavedT :: Monad m => WSerialT m a -> m ()
226runInterleavedT = runStream . K.adapt
228-- | Same as @runStream . parallely@.
229--
230-- @since 0.1.0
231{-# DEPRECATED runParallelT "Please use 'runStream . parallely' instead." #-}
232runParallelT :: Monad m => ParallelT m a -> m ()
233runParallelT = runStream . K.adapt
235-- | Same as @runStream . asyncly@.
236--
237-- @since 0.1.0
238{-# DEPRECATED runAsyncT "Please use 'runStream . asyncly' instead." #-}
239runAsyncT :: Monad m => AsyncT m a -> m ()
240runAsyncT = runStream . K.adapt
242-- | Same as @runStream . zipping@.
243--
244-- @since 0.1.0
245{-# DEPRECATED runZipStream "Please use 'runStream . zipSerially instead." #-}
246runZipStream :: Monad m => ZipSerialM m a -> m ()
247runZipStream = runStream . K.adapt
249-- | Same as @runStream . zippingAsync@.
250--
251-- @since 0.1.0
252{-# DEPRECATED runZipAsync "Please use 'runStream . zipAsyncly instead." #-}
253runZipAsync :: Monad m => ZipAsyncM m a -> m ()
254runZipAsync = runStream . K.adapt
256------------------------------------------------------------------------------
257-- Documentation
258------------------------------------------------------------------------------
260-- $serial
261--
262-- Serial streams compose serially or non-concurrently. In a composed stream,
263-- each action is executed only after the previous action has finished. The two
264-- serial stream types 'SerialT' and 'WSerialT' differ in how they traverse the
265-- streams in a 'Semigroup' or 'Monad' composition.
267-- $async
268--
269-- The async style streams execute actions asynchronously and consume the
270-- outputs as well asynchronously. In a composed stream, at any point of time
271-- more than one stream can run concurrently and yield elements. The elements
272-- are yielded by the composed stream as they are generated by the constituent
273-- streams on a first come first serve basis. Therefore, on each run the
274-- stream may yield elements in a different sequence depending on the delays
275-- introduced by scheduling. The two async types 'AsyncT' and 'WAsyncT' differ
276-- in how they traverse streams in 'Semigroup' or 'Monad' compositions.
278-- $zipping
279--
280-- 'ZipSerialM' and 'ZipAsyncM', provide 'Applicative' instances for zipping the
281-- corresponding elements of two streams together. Note that these types are
282-- not monads.
284-- $application
285--
286-- Stream processing functions can be composed in a chain using function
287-- application with or without the '$' operator, or with reverse function
288-- application operator '&'. Streamly provides concurrent versions of these
289-- operators applying stream processing functions such that each stage of the
290-- stream can run in parallel. The operators start with a @|@; we can read '|$'
291-- as "@parallel dollar@" to remember that @|@ comes before '$'.
292--
293-- Imports for the code snippets below:
294--
295-- @
296-- import Streamly
297-- import qualified Streamly.Prelude as S
298-- import Control.Concurrent
299-- @
301-- $sum
302-- The 'Semigroup' operation '<>' of each stream type combines two streams in a
303-- type specific manner. This section provides polymorphic versions of '<>'
304-- which can be used to combine two streams in a predetermined way irrespective
305-- of the type.
307-- XXX An alternative design choice would be to let a control parameter affect
308-- the nearest SVar only and then it gets cleared. The benefit of the current
309-- choice is that it is simply just like global configuration, just like state
310-- behaves, so should be easy to comprehend. But it has the downside of leaking
311-- to undesired actions, that is we can forget to reset it.
312--
313-- $concurrency
314--
315-- These combinators can be used at any point in a stream composition to set
316-- parameters to control the concurrency of the enclosed stream. A parameter
317-- set at any point remains effective for any concurrent combinators used
318-- downstream until it is reset. These control parameters have no effect on
319-- non-concurrent combinators in the stream, or on non-concurrent streams. They
320-- also do not affect 'Parallel' streams, as concurrency for 'Parallel' streams
321-- is always unbounded.
323-- $adapters
324--
325-- You may want to use different stream composition styles at different points
326-- in your program. Stream types can be freely converted or adapted from one
327-- type to another. The 'IsStream' type class facilitates type conversion of
328-- one stream type to another. It is not used directly, instead the type
329-- combinators provided below are used for conversions.
330--
331-- To adapt from one monomorphic type (e.g. 'AsyncT') to another monomorphic
332-- type (e.g. 'SerialT') use the 'adapt' combinator. To give a polymorphic code
333-- a specific interpretation or to adapt a specific type to a polymorphic type
334-- use the type specific combinators e.g. 'asyncly' or 'wSerially'. You
335-- cannot adapt polymorphic code to polymorphic code, as the compiler would not know
336-- which specific type you are converting from or to. If you see a an
337-- @ambiguous type variable@ error then most likely you are using 'adapt'
338-- unnecessarily on polymorphic code.
339--
341-- $foldutils
342--
343-- These are variants of standard 'Foldable' fold functions that use a
344-- polymorphic stream sum operation (e.g. 'async' or 'wSerial') to fold a
345-- container of streams.