on 42df609 help sign in
streamly/src/Streamly.hs
249 lines 9.1 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
10module Streamly
11 (
12 -- * Background
13 -- $background
15 -- * Overview
16 -- $overview
18 MonadAsync
19 , Streaming
21 -- * Product Style Composition
22 -- $product
23 , StreamT
24 , InterleavedT
25 , AsyncT
26 , ParallelT
28 -- * Zip Style Composition
29 -- $zipping
30 , ZipStream
31 , ZipAsync
33 -- * Sum Style Composition
34 -- $sum
35 , (<=>)
36 , (<|)
38 -- * Transformation
39 , async
41 -- * Stream Type Adapters
42 -- $adapters
43 , serially
44 , interleaving
45 , asyncly
46 , parallely
47 , zipping
48 , zippingAsync
49 , adapt
51 -- * Running Streams
52 , runStreaming
53 , runStreamT
54 , runInterleavedT
55 , runAsyncT
56 , runParallelT
57 , runZipStream
58 , runZipAsync
60 -- * Fold Utilities
61 -- $foldutils
62 , foldWith
63 , foldMapWith
64 , forEachWith
66 -- * Re-exports
67 , Monoid (..)
68 , Semigroup (..)
69 , Alternative (..)
70 , MonadPlus (..)
71 , MonadIO (..)
72 , MonadTrans (..)
73 )
74where
76import Streamly.Streams
77import Data.Semigroup (Semigroup(..))
78import Control.Applicative (Alternative(..))
79import Control.Monad (MonadPlus(..))
80import Control.Monad.IO.Class (MonadIO (..))
81import Control.Monad.Trans.Class (MonadTrans (..))
83-- $background
84--
85-- Streamly provides a monad transformer that extends the product style
86-- composition of monads to streams of many elements of the same type; it is a
87-- functional programming equivalent of nested loops from imperative
88-- programming. Composing each element in one stream with each element in the
89-- other stream generalizes the monadic product of single elements. You can
90-- think of the IO monad as a special case of the more general @StreamT IO@
91-- monad; with single element streams. List transformers and logic programming
92-- monads also provide a similar product style composition of streams, however
93-- streamly generalizes it with the time dimension; allowing streams to be
94-- composed in an asynchronous and concurrent fashion in many different ways.
95-- It also provides multiple alternative ways of composing streams e.g.
96-- serial, interleaved or concurrent.
97--
98-- The seemingly simple addition of asynchronicity and concurrency to product
99-- style streaming composition unifies a number of disparate abstractions into
100-- one powerful and elegant abstraction. A wide variety of programming
101-- problems can be solved elegantly with this abstraction. In particular, it
102-- unifies three major programming domains namely non-deterministic (logic)
103-- programming, concurrent programming and functional reactive programming. In
104-- other words, you can do everything with this one abstraction that you could
105-- with list transformers (e.g.
106-- <https://hackage.haskell.org/package/list-t list-t>), logic programming
107-- monads (e.g. <https://hackage.haskell.org/package/logict logict>),
108-- streaming libraries (a lot of what
109-- <https://hackage.haskell.org/package/conduit conduit> or
110-- <https://hackage.haskell.org/package/pipes pipes> can do), concurrency
111-- libraries (e.g. <https://hackage.haskell.org/package/async async>) and FRP
112-- libraries (e.g. <https://hackage.haskell.org/package/Yampa Yampa> or
113-- <https://hackage.haskell.org/package/reflex reflex>).
115-- $overview
116--
117-- Streamly provides six distinct stream types i.e. 'StreamT', 'InterleavedT',
118-- 'AsyncT' and 'ParallelT', 'ZipStream' and 'ZipAsync', each representing a
119-- stream of elements. All these types have the same underlying representation
120-- and can be adapted from one to another using type adaptor combinators
121-- described later. Each of these types belongs to the 'Streaming' type class
122-- which helps converting the specific type to and from the underlying generic
123-- stream type.
124--
125-- The types 'StreamT', 'InterleavedT', 'AsyncT' and 'ParallelT' are 'Monad'
126-- transformers with the monadic bind operation combining streams in a product
127-- style in much the same way as a list monad or a list transformer i.e. each
128-- element from one stream is combined with every element of the other stream.
129-- However, the applicative and monadic composition of these types differ in
130-- terms of the ordering and time sequence in which the elements from two
131-- streams are combined. 'StreamT' and 'InterleavedT' compose streams serially
132-- whereas 'AsyncT' and 'ParallelT' are their concurrent counterparts. See the
133-- documentation of the respective types for more details.
134--
135-- The types 'ZipStream' and 'ZipAsync' provide 'Applicative' instances to zip
136-- two streams together i.e. each element in one stream is combined with the
137-- corresponding element in the other stream. 'ZipStream' generates the streams
138-- being zipped serially whereas 'ZipAsync' produces both the elements being
139-- zipped concurrently.
140--
141-- Two streams of the same type can be combined using a sum style composition
142-- to generate a stream of the same type where the output stream would contain
143-- all elements of both the streams. However, the sequence in which the
144-- elements in the resulting stream are produced depends on the combining
145-- operator. Four distinct sum style operators, '<>', '<=>', '<|' and '<|>'
146-- combine two streams in different ways, each corresponding to the one of the
147-- four ways of combining monadically. See the respective section below for
148-- more details.
149--
150-- Concurrent composition types 'AsyncT', 'ParallelT', 'ZipAsync' and
151-- concurrent composition operators '<|' and '<|>' require the underlying monad
152-- of the streaming monad transformer to be 'MonadAsync'.
153--
154-- For more details please see the "Streamly.Tutorial" and "Streamly.Examples"
155-- (the latter is available only when built with the 'examples' build flag).
157-- A simple inline example here illustrating applicative, monad and alternative
158-- compositions.
160-- $product
161--
162-- Streams that compose serially or non-concurrently come in two flavors i.e.
163-- 'StreamT' and 'InterleavedT'. Both of these serial flavors have
164-- corresponding concurrent equivalents, those are 'AsyncT' and 'ParallelT'
165-- respectively.
167-- $zipping
168--
169-- 'ZipStream' and 'ZipAsync', provide 'Applicative' instances for zipping the
170-- corresponding elements of two streams together. Note that these types are
171-- not monads.
173-- $sum
174--
175-- Just like product style composition there are four distinct ways to combine
176-- streams in sum style each directly corresponding to one of the product style
177-- composition.
178--
179-- The standard semigroup append '<>' operator appends two streams serially,
180-- this style corresponds to the 'StreamT' style of monadic composition.
181--
182-- @
183-- main = ('toList' . 'serially' $ (return 1 <> return 2) <> (return 3 <> return 4)) >>= print
184-- @
185-- @
186-- [1,2,3,4]
187-- @
188--
189-- The standard 'Alternative' operator '<|>' fairly interleaves two streams in
190-- parallel, this operator corresponds to the 'ParallelT' style.
191--
192-- @
193-- main = ('toList' . 'serially' $ (return 1 <> return 2) \<|\> (return 3 <> return 4)) >>= print
194-- @
195-- @
196-- [1,3,2,4]
197-- @
198--
199-- Unlike '<|', this operator cannot be used to fold infinite containers since
200-- that might accumulate too many partially drained streams. To be clear, it
201-- can combine infinite streams but not infinite number of streams.
202--
203-- Two additional sum style composition operators that streamly introduces are
204-- described below.
206-- $adapters
207--
208-- Code using streamly is usually written such that it is agnostic of any
209-- specific streaming type. We use a type variable (polymorphic type) with the
210-- 'Streaming' class constraint. Finally, when running the monad we can specify
211-- the actual type that we want to use to interpret the code. However, in
212-- certain cases we may want to use a specific type to force a certain type of
213-- composition. These combinators can be used to convert the stream types from
214-- one to another at no cost as all the types have the same underlying
215-- representation.
216--
217-- If you see an @ambiguous type variable@ error then most likely it is because
218-- you have not specified the stream type. You either need a type annotation or
219-- one of the following combinators to specify what type of stream you mean.
220--
221-- This code:
222--
223-- @
224-- main = ('toList' $ (return 1 <> return 2)) >>= print
225-- @
226--
227-- will result in a type error like this:
228--
229-- @
230-- Ambiguous type variable ‘t0’ arising from a use of ...
231-- @
232--
233-- To fix the error just tell 'toList' what kind of stream are we feeding it:
234--
235-- @
236-- main = ('toList' $ 'serially' $ (return 1 <> return 2)) >>= print
237-- @
238-- @
239-- main = ('toList' $ (return 1 <> return 2 :: StreamT IO Int)) >>= print
240-- @
241--
242-- Note that using the combinators is easier as you do not have to think about
243-- the specific types, they are just inferred.
244--
246-- $foldutils
247--
248-- These are some convenience functions to fold any 'Foldable' container using
249-- one of the sum composition operators to convert it into a streamly stream.