on master help sign in
update documentation
328365eHarendra Kumar
Changelog.md+3−3
@@ -10,8 +10,8 @@
10* Fixed a race due to which, in a rare case, we might block indefinitely on
10* Fixed a race due to which, in a rare case, we might block indefinitely on
11 an MVar due to a lost wakeup.
11 an MVar due to a lost wakeup.
12* Fixed an issue in adaptive concurrency. The issue caused us to stop creating
12* Fixed an issue in adaptive concurrency. The issue caused us to stop creating
13− more worker threads in some cases due to a race. This would not cause any
13+ more worker threads in some cases due to a race. This bug would not cause any
14− functional issue but would reduce concurrency in some cases.
14+ functional issue but may reduce concurrency in some cases.
15
15
16### Enhancements
16### Enhancements
17* Added a concurrent lookahead stream type `Ahead`
17* Added a concurrent lookahead stream type `Ahead`
@@ -24,7 +24,7 @@
24 concurrently when used at appropriate stream types.
24 concurrently when used at appropriate stream types.
25* Added concurrent function application operators to run stages of a
25* Added concurrent function application operators to run stages of a
26 stream processing function application pipeline concurrently.
26 stream processing function application pipeline concurrently.
27−* Added two functions `mapMaybe` and `mapMaybeM`.
27+* Added `mapMaybe` and `mapMaybeM`.
28
28
29## 0.2.1
29## 0.2.1
30
30
README.md+27−5
@@ -91,9 +91,26 @@ main = runStream $
91
91
92## Concurrent Stream Generation
92## Concurrent Stream Generation
93
93
94−We can use standard monadic stream generation APIs like `repeatM`,
94+Monadic construction and generation functions e.g. `consM`, `unfoldrM`,
95−`replicateM`, `unfoldrM`, `iterateM` etc. to generate streams in a concurrent
95+`replicateM`, `repeatM`, `iterateM` and `fromFoldableM` etc. work concurrently
96−manner by using an appropriate stream style combinator.
96+when used with appropriate stream type combinator.
97+
98+The following code finishes in 3 seconds (6 seconds when serial):
99+
100+```
101+> let p n = threadDelay (n * 1000000) >> return n
102+> S.toList $ aheadly $ p 3 |: p 2 |: p 1 |: S.nil
103+[3,2,1]
104+
105+> S.toList $ parallely $ p 3 |: p 2 |: p 1 |: S.nil
106+[1,2,3]
107+```
108+
109+The following finishes in 10 seconds (100 seconds when serial):
110+
111+```
112+runStream $ asyncly $ S.replicateM 10 $ p 10
113+```
97
114
98## Concurrent Streaming Pipelines
115## Concurrent Streaming Pipelines
99
116
@@ -108,9 +125,14 @@ main = runStream $
108 |& S.mapM (\x -> threadDelay 1000000 >> putStrLn x)
125 |& S.mapM (\x -> threadDelay 1000000 >> putStrLn x)
109```
126```
110
127
111−## Concurrent transformation
128+## Mapping Concurrently
112
129
113−We can use `mapM` `sequence` concurrently on a stream.
130+We can use `mapM` or `sequence` concurrently on a stream.
131+
132+```
133+> let p n = threadDelay (n * 1000000) >> return n
134+> runStream $ aheadly $ S.mapM (\x -> p 1 >> print x) (serially $ repeatM (p 1))
135+```
114
136
115## Serial and Concurrent Merging
137## Serial and Concurrent Merging
116
138
examples/SearchQuery.hs+10−7
@@ -1,5 +1,5 @@
1import Streamly
1import Streamly
2−import Streamly.Prelude (once)
2+import Streamly.Prelude (nil, once, (|:))
3import Network.HTTP.Simple
3import Network.HTTP.Simple
4
4
5-- | Runs three search engine queries in parallel and prints the search engine
5-- | Runs three search engine queries in parallel and prints the search engine
@@ -9,17 +9,20 @@ import Network.HTTP.Simple
9--
9--
10main :: IO ()
10main :: IO ()
11main = do
11main = do
12− putStrLn "Using parallel semigroup composition"
12+ putStrLn "Using parallel stream construction"
13+ runStream . parallely $ google |: bing |: duckduckgo |: nil
14+
15+ putStrLn "\nUsing parallel semigroup composition"
13− runStream . parallely $ google <> bing <> duckduckgo
16+ runStream . parallely $ once google <> once bing <> once duckduckgo
14
17
15 putStrLn "\nUsing parallel applicative zip"
18 putStrLn "\nUsing parallel applicative zip"
16− runStream . zipAsyncly $ (,,) <$> google <*> bing <*> duckduckgo
19+ runStream . zipAsyncly $ (,,) <$> once google <*> once bing <*> once duckduckgo
17
20
18 where
21 where
19− get :: IsStream t => String -> t IO ()
22+ get :: String -> IO ()
20− get s = once (httpNoBody (parseRequest_ s) >> putStrLn (show s))
23+ get s = httpNoBody (parseRequest_ s) >> putStrLn (show s)
21
24
22− google, bing, duckduckgo :: IsStream t => t IO ()
25+ google, bing, duckduckgo :: IO ()
23 google = get "https://www.google.com/search?q=haskell"
26 google = get "https://www.google.com/search?q=haskell"
24 bing = get "https://www.bing.com/search?q=haskell"
27 bing = get "https://www.bing.com/search?q=haskell"
25 duckduckgo = get "https://www.duckduckgo.com/?q=haskell"
28 duckduckgo = get "https://www.duckduckgo.com/?q=haskell"
src/Streamly/Prelude.hs+22−21
@@ -100,13 +100,13 @@ module Streamly.Prelude
100 , takeWhile
100 , takeWhile
101 , drop
101 , drop
102 , dropWhile
102 , dropWhile
103− , mapMaybe
104
103
105 -- * Reordering
104 -- * Reordering
106 , reverse
105 , reverse
107
106
108 -- * Mapping
107 -- * Mapping
109 , mapM
108 , mapM
109+ , mapMaybe
110 , mapMaybeM
110 , mapMaybeM
111 , sequence
111 , sequence
112
112
@@ -580,24 +580,6 @@ dropWhile p m = fromStream $ go (toStream m)
580 | otherwise = yld a r
580 | otherwise = yld a r
581 in (S.runStream m1) Nothing stp single yield
581 in (S.runStream m1) Nothing stp single yield
582
582
583−-- | Map + filter: compute a stream of b from a stream of a and filter out
584−-- elements that are mapped to Nothing. It is similar to 'mapMaybe' in
585−-- 'Data.Maybe' but applies to streams instead of list.
586−--
587−-- @since 0.2.1
588−{-# INLINE mapMaybe #-}
589−mapMaybe :: (IsStream t) => (a -> Maybe b) -> t m a -> t m b
590−mapMaybe f m = go (toStream m)
591− where
592− go m1 = fromStream $ Stream $ \_ stp sng yld ->
593− let single a = case f a of
594− Just b -> sng b
595− Nothing -> stp
596− yield a r = case f a of
597− Just b -> yld b (toStream $ go r)
598− Nothing -> (S.runStream r) Nothing stp single yield
599− in (S.runStream m1) Nothing stp single yield
600−
601-- | Determine whether all elements of a stream satisfy a predicate.
583-- | Determine whether all elements of a stream satisfy a predicate.
602--
584--
603-- @since 0.1.0
585-- @since 0.1.0
@@ -778,9 +760,28 @@ mapM f m = go (toStream m)
778 yield a r = S.runStream (toStream (f a |: (go r))) svr stp sng yld
760 yield a r = S.runStream (toStream (f a |: (go r))) svr stp sng yld
779 in (S.runStream m1) Nothing stp single yield
761 in (S.runStream m1) Nothing stp single yield
780
762
781−-- | Monadic version mapMaybe.
763+-- | Map a 'Maybe' returning function to a stream, filter out the 'Nothing'
764+-- elements, and return a stream of values extracted from 'Just'.
765+--
766+-- @since 0.3.0
767+{-# INLINE mapMaybe #-}
768+mapMaybe :: (IsStream t) => (a -> Maybe b) -> t m a -> t m b
769+mapMaybe f m = go (toStream m)
770+ where
771+ go m1 = fromStream $ Stream $ \_ stp sng yld ->
772+ let single a = case f a of
773+ Just b -> sng b
774+ Nothing -> stp
775+ yield a r = case f a of
776+ Just b -> yld b (toStream $ go r)
777+ Nothing -> (S.runStream r) Nothing stp single yield
778+ in (S.runStream m1) Nothing stp single yield
779+
780+-- | Like 'mapMaybe' but maps a monadic function.
781+--
782+-- /Concurrent (do not use with 'parallely' on infinite streams)/
782--
783--
783−-- @since 0.2.1
784+-- @since 0.3.0
784{-# INLINE mapMaybeM #-}
785{-# INLINE mapMaybeM #-}
785mapMaybeM :: (IsStream t, MonadAsync m, Functor (t m))
786mapMaybeM :: (IsStream t, MonadAsync m, Functor (t m))
786 => (a -> m (Maybe b)) -> t m a -> t m b
787 => (a -> m (Maybe b)) -> t m a -> t m b
src/Streamly/Tutorial.hs+240−83
@@ -37,7 +37,10 @@ module Streamly.Tutorial
37 -- * Streams
37 -- * Streams
38 -- $streams
38 -- $streams
39
39
40+ -- * Concurrent Streams
41+ -- $concurrentStreams
42+
40− -- * Flavors of Streams
43+ -- * Combining Streams
41 -- $flavors
44 -- $flavors
42
45
43 -- * Imports and Supporting Code
46 -- * Imports and Supporting Code
@@ -46,12 +49,21 @@ module Streamly.Tutorial
46 -- * Generating Streams
49 -- * Generating Streams
47 -- $generating
50 -- $generating
48
51
52+ -- * Generating Streams Concurrently
53+ -- $generatingConcurrently
54+
49 -- * Eliminating Streams
55 -- * Eliminating Streams
50 -- $eliminating
56 -- $eliminating
51
57
58+ -- * Concurrent Pipeline Stages
59+ -- $concurrentApplication
60+
52 -- * Transforming Streams
61 -- * Transforming Streams
53 -- $transformation
62 -- $transformation
54
63
64+ -- * Mapping Concurrently
65+ -- $concurrentTransformation
66+
55 -- * Merging Streams
67 -- * Merging Streams
56
68
57 -- ** Semigroup Style
69 -- ** Semigroup Style
@@ -63,6 +75,9 @@ module Streamly.Tutorial
63 -- *** Wide Serial Composition ('WSerial')
75 -- *** Wide Serial Composition ('WSerial')
64 -- $interleaved
76 -- $interleaved
65
77
78+ -- *** Deep Ahead Composition ('Ahead')
79+ -- $ahead
80+
66 -- *** Deep Asynchronous Composition ('Async')
81 -- *** Deep Asynchronous Composition ('Async')
67 -- $async
82 -- $async
68
83
@@ -90,6 +105,9 @@ module Streamly.Tutorial
90 -- *** Wide Serial Nesting ('WSerial')
105 -- *** Wide Serial Nesting ('WSerial')
91 -- $interleavedNesting
106 -- $interleavedNesting
92
107
108+ -- *** Deep Ahead Nesting ('Ahead')
109+ -- $aheadNesting
110+
93 -- *** Deep Asynchronous Nesting ('Async')
111 -- *** Deep Asynchronous Nesting ('Async')
94 -- $concurrentNesting
112 -- $concurrentNesting
95
113
@@ -174,51 +192,89 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
174--
192--
175-- Similarly, the 'Serial' type is almost a drop in replacement for pure lists,
193-- Similarly, the 'Serial' type is almost a drop in replacement for pure lists,
176-- pure lists are a special case of monadic streams. If you use 'nil' in place
194-- pure lists are a special case of monadic streams. If you use 'nil' in place
177−-- of '[]' and '|:' in place ':' you can replace a list with a 'Serial' The
195+-- of '[]' and '|:' in place ':' you can replace a list with a 'Serial' stream.
178−-- only difference is that the elements must be monadic type and to operate on
196+-- The only difference is that the elements must be monadic type and to operate
179−-- the streams we must use the corresponding functions from "Streamly.Prelude"
197+-- on the streams we must use the corresponding functions from
180−-- instead of using the base "Prelude".
198+-- "Streamly.Prelude" instead of using the base "Prelude".
199+
200+-- $concurrentStreams
201+--
202+-- Streams can be generated concurrently, even infnite streams can be generated
203+-- concurrently using controlled concurrency, streams can be merged
204+-- concurrently, multiple stages in a streaming pipeline can run concurrently,
205+-- streams can be mapped concurrently, they can be zipped concurrently, and in
206+-- a monadic composition they combine like a list transformer providing
207+-- concurrent non-determinism.
208+--
209+-- There are three basic concurrent stream styles, 'Ahead', 'Async', and
210+-- 'Parallel'. The 'Ahead' style streams are similar to 'Serial' except that
211+-- they can speculatively execute multiple stream actions concurrently in
212+-- advance. 'Ahead' would return exactly the same stream as 'Serial' except
213+-- that it may execute the actions concurrently. The 'Async' style streams,
214+-- like 'Ahead', speculatively execute multiple stream actions in advance but
215+-- return the results in their finishing order rather than in the stream
216+-- traversal order. 'Parallel' is like 'Async' except that it provides
217+-- unbounded parallelism instead of controlled parallelism.
218+--
219+-- For easy reference, we can classify the stream types based on /execution order/,
220+-- /consumption order/, and /bounded or unbounded/ concurrency.
221+-- Execution could be serial (i.e. synchronous) or asynchronous. In serial
222+-- execution we execute the next action in the stream only after the previous
223+-- one has finished executing. In asynchronous execution multiple actions in
224+-- the stream can be executed asynchronously i.e. the next action can start
225+-- executing even before the first one has finished. Consumption order
226+-- determines the order in which the outputs generated by the composition are
227+-- consumed. Consumption could be serial or asynchronous. In serial
228+-- consumption, the outputs are consumed in the traversal order, in
229+-- asynchronous consumption the outputs are consumed as they arrive i.e. first
230+-- come first serve order.
231+--
232+-- @
233+-- +------------+--------------+--------------+--------------+
234+-- | Type | Execution | Consumption | Concurrency |
235+-- +============+==============+==============+==============+
236+-- | 'Serial' | Serial | Serial | None |
237+-- +------------+--------------+--------------+--------------+
238+-- | 'Ahead' | Asynchronous | Serial | bounded |
239+-- +------------+--------------+--------------+--------------+
240+-- | 'Async' | Asynchronous | Asynchronous | bounded |
241+-- +------------+--------------+--------------+--------------+
242+-- | 'Parallel' | Asynchronous | Asynchronous | unbounded |
243+-- +------------+--------------+--------------+--------------+
244+-- @
245+--
246+-- All these types can be freely inter-converted using type conversion
247+-- combinators or type annotations without any cost, to acheive the desired
248+-- composition style. To force a particular type of composition we coerce the
249+-- stream type using the corresponding type adapting combinator from
250+-- 'serially', 'aheadly', 'asyncly', or 'parallely'. The default stream type
251+-- is inferred as 'Serial' unless you change it by using one of the combinators
252+-- or using a type annotation.
181
253
182-- $flavors
254-- $flavors
183--
255--
184−-- There are a few more types similar to 'Serial' that all represent streams
256+-- Streams can be combined using semigroup or monoid composition to form a
185−-- and differ only in the 'Semigroup', 'Applicative' and 'Monad' compositions
257+-- composite stream. Traversal of a composition of streams could be @deep@ or
186−-- of the streams.
258+-- @wide@. Deep goes depth first i.e. each stream is traversed fully before
259+-- we traverse the next stream. Wide goes breadth first i.e. one element from
260+-- each stream is traversed before coming back to the first stream again.
187--
261--
188−-- The composition of two or more streams is distinguished based on three
262+-- Each stream type has a wide traversal variant prefixed by 'W'. The wide
189−-- characterstics, /traversal order/, /execution order/ and
263+-- variant differs only in the Semigroup\/Monoid, Applicative\/Monad
190−-- /consumption order/. Traversal of a composition of streams could be @deep@
191−-- or @wide@. Deep goes depth first i.e. each stream is traversed fully
192−-- before we traverse the next stream. Wide goes breadth first i.e. one element
193−-- from each stream is traversed before coming back to the first stream again.
194−-- Execution could be serial (i.e. synchronous) or asynchronous. In serial
195−-- execution we execute an action in the next stream only after the first has
196−-- finished executing. In asynchronous execution actions in both streams can be
197−-- executed asynchronously i.e. the next action can start executing even before
198−-- the first one has finished. The third parameter is consumption order that is
199−-- in what order the output generated by the composition is consumed.
200−-- Consumption could be serial or asynchronous. In serial consumption, the
201−-- outputs are consumed in the traversal order, in asynchronous consumption the
202−-- outputs are consumed as they arrive i.e. first come first serve order.
203−--
204−-- The following table summarizes different styles of streams based on how they
205−-- compose. All these types are monads and they differ in 'Semigroup',
206−-- 'Applicative' and 'Monad' compositions:
264+-- compositions of the streams.
265+-- The following table summarizes the basic types and the corresponding wide
266+-- variants:
207−--
267+--
208−-- @
268+-- @
209−-- +------------+-----------+--------------+--------------+
269+-- +------------+-----------+
210−-- | Type | Traversal | Execution | Consumption |
270+-- | Deep | Wide |
211−-- +============+===========+==============+==============+
271+-- +============+===========+
212−-- | 'Serial' | Deep | Serial | Serial |
272+-- | 'Serial' | 'WSerial' |
213−-- +------------+-----------+--------------+--------------+
273+-- +------------+-----------+
214−-- | 'WSerial' | Wide | Serial | Serial |
274+-- | 'Ahead' | 'WAhead' |
215−-- +------------+-----------+--------------+--------------+
275+-- +------------+-----------+
216−-- | 'Async' | Deep | Asynchronous | Asynchronous |
276+-- | 'Async' | 'WAsync' |
217−-- +------------+-----------+--------------+--------------+
277+-- +------------+-----------+
218−-- | 'WAsync' | Wide | Asynchronous | Asynchronous |
219−-- +------------+-----------+--------------+--------------+
220−-- | 'Parallel' | Parallel | Asynchronous | Asynchronous |
221−-- +------------+-----------+--------------+--------------+
222-- @
278-- @
223--
279--
224-- Other than these types there are also 'ZipSerial' and 'ZipAsync' types that
280-- Other than these types there are also 'ZipSerial' and 'ZipAsync' types that
@@ -226,13 +282,6 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
226-- types are not monads they are only applicatives and they do not differ in
282-- types are not monads they are only applicatives and they do not differ in
227-- 'Semigroup' composition.
283-- 'Semigroup' composition.
228--
284--
229−-- All these types can be freely inter-converted using type conversion
230−-- combinators or type annotations without any cost, to acheive the desired
231−-- composition style. To force a particular type of composition we coerce the
232−-- stream type using the corresponding type adapting combinator from
233−-- 'serially', 'wSerially', 'asyncly', 'wAsyncly', 'parallely', 'zipSerially'
234−-- or 'zipAsyncly'. The default stream type is inferred as 'Serial' unless you
235−-- change it by using one of the combinators or using a type annotation.
236
285
237-- $programs
286-- $programs
238--
287--
@@ -328,15 +377,31 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
328-- @
377-- @
329--
378--
330-- For more ways to construct a stream see the module "Streamly.Prelude".
379-- For more ways to construct a stream see the module "Streamly.Prelude".
380+
381+-- $generatingConcurrently
331--
382--
332−-- Note that monadic generation functions e.g. 'consM', 'unfoldrM',
383+-- Monadic construction and generation functions e.g. 'consM', 'unfoldrM',
333-- 'replicateM', 'repeatM', 'iterateM' and 'fromFoldableM' etc work
384-- 'replicateM', 'repeatM', 'iterateM' and 'fromFoldableM' etc work
334-- concurrently when used with appropriate stream type combinator. The pure
385-- concurrently when used with appropriate stream type combinator. The pure
335−-- versions do not work concurrently, however you can use the monadic versions
386+-- versions of these APIs are not concurrent, however you can use the monadic
387+-- versions even for pure computations by wrapping the pure value in a monad to
336−-- even for pure computations to get the concurrent generation capability where
388+-- get the concurrent generation capability where required.
337−-- required.
389+--
390+-- The following code finishes in 3 seconds (6 seconds when serial):
391+--
392+-- @
393+-- > let p n = threadDelay (n * 1000000) >> return n
394+-- > S.'toList' $ 'parallely' $ p 3 |: p 2 |: p 1 |: S.'nil'
395+-- [1,2,3]
396+-- > S.'toList' $ 'aheadly' $ p 3 |: p 2 |: p 1 |: S.'nil'
397+-- [3,2,1]
398+-- @
399+-- The following finishes in 10 seconds (100 seconds when serial):
400+--
401+-- @
402+-- > 'runStream' $ 'asyncly' $ S.'replicateM' 10 $ p 10
403+-- @
338--
404--
339−-- TBD add more details and examples about concurrent generation.
340
405
341-- $eliminating
406-- $eliminating
342--
407--
@@ -383,15 +448,35 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
383-- & S.'zipWith' (\\n s -> show n ++ " " ++ s) (S.'fromFoldable' [1..])
448-- & S.'zipWith' (\\n s -> show n ++ " " ++ s) (S.'fromFoldable' [1..])
384-- & S.'mapM' putStrLn
449-- & S.'mapM' putStrLn
385-- @
450-- @
451+
452+-- $concurrentTransformation
386--
453--
387−-- Note that monadic transformation functions 'mapM' and 'sequence' work
454+-- Monadic transformation functions 'mapM' and 'sequence' work concurrently
388−-- concurrently when used with appropriate stream type combinator. The pure
455+-- when used with appropriate stream type combinators. The pure versions do not
389−-- versions do not work concurrently, however you can use the monadic versions
456+-- work concurrently, however you can use the monadic versions even for pure
390−-- even for pure computations to get the concurrent transformation capability
457+-- computations to get the concurrent transformation capability where required.
391−-- where required.
392--
458--
393−-- TBD add more details and examples about concurrent transformation.
459+-- This would print a value every second (2 seconds when serial):
394−-- TBD add details about concurrent function application.
460+--
461+-- @
462+-- > let p n = threadDelay (n * 1000000) >> return n
463+-- > runStream $ aheadly $ S.'mapM' (\\x -> p 1 >> print x) (serially $ repeatM (p 1))
464+-- @
465+--
466+
467+-- $concurrentApplication
468+--
469+-- The concurrent function application operators '|$' and '|&' apply a stream
470+-- argument to a stream function concurrently to compose a concurrent pipeline
471+-- of stream processing functions:
472+--
473+-- Because both the stages run concurrently, we would see a delay of only 1
474+-- second instead of 2 seconds in the following:
475+--
476+-- @
477+-- > let p n = threadDelay (n * 1000000) >> return n
478+-- > runStream $ S.'repeatM' (p 1) '|&' S.'mapM' (\\x -> p 1 >> print x)
479+-- @
395
480
396-- $semigroup
481-- $semigroup
397--
482--
@@ -531,6 +616,39 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
531-- Note that this composition cannot be used to fold infinite number of streams
616-- Note that this composition cannot be used to fold infinite number of streams
532-- since it requires preserving the state until a stream is finished.
617-- since it requires preserving the state until a stream is finished.
533
618
619+-- $ahead
620+--
621+-- The 'Semigroup' operation '<>' of the 'Ahead' type combines two streams in a
622+-- /serial depth first/ manner with concurrent lookahead. We use the 'aheadly'
623+-- type combinator to effect 'Ahead' style of composition. We can also use an
624+-- explicit 'Ahead' type annotation for the stream to acheive the same effect.
625+--
626+-- When two streams are combined in this manner, the streams are traversed in
627+-- depth first manner just like 'Serial', however it can execute the next
628+-- stream concurrently and keep the results ready when its turn arrives.
629+-- Concurrent execution of the next stream(s) is performed if the first stream
630+-- blocks or if it cannot produce output at the rate that is enough to meet the
631+-- consumer demand. Multiple streams can be executed concurrently to meet the
632+-- demand. The following example would print the result in a second even
633+-- though each action in each stream takes one second:
634+--
635+-- @
636+-- main = do
637+-- xs \<- 'toList' . 'aheadly' $ (p 1 |: p 2 |: nil) <> (p 3 |: p 4 |: nil)
638+-- print xs
639+-- where p n = threadDelay 1000000 >> return n
640+-- @
641+-- @
642+-- [1,2,3,4]
643+-- @
644+--
645+-- Each stream is constructed 'aheadly' and then both the streams are merged
646+-- 'aheadly', therefore, all the actions can run concurrently but the result is
647+-- presented in serial order.
648+--
649+-- You can also use the polymorphic combinator 'ahead' in place of '<>' to
650+-- compose any type of streams in this manner.
651+
534-- $async
652-- $async
535--
653--
536-- The 'Semigroup' operation '<>' of the 'Async' type combines the two
654-- The 'Semigroup' operation '<>' of the 'Async' type combines the two
@@ -547,32 +665,33 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
547-- stream(s) is performed if the first stream blocks or if it cannot produce
665-- stream(s) is performed if the first stream blocks or if it cannot produce
548-- output at the rate that is enough to meet the consumer demand. Multiple
666-- output at the rate that is enough to meet the consumer demand. Multiple
549-- streams can be executed concurrently to meet the demand.
667-- streams can be executed concurrently to meet the demand.
550−-- In the following example the first stream does not block,
668+-- In the example below each element in the stream introduces a constant delay
551−-- therefore the first stream is completely exhausted before the second.
669+-- of 1 second, however, it takes just one second to produce all the results.
670+-- The results are not guaranteed to be in any particular order:
552--
671--
553-- @
672-- @
673+-- main = do
554−-- main = 'runStream' . 'asyncly' $ (print 1 |: print 2 |: nil) <> (print 3 |: print 4 |: nil)
674+-- xs \<- 'runStream' . 'asyncly' $ (p 1 |: p 2 |: nil) <> (p 3 |: p 4 |: nil)
675+-- print xs
676+-- where p n = threadDelay 1000000 >> return n
555-- @
677-- @
556-- @
678-- @
557−-- 1
679+-- [4,2,1,3]
558−-- 2
559−-- 3
560−-- 4
561-- @
680-- @
562--
681--
563−-- If the first stream blocks, we can yield from the second. In the example
682+-- The constituent streams are also composed in 'Async' manner and the
564−-- below each yield in the stream has a constant delay of 1 second therefore 1
683+-- composition of streams too. We can compose the constituent streams to run
565−-- and 3 would be yielded first and then 2 and 4 would be yielded.
684+-- serially, in that case it would take 2 seconds to produce all the results.
685+-- The elements in the serial streams would be in serial order in the results:
566--
686--
567-- @
687-- @
688+-- main = do
568−-- main = 'runStream' . 'asyncly' $ (p 1 |: p 2 |: nil) <> (p 3 |: p 4 |: nil)
689+-- xs \<- 'runStream' . 'asyncly' $ (serially $ p 1 |: p 2 |: nil) <> (serially $ p 3 |: p 4 |: nil)
690+-- print xs
569−-- where p n = threadDelay 1000000 >> print n
691+-- where p n = threadDelay 1000000 >> return n
570-- @
692-- @
571-- @
693-- @
572−-- 1
694+-- [3,1,2,4]
573−-- 3
574−-- 2
575−-- 4
576-- @
695-- @
577--
696--
578-- In the following example we can see that new threads are started when a
697-- In the following example we can see that new threads are started when a
@@ -665,20 +784,20 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
665-- The 'Semigroup' operation '<>' of the 'WAsync' type combines two streams in
784-- The 'Semigroup' operation '<>' of the 'WAsync' type combines two streams in
666-- a concurrent manner using /breadth first traversal/. We use the 'wAsyncly'
785-- a concurrent manner using /breadth first traversal/. We use the 'wAsyncly'
667-- type combinator to effect 'WAsync' style of composition. We can also use the
786-- type combinator to effect 'WAsync' style of composition. We can also use the
668−-- 'WAsync' type annotation for the stream to acheive the same effect.
787+-- 'WAsync' type annotation for the stream to achieve the same effect.
669--
788--
670-- When streams with multiple elements are combined in this manner, we traverse
789-- When streams with multiple elements are combined in this manner, we traverse
671-- all the streams concurrently in a breadth first manner i.e. one action from
790-- all the streams concurrently in a breadth first manner i.e. one action from
672−-- each stream is peformed and yielded to the resulting stream before we come
791+-- each stream is performed and yielded to the resulting stream before we come
673-- back to the first stream again and so on. Even though we execute the actions
792-- back to the first stream again and so on. Even though we execute the actions
674−-- in a breadth first order the outputs may be consumed in a different order
675−-- because they are consumed on a first come first serve basis.
793+-- in a breadth first order the outputs are consumed on a first come first
794+-- serve basis.
676--
795--
677-- In the following example we can see that outputs are produced in the breadth
796-- In the following example we can see that outputs are produced in the breadth
678−-- first travresal order but this is not guaranteed.
797+-- first traversal order but this is not guaranteed.
679--
798--
680-- @
799-- @
681−-- main = 'runStream' . 'wAsyncly' $ (print 1 |: print 2 |: nil) <> (print 3 |: print 4 |: nil)
800+-- main = 'runStream' . 'wAsyncly' $ (serially $ print 1 |: print 2 |: nil) <> (serially $ print 3 |: print 4 |: nil)
682-- @
801-- @
683-- @
802-- @
684-- 1
803-- 1
@@ -896,6 +1015,44 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
896-- Notice that this is analogous to merging streams of type 'Serial' or merging
1015-- Notice that this is analogous to merging streams of type 'Serial' or merging
897-- streams using 'serial'.
1016-- streams using 'serial'.
898
1017
1018+-- $aheadNesting
1019+--
1020+-- The 'Monad' composition of 'Ahead' type behaves just like 'Serial' except
1021+-- that it can speculatively perform a bounded number of next iterations of a
1022+-- loop concurrently.
1023+--
1024+-- The 'aheadly' type combinator can be used to switch to this style of
1025+-- composition. Alternatively, a type annotation can be used to specify the
1026+-- type of the stream as 'Ahead'.
1027+--
1028+-- @
1029+-- import "Streamly"
1030+-- import "Streamly.Prelude" as S
1031+--
1032+-- comp = 'toList' . 'aheadly' $ do
1033+-- x <- S.'fromFoldable' [3,2,1]
1034+-- delay x >> return x
1035+--
1036+-- main = comp >> print
1037+-- @
1038+-- @
1039+-- ThreadId 40: Delay 1
1040+-- ThreadId 39: Delay 2
1041+-- ThreadId 38: Delay 3
1042+-- [3,2,1]
1043+-- @
1044+--
1045+-- This code finishes in 3 seconds, 'Serial' would take 6 seconds. As we can
1046+-- see all the three iterations are concurrent and run in different threads,
1047+-- however, the results are returned in the serial order.
1048+--
1049+-- Concurrency is demand driven, when multiple streams are composed using this
1050+-- style, the iterations are executed in a depth first manner just like
1051+-- 'Serial' i.e. nested iterations are executed before we proceed to the next
1052+-- outer iteration. The only difference is that we may execute multiple future
1053+-- iterations concurrently and keep the results ready.
1054+--
1055+
899-- $concurrentNesting
1056-- $concurrentNesting
900--
1057--
901-- The 'Monad' composition of 'Async' type can perform the iterations of a
1058-- The 'Monad' composition of 'Async' type can perform the iterations of a