@@ -37,6 +37,9 @@ module Streamly.Tutorial
37 -- * Streams
37 -- * Streams
38 -- $streams
38 -- $streams
40+ -- * Flavors of Streams
40 -- * Generating Streams
43 -- * Generating Streams
41 -- $generating
44 -- $generating
@@ -51,16 +54,19 @@ module Streamly.Tutorial
51 -- ** Semigroup Style
54 -- ** Semigroup Style
52 -- $semigroup
55 -- $semigroup
54− -- *** Serial Depth First Composition ('Stream')
57+ -- *** Deep Serial Composition ('Serial')
55 -- $serial
58 -- $serial
57− -- *** Serial Breadth First Composition ('Costream')
60+ -- *** Wide Serial Composition ('WSerial')
58 -- $interleaved
61 -- $interleaved
60− -- *** Concurrent Depth First Composition ('ParAhead')
63+ -- *** Deep Asynchronous Composition ('Async')
61− -- $parAhead
64+ -- $async
66+ -- *** Wide Asynchronous Composition ('WAsync')
63− -- *** Concurrent Breadth First Composition ('CoParAhead')
69+ -- *** Parallel Asynchronous Composition ('Parallel')
64 -- $parallel
70 -- $parallel
66 -- *** Custom composition
72 -- *** Custom composition
@@ -75,17 +81,20 @@ module Streamly.Tutorial
75 -- ** Monad
81 -- ** Monad
78− -- *** Serial Depth First Nesting ('Stream')
84+ -- *** Deep Serial Nesting ('Serial')
79 -- $regularSerial
85 -- $regularSerial
81− -- *** Serial Breadth First Nesting ('Costream')
87+ -- *** Wide Serial Nesting ('WSerial')
82 -- $interleavedNesting
88 -- $interleavedNesting
84− -- *** Concurrent Depth First Nesting ('ParAhead')
90+ -- *** Deep Asynchronous Nesting ('Async')
85 -- $concurrentNesting
91 -- $concurrentNesting
87− -- *** Concurrent Breadth First Nesting ('CoparAhead')
93+ -- *** Wide Asynchronous Nesting ('WAsync')
88− -- $fairlyConcurrentNesting
94+ -- $wasyncNesting
96+ -- *** Parallel Asynchronous Nesting ('Parallel')
90 -- *** Exercise
99 -- *** Exercise
91 -- $monadExercise
100 -- $monadExercise
@@ -105,9 +114,6 @@ module Streamly.Tutorial
105 -- ** Parallel Zipping
114 -- ** Parallel Zipping
106 -- $parallelzip
115 -- $parallelzip
108− -- * Summary of Compositions
109− -- $compositionSummary
111 -- * Monad transformers
117 -- * Monad transformers
112 -- $monadtransformers
118 -- $monadtransformers
@@ -149,47 +155,90 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
149-- concurrent list transformer. In contrast to the "Prelude" lists, merging or
155-- concurrent list transformer. In contrast to the "Prelude" lists, merging or
150-- appending streams of arbitrary length is scalable and inexpensive.
156-- appending streams of arbitrary length is scalable and inexpensive.
152−-- The basic stream type is 'Stream', it represents a sequence of IO actions,
158+-- The basic stream type is 'Serial', it represents a sequence of IO actions,
153−-- and is a 'Monad'. The type 'StreamT' is a monad transformer that can
154−-- represent a sequence of actions in an arbitrary monad. The type 'Stream' is
155−-- in fact a synonym for @StreamT IO@. There are a few more types similar to
156−-- 'StreamT' that all represent streams and differ only in the 'Semigroup',
157−-- 'Applicative' and 'Monad' compositions of the streams. 'Stream' and
158−-- 'Costream' types compose serially whereas 'ParAhead' and 'CoparAhead' types
159−-- compose concurrently. All these types can be freely inter-converted using
160−-- type combinators without any cost. You can freely switch to any type of
161−-- composition at any point in the program. When no type annotation or
162−-- explicit stream type combinators are used, the default stream type is
163−-- inferred as 'Stream'.
165−-- The 'Stream' monad is almost a drop in replacement for the 'IO' monad, IO
159+-- and is a 'Monad'. The 'Serial' monad is almost a drop in replacement for
166−-- monad is a special case of the 'Stream' monad; IO monad represents a single
160+-- the 'IO' monad, IO monad is a special case of the 'Serial' monad; IO monad
167−-- IO action whereas the 'Stream' monad represents a sequence of IO actions.
161+-- represents a single IO action whereas the 'Serial' monad represents a series
168−-- The only change you need to make to go from 'IO' to 'Stream' is to use
162+-- of IO actions. The only change you need to make to go from 'IO' to 'Serial'
169−-- 'runStream' to run the monad and to prefix the IO actions with 'once'. You
163+-- is to use 'runStream' to run the monad and to prefix the IO actions with
170−-- can also use 'liftIO' instead of 'once'. In fact, if you use liftIO you can
164+-- either 'once' or 'liftIO'. If you use liftIO you can switch from 'Serial'
171−-- switch from 'Stream' to IO monad by simply removing the 'runStream'
165+-- to IO monad by simply removing the 'runStream' function; no other changes
172−-- function; no other changes are needed unless you have used some stream
166+-- are needed unless you have used some stream specific composition or
173−-- specific composition or combinators.
167+-- combinators.
175−-- Similarly, the 'Stream' type is almost a drop in replacement for pure lists,
169+-- 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
170-- 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 'Stream'. The
171+-- of '[]' and '|:' in place ':' you can replace a list with a 'Serial' The
178-- only difference is that the elements must be monadic type and to operate on
172-- only difference is that the elements must be monadic type and to operate on
179-- the streams we must use the corresponding functions from "Streamly.Prelude"
173-- the streams we must use the corresponding functions from "Streamly.Prelude"
180-- instead of using the base "Prelude".
174-- instead of using the base "Prelude".
178+-- There are a few more types similar to 'Serial' that all represent streams
179+-- and differ only in the 'Semigroup', 'Applicative' and 'Monad' compositions
182+-- The composition of two or more streams is distinguished based on three
183+-- characterstics, /traversal order/, /execution order/ and
184+-- /consumption order/. Traversal of a composition of streams could be @deep@
185+-- or @wide@. Deep goes depth first i.e. each stream is traversed fully
186+-- before we traverse the next stream. Wide goes breadth first i.e. one element
187+-- from each stream is traversed before coming back to the first stream again.
188+-- Execution could be serial (i.e. synchronous) or asynchronous. In serial
189+-- execution we execute an action in the next stream only after the first has
190+-- finished executing. In asynchronous execution actions in both streams can be
191+-- executed asynchronously i.e. the next action can start executing even before
192+-- the first one has finished. The third parameter is consumption order that is
193+-- in what order the output generated by the composition is consumed.
194+-- Consumption could be serial or asynchronous. In serial consumption, the
195+-- outputs are consumed in the traversal order, in asynchronous consumption the
196+-- outputs are consumed as they arrive i.e. first come first serve order.
198+-- The following table summarizes different styles of streams based on how they
199+-- compose. All these types are monads and they differ in 'Semigroup',
200+-- 'Applicative' and 'Monad' compositions:
203+-- +------------+-----------+--------------+--------------+
204+-- | Type | Traversal | Execution | Consumption |
205+-- +============+===========+==============+==============+
206+-- | 'Serial' | Deep | Serial | Serial |
207+-- +------------+-----------+--------------+--------------+
208+-- | 'WSerial' | Wide | Serial | Serial |
209+-- +------------+-----------+--------------+--------------+
210+-- | 'Async' | Deep | Asynchronous | Asynchronous |
211+-- +------------+-----------+--------------+--------------+
212+-- | 'WAsync' | Wide | Asynchronous | Asynchronous |
213+-- +------------+-----------+--------------+--------------+
214+-- | 'Parallel' | Parallel | Asynchronous | Asynchronous |
215+-- +------------+-----------+--------------+--------------+
218+-- Other than these types there are also 'ZipSerial' and 'ZipAsync' types that
219+-- zip streams serially or concurrently using 'Applicative' operation. These
220+-- types are not monads they are only applicatives and they do not differ in
221+-- 'Semigroup' composition.
223+-- All these types can be freely inter-converted using type conversion
224+-- combinators or type annotations without any cost, to acheive the desired
225+-- composition style. To force a particular type of composition we coerce the
226+-- stream type using the corresponding type adapting combinator from
227+-- 'serially', 'wSerially', 'asyncly', 'wAsyncly', 'parallely', 'zipSerially'
228+-- or 'zipAsyncly'. The default stream type is inferred as 'Serial' unless you
229+-- change it by using one of the combinators or using a type annotation.
182-- $monadtransformers
231-- $monadtransformers
184-- To represent streams in an arbitrary monad use the more general monad
233-- To represent streams in an arbitrary monad use the more general monad
185-- transformer types for example the monad transformer type corresponding to
234-- transformer types for example the monad transformer type corresponding to
186−-- the 'Stream' type is 'StreamT'. @StreamT m a@ represents a stream of values
235+-- the 'Serial' type is 'SerialT'. @SerialT m a@ represents a stream of values
187−-- of type 'a' in some underlying monad 'm'. For example, @StreamT IO Int@ is a
236+-- of type 'a' in some underlying monad 'm'. For example, @SerialT IO Int@ is a
188−-- stream of 'Int' in 'IO' monad. In fact, the type 'Stream' is a synonym for
237+-- stream of 'Int' in 'IO' monad. In fact, the type 'Serial' is a synonym for
189−-- @StreamT IO@.
238+-- @SerialT IO@.
191-- Similarly we have monad transformer types for other stream types as well viz.
240-- Similarly we have monad transformer types for other stream types as well viz.
192−-- 'CostreamT', 'ParAheadT' and 'CoparAheadT'.
241+-- 'WSerialT', 'AsyncT', 'WAsyncT' and 'ParallelT'.
194-- To lift a value from an underlying monad in a monad transformer stack into a
243-- To lift a value from an underlying monad in a monad transformer stack into a
195-- singleton stream use 'lift' and to lift from an IO action use 'liftIO'.
244-- singleton stream use 'lift' and to lift from an IO action use 'liftIO'.
@@ -307,17 +356,11 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
307-- We can combine two streams into a single stream using semigroup composition
356-- We can combine two streams into a single stream using semigroup composition
308-- operation '<>'. Streams can be combined in many different ways as described
357-- operation '<>'. Streams can be combined in many different ways as described
309-- in the following sections, the '<>' operation behaves differently depending
358-- in the following sections, the '<>' operation behaves differently depending
310−-- on the stream type in effect. Streamly streams can be of many
359+-- on the stream type in effect. The stream type and therefore the composition
311−-- different types i.e. 'Stream', 'Costream', 'ParAhead', 'CoparAhead',
312−-- 'ZipStream', and 'ZipParallel'. The first four are monads whereas the last
313−-- two are applicatives. These types can be freely converted from one to
314−-- another to acheive the desired composition style. To force a particular
315−-- type of composition we coerce the stream type using the corresponding type
316−-- adapting combinator from 'asStream', 'asCostream', 'asParAhead',
317−-- 'asCoparAhead', 'asZipStream' or 'asZipParallel'. The default stream type is
318−-- 'Stream' unless you change it by using one of the combinators.
360+-- style can be changed at any point using one of the type combinators as
361+-- discussed earlier.
320−-- To illustrate the concurrent vs serial composition aspects, we will use the
363+-- To illustrate concurrent vs serial composition aspects, we will use the
321-- following @delay@ function to introduce a delay specified in seconds.
364-- following @delay@ function to introduce a delay specified in seconds.
@@ -334,11 +377,11 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
335-- $serial
378-- $serial
337−-- The 'Semigroup' operation '<>' of the 'Stream' type combines the two streams
380+-- The 'Semigroup' operation '<>' of the 'Serial' type combines the two streams
338−-- in a /serial depth first/ manner. We use the 'asStream' type combinator to
381+-- in a /serial depth first/ manner. We use the 'serially' type combinator to
339−-- effect 'Stream' style of composition. We can also use an explicit 'Stream'
382+-- effect 'Serial' style of composition. We can also use an explicit 'Serial'
340-- type annotation for the stream to acheive the same effect. However, since
383-- type annotation for the stream to acheive the same effect. However, since
341−-- 'Stream' is the default type unless explicitly specified by using a
384+-- 'Serial' is the default type unless explicitly specified by using a
342-- combinator, we can omit using an explicit combinator or type annotation for
385-- combinator, we can omit using an explicit combinator or type annotation for
343-- this style of composition.
386-- this style of composition.
@@ -362,7 +405,7 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
363-- All actions in both the streams are performed serially in the same thread.
406-- All actions in both the streams are performed serially in the same thread.
364-- In the following example we can see that all actions are performed in the
407-- In the following example we can see that all actions are performed in the
365−-- same thread and take a combined total of 6 seconds:
408+-- same thread and take a combined total of @3 + 2 + 1 = 6@ seconds:
368-- main = 'runStream' $ delay 3 <> delay 2 <> delay 1
411-- main = 'runStream' $ delay 3 <> delay 2 <> delay 1
@@ -373,20 +416,20 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
373-- ThreadId 36: Delay 1
416-- ThreadId 36: Delay 1
376−-- The polymorphic version of the 'Stream' binary operation '<>' is called
419+-- The polymorphic version of the binary operation '<>' of the 'Serial' type is
377−-- 'splice'. We can use 'splice' to join streams in a sequential manner
420+-- 'serial'. We can use 'serial' to join streams in a sequential manner
378-- irrespective of the type of stream:
421-- irrespective of the type of stream:
381−-- main = 'runStream' $ (print 1 |: print 2 |: nil) \`splice` (print 3 |: print 4 |: nil)
424+-- main = 'runStream' $ (print 1 |: print 2 |: nil) \`serial` (print 3 |: print 4 |: nil)
384-- $interleaved
427-- $interleaved
386−-- The 'Semigroup' operation '<>' of the 'Costream' type combines the two
429+-- The 'Semigroup' operation '<>' of the 'WSerial' type combines the two
387−-- streams in a /serial breadth first/ manner. We use the 'asCostream' type
430+-- streams in a /serial breadth first/ manner. We use the 'wSerially' type
388−-- combinator to effect 'Costream' style of composition. We can also use the
431+-- combinator to effect 'WSerial' style of composition. We can also use the
389−-- 'Costream' type annotation for the stream to acheive the same effect.
432+-- 'WSerial' type annotation for the stream to acheive the same effect.
391-- When two streams with multiple elements are combined in this manner, we
434-- When two streams with multiple elements are combined in this manner, we
392-- traverse all the streams in a breadth first manner i.e. one action from each
435-- traverse all the streams in a breadth first manner i.e. one action from each
@@ -395,7 +438,7 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
395-- The following example prints the sequence 1, 3, 2, 4
438-- The following example prints the sequence 1, 3, 2, 4
398−-- main = 'runStream' . 'asCostream' $ (print 1 |: print 2 |: nil) <> (print 3 |: print 4 |: nil)
441+-- main = 'runStream' . 'wSerially' $ (print 1 |: print 2 |: nil) <> (print 3 |: print 4 |: nil)
@@ -407,10 +450,10 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
407-- Even though the monadic actions of the two streams are performed in an
450-- Even though the monadic actions of the two streams are performed in an
408-- interleaved manner they are all performed serially in the same thread. In
451-- interleaved manner they are all performed serially in the same thread. In
409-- the following example we can see that all actions are performed in the same
452-- the following example we can see that all actions are performed in the same
410−-- thread and take a combined total of 6 seconds:
453+-- thread and take a combined total of @3 + 2 + 1 = 6@ seconds:
413−-- main = 'runStream' . 'asCostream' $ delay 3 <> delay 2 <> delay 1
456+-- main = 'runStream' . 'wSerially' $ delay 3 <> delay 2 <> delay 1
416-- ThreadId 36: Delay 3
459-- ThreadId 36: Delay 3
@@ -418,13 +461,13 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
418-- ThreadId 36: Delay 1
461-- ThreadId 36: Delay 1
421−-- The polymorphic version of the 'Costream' binary operation '<>' is called
464+-- The polymorphic version of the 'WSerial' binary operation '<>' is called
422−-- 'cosplice'. We can use 'cosplice' to join streams in an interleaved manner
465+-- 'wSerial'. We can use 'wSerial' to join streams in an interleaved manner
423−-- irrespective of the type, notice that we have not used the 'asCostream'
466+-- irrespective of the type, notice that we have not used the 'wSerially'
424-- combinator in the following example:
467-- combinator in the following example:
427−-- main = 'runStream' $ (print 1 |: print 2 |: nil) \`cosplice` (print 3 |: print 4 |: nil)
470+-- main = 'runStream' $ (print 1 |: print 2 |: nil) \`wSerial` (print 3 |: print 4 |: nil)
@@ -436,16 +479,16 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
436-- Note that this composition cannot be used to fold infinite number of streams
479-- Note that this composition cannot be used to fold infinite number of streams
437-- since it requires preserving the state until a stream is finished.
480-- since it requires preserving the state until a stream is finished.
439−-- $parAhead
482+-- $async
441−-- The 'Semigroup' operation '<>' of the 'ParAhead' type combines the two
484+-- The 'Semigroup' operation '<>' of the 'Async' type combines the two
442-- streams in a depth first manner with parallel look ahead. We use the
485-- streams in a depth first manner with parallel look ahead. We use the
443−-- 'asParAhead' type combinator to effect 'ParAhead' style of composition. We
486+-- 'asyncly' type combinator to effect 'Async' style of composition. We
444−-- can also use the 'ParAhead' type annotation for the stream type to acheive
487+-- can also use the 'Async' type annotation for the stream type to acheive
445-- the same effect.
488-- the same effect.
447-- When two streams with multiple elements are combined in this manner, the
490-- When two streams with multiple elements are combined in this manner, the
448−-- streams are traversed in depth first manner just like 'Stream', however it
491+-- streams are traversed in depth first manner just like 'Serial', however it
449-- can execute the next stream concurrently and return the results from it
492-- can execute the next stream concurrently and return the results from it
450-- as they arrive i.e. the results from the next stream may be yielded even
493-- as they arrive i.e. the results from the next stream may be yielded even
451-- before the results from the first stream. Concurrent execution of the next
494-- before the results from the first stream. Concurrent execution of the next
@@ -456,7 +499,7 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
456-- therefore the first stream is completely exhausted before the second.
499-- therefore the first stream is completely exhausted before the second.
459−-- main = 'runStream' . 'asParAhead' $ (print 1 |: print 2 |: nil) <> (print 3 |: print 4 |: nil)
502+-- main = 'runStream' . 'asyncly' $ (print 1 |: print 2 |: nil) <> (print 3 |: print 4 |: nil)
@@ -470,7 +513,7 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
470-- and 3 would be yielded first and then 2 and 4 would be yielded.
513-- and 3 would be yielded first and then 2 and 4 would be yielded.
473−-- main = 'runStream' . 'asParAhead' $ (p 1 |: p 2 |: nil) <> (p 3 |: p 4 |: nil)
516+-- main = 'runStream' . 'asyncly' $ (p 1 |: p 2 |: nil) <> (p 3 |: p 4 |: nil)
474-- where p n = threadDelay 1000000 >> print n
517-- where p n = threadDelay 1000000 >> print n
@@ -482,10 +525,11 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
483-- In the following example we can see that new threads are started when a
526-- In the following example we can see that new threads are started when a
484-- computation blocks. Notice that the output from the stream with the
527-- computation blocks. Notice that the output from the stream with the
485−-- shortest delay is printed first:
528+-- shortest delay is printed first. The whole computation takes @maximum of
529+-- (3, 2, 1) = 3@ seconds:
488−-- main = 'runStream' . 'asParAhead' $ delay 3 '<>' delay 2 '<>' delay 1
532+-- main = 'runStream' . 'asyncly' $ delay 3 '<>' delay 2 '<>' delay 1
491-- ThreadId 42: Delay 1
535-- ThreadId 42: Delay 1
@@ -494,7 +538,7 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
496-- When we have a tree of computations composed using this style, the tree is
540-- When we have a tree of computations composed using this style, the tree is
497−-- traversed in DFS style just like the serial style, the only difference is
541+-- traversed in DFS style just like the 'Serial' style, the only difference is
498-- that here we can move on to executing the next stream if a stream blocks.
542-- that here we can move on to executing the next stream if a stream blocks.
499-- However, we will not start new threads if we have sufficient output to
543-- However, we will not start new threads if we have sufficient output to
500-- saturate the consumer. This is why we call it left-biased demand driven or
544-- saturate the consumer. This is why we call it left-biased demand driven or
@@ -504,7 +548,7 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
504-- second as all of the actions are concurrent.
548-- second as all of the actions are concurrent.
507−-- main = 'runStream' . 'asParAhead' $ (delay 1 <> delay 2) <> (delay 3 <> delay 4)
551+-- main = 'runStream' . 'asyncly' $ (delay 1 <> delay 2) <> (delay 3 <> delay 4)
@@ -521,7 +565,7 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
521-- even if none of them blocks:
565-- even if none of them blocks:
524−-- main = 'runStream' . 'asParAhead' $ traced (sqrt 9) '<>' traced (sqrt 16) '<>' traced (sqrt 25)
568+-- main = 'runStream' . 'asyncly' $ traced (sqrt 9) '<>' traced (sqrt 16) '<>' traced (sqrt 25)
525-- where traced m = S.'once' (myThreadId >>= print) >> return m
569-- where traced m = S.'once' (myThreadId >>= print) >> return m
@@ -533,13 +577,13 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
533-- Note that the order of printing in the above examples may change due to
577-- Note that the order of printing in the above examples may change due to
534-- variations in scheduling latencies for concurrent threads.
578-- variations in scheduling latencies for concurrent threads.
536−-- The polymorphic version of the 'ParAhead' binary operation '<>' is called
580+-- The polymorphic version of the 'Async' binary operation '<>' is called
537−-- 'parAhead'. We can use 'parAhead' to join streams in a left biased
581+-- 'async'. We can use 'async' to join streams in a left biased
538-- adaptively concurrent manner irrespective of the type, notice that we have
582-- adaptively concurrent manner irrespective of the type, notice that we have
539−-- not used the 'asParAhead' combinator in the following example:
583+-- not used the 'asyncly' combinator in the following example:
542−-- main = 'runStream' $ delay 3 \`parAhead` delay 2 \`parAhead` delay 1
586+-- main = 'runStream' $ delay 3 \`async` delay 2 \`async` delay 1
545-- ThreadId 42: Delay 1
589-- ThreadId 42: Delay 1
@@ -555,27 +599,80 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
555-- all computations at once for any reason 'Parallel' style must be used
599-- all computations at once for any reason 'Parallel' style must be used
556-- instead.
600-- instead.
558−-- 'ParAhead' style should be preferred over 'CoparAhead' unless you really
602+-- 'Async' style should be preferred over 'Parallel' or 'WAsync' unless you
559−-- need 'CoparAhead'. It utilizes the resources optimally. It should be used when
603+-- really need those. It utilizes the resources optimally. It should be used
560−-- we know that the computations can run in parallel but we do not care if they
604+-- when we know that the computations can run in parallel but we do not care if
561−-- actually run in parallel or not, that decision can be left to the scheduler
605+-- they actually run in parallel or not, that decision can be left to the
562−-- based on demand. Also, note that this operator can be used to fold infinite
606+-- scheduler based on demand. Also, note that this operator can be used to fold
563−-- number of streams in contrast to the 'CoparAhead' style, because it does not
607+-- infinite number of streams in contrast to the 'Parallel' or 'WAsync' styles,
564−-- require us to run all of them at the same time in a fair manner.
608+-- because it does not require us to run all of them at the same time in a fair
613+-- The 'Semigroup' operation '<>' of the 'WAsync' type combines two streams in
614+-- a concurrent manner using /breadth first traversal/. We use the 'wAsyncly'
615+-- type combinator to effect 'WAsync' style of composition. We can also use the
616+-- 'WAsync' type annotation for the stream to acheive the same effect.
618+-- When streams with multiple elements are combined in this manner, we traverse
619+-- all the streams concurrently in a breadth first manner i.e. one action from
620+-- each stream is peformed and yielded to the resulting stream before we come
621+-- back to the first stream again and so on. Even though we execute the actions
622+-- in a breadth first order the outputs may be consumed in a different order
623+-- because they are consumed on a first come first serve basis.
625+-- In the following example we can see that outputs are produced in the breadth
626+-- first travresal order but this is not guaranteed.
629+-- main = 'runStream' . 'wAsyncly' $ (print 1 |: print 2 |: nil) <> (print 3 |: print 4 |: nil)
638+-- The polymorphic version of the binary operation '<>' of the 'WAsync' type is
639+-- 'wAsync'. We can use 'wAsync' to join streams using a breadth first
640+-- concurrent traversal irrespective of the type, notice that we have not used
641+-- the 'wAsyncly' combinator in the following example:
644+-- main = 'runStream' $ delay 3 \`wAsync` delay 2 \`wAsync` delay 1
647+-- ThreadId 42: Delay 1
648+-- ThreadId 41: Delay 2
649+-- ThreadId 40: Delay 3
652+-- Since the concurrency provided by this style is demand driven it may not
653+-- be used when the composed computations start timers that are relative to
654+-- each other because all computations may not be started at the same time and
655+-- therefore timers in all of them may not start at the same time. When
656+-- relative timing among all computations is important or when we need to start
657+-- all computations at once for any reason 'Parallel' style must be used
566-- $parallel
661-- $parallel
568-- The 'Semigroup' operation '<>' of the 'Parallel' type combines the two
663-- The 'Semigroup' operation '<>' of the 'Parallel' type combines the two
569-- streams in a fairly concurrent manner with round robin scheduling. We use
664-- streams in a fairly concurrent manner with round robin scheduling. We use
570−-- the 'parallel' type combinator to effect 'Parallel' style of composition. We
665+-- the 'parallely' type combinator to effect 'Parallel' style of composition.
571−-- can also use the 'Parallel' type annotation for the stream type to acheive
666+-- We can also use the 'Parallel' type annotation for the stream type to
572−-- the same effect.
667+-- acheive the same effect.
574-- When two streams with multiple elements are combined in this manner, the
669-- When two streams with multiple elements are combined in this manner, the
575-- monadic actions in both the streams are performed concurrently with a fair
670-- monadic actions in both the streams are performed concurrently with a fair
576-- round robin scheduling. The outputs are yielded in the order in which the
671-- round robin scheduling. The outputs are yielded in the order in which the
577−-- actions complete. This can be thought of as the concurrent analogue of the
672+-- actions complete. This is pretty similar to the 'WAsync' type, the
578−-- 'Costream' style serial composition.
673+-- difference is that 'WAsync' is adaptive to the consumer demand and may or
674+-- may not execute all actions in parallel depending on the demand, whereas
675+-- 'Parallel' runs all the streams in parallel irrespective of the demand.
580-- The following example sends a query to all the three search engines in
677-- The following example sends a query to all the three search engines in
581-- parallel and prints the name of the search engines in the order in which the
678-- parallel and prints the name of the search engines in the order in which the
@@ -586,7 +683,7 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
586-- import qualified Streamly.Prelude as S
683-- import qualified Streamly.Prelude as S
587-- import Network.HTTP.Simple
684-- import Network.HTTP.Simple
589−-- main = 'runStream' . 'asParallel' $ google \<> bing \<> duckduckgo
686+-- main = 'runStream' . 'parallely' $ google \<> bing \<> duckduckgo
591-- google = get "https://www.google.com/search?q=haskell"
688-- google = get "https://www.google.com/search?q=haskell"
592-- bing = get "https://www.bing.com/search?q=haskell"
689-- bing = get "https://www.bing.com/search?q=haskell"
@@ -594,27 +691,13 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
594-- get s = S.'once' (httpNoBody (parseRequest_ s) >> putStrLn (show s))
691-- get s = S.'once' (httpNoBody (parseRequest_ s) >> putStrLn (show s))
597−-- In the following example we can see that the co-ahead parallel composition
598−-- yields outputs in the same order as the 'Costream' composition, though this
599−-- is not always guaranteed because of thread scheduling variances.
602−-- main = 'runStream' . 'asCoparAhead' $ (print 1 |: print 2 |: nil) <> (print 3 |: print 4 |: nil)
611−-- The polymorphic version of the 'CoparAhead' binary operation '<>' is called
694+-- The polymorphic version of the binary operation '<>' of the 'Parallel' type
612−-- 'coparAhead'. We can use 'coparAhead' to join streams in a fairly
695+-- is 'parallel'. We can use 'parallel' to join streams in a fairly concurrent
613−-- concurrent manner irrespective of the type, notice that we have
696+-- manner irrespective of the type, notice that we have not used the
614−-- not used the 'asCoparAhead' combinator in the following example:
697+-- 'parallely' combinator in the following example:
617−-- main = 'runStream' $ delay 3 \`coparAhead` delay 2 \`coparAhead` delay 1
700+-- main = 'runStream' $ delay 3 \`parallel` delay 2 \`wAsync` delay 1
620-- ThreadId 42: Delay 1
703-- ThreadId 42: Delay 1
@@ -628,7 +711,7 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
629-- $custom
712-- $custom
631−-- The 'async' API can be used to create references to asynchronously running
714+-- The 'mkAsync' API can be used to create references to asynchronously running
632-- stream computations. We can then use 'uncons' to explore the streams
715-- stream computations. We can then use 'uncons' to explore the streams
633-- arbitrarily and then recompose individual elements to create a new stream.
716-- arbitrarily and then recompose individual elements to create a new stream.
634-- This way we can dynamically decide which stream to explore at any given
717-- This way we can dynamically decide which stream to explore at any given
@@ -660,10 +743,10 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
660-- import Control.Concurrent
743-- import Control.Concurrent
662-- main = do
745-- main = do
663−-- 'runStream' $ 'asParAhead' $ foldMap delay [1..10]
746+-- 'runStream' $ 'asyncly' $ foldMap delay [1..10]
664−-- 'runStream' $ 'foldWith' 'parAhead' (map delay [1..10])
747+-- 'runStream' $ 'foldWith' 'async' (map delay [1..10])
665−-- 'runStream' $ 'foldMapWith' 'parAhead' delay [1..10]
748+-- 'runStream' $ 'foldMapWith' 'async' delay [1..10]
666−-- 'runStream' $ 'forEachWith' 'parAhead' [1..10] delay
749+-- 'runStream' $ 'forEachWith' 'async' [1..10] delay
667-- where delay n = S.'once' $ threadDelay (n * 1000000) >> print n
750-- where delay n = S.'once' $ threadDelay (n * 1000000) >> print n
@@ -688,18 +771,18 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
688-- element in the first stream and for each element in the second stream
771-- element in the first stream and for each element in the second stream
689-- execute the body of the loop.
772-- execute the body of the loop.
691−-- The 'Monad' instances of 'Stream', 'Costream', 'ParAhead' and 'CoparAhead'
774+-- The 'Monad' instances of 'Serial', 'WSerial', 'Async' and 'WAsync'
692-- stream types support different flavors of nested looping. In other words,
775-- stream types support different flavors of nested looping. In other words,
693-- they are all variants of list transformer. The nesting behavior of these
776-- they are all variants of list transformer. The nesting behavior of these
694−-- types exactly correspond to the way they merge streams as we discussed in
777+-- types correspond exactly to the way they merge streams as we discussed in
695-- the previous section.
778-- the previous section.
698-- $regularSerial
781-- $regularSerial
700−-- The 'Monad' composition of 'Stream' type behaves like a standard list
783+-- The 'Monad' composition of the 'Serial' type behaves like a standard list
701-- transformer. This is the default when we do not use an explicit type
784-- transformer. This is the default when we do not use an explicit type
702−-- combinator. However, the 'streamly' type combinator can be used to switch to
785+-- combinator. However, the 'serially' type combinator can be used to switch to
703-- this style of composition. We will see how this style of composition works
786-- this style of composition. We will see how this style of composition works
704-- in the following examples.
787-- in the following examples.
@@ -722,7 +805,7 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
722-- ThreadId 30: Delay 1
805-- ThreadId 30: Delay 1
725−-- As you can see, the code after the @fromFoldable@ statement is run three
808+-- As we can see, the code after the @fromFoldable@ statement is run three
726-- times, once for each value of @x@ drawn from the stream. All the three
809-- times, once for each value of @x@ drawn from the stream. All the three
727-- iterations are serial and run in the same thread one after another. In
810-- iterations are serial and run in the same thread one after another. In
728-- imperative terms this is equivalent to a @for@ loop with three iterations.
811-- imperative terms this is equivalent to a @for@ loop with three iterations.
@@ -758,27 +841,27 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
761−-- Notice that this is analogous to merging streams of type 'Stream' or merging
844+-- Notice that this is analogous to merging streams of type 'Serial' or merging
762−-- streams using 'splice'.
845+-- streams using 'serial'.
764-- $concurrentNesting
847-- $concurrentNesting
766−-- The 'Monad' composition of 'ParAhead' type can perform the iterations of a
849+-- The 'Monad' composition of 'Async' type can perform the iterations of a
767-- loop concurrently. Concurrency is demand driven i.e. more concurrent
850-- loop concurrently. Concurrency is demand driven i.e. more concurrent
768-- iterations are started only if the previous iterations are not able to
851-- iterations are started only if the previous iterations are not able to
769-- produce enough output for the consumer of the output stream. This works
852-- produce enough output for the consumer of the output stream. This works
770−-- exactly the same way as the merging of two streams 'asParAhead' works.
853+-- exactly the same way as the merging of two streams 'asyncly' works.
771−-- This is the concurrent analogue of 'Stream' style monadic composition.
854+-- This is the concurrent analogue of 'Serial' style monadic composition.
773−-- The 'asParAhead' type combinator can be used to switch to this
856+-- The 'asyncly' type combinator can be used to switch to this style of
774−-- style of composition. Alternatively, a type annotation can be used to
857+-- composition. Alternatively, a type annotation can be used to specify the
775−-- specify the type of the stream as 'ParAhead'.
858+-- type of the stream as 'Async'.
778-- import "Streamly"
861-- import "Streamly"
779-- import "Streamly.Prelude"
862-- import "Streamly.Prelude"
781−-- main = 'runStream' . 'asParAhead' $ do
864+-- main = 'runStream' . 'asyncly' $ do
782-- x <- 'fromFoldable' [3,2,1]
865-- x <- 'fromFoldable' [3,2,1]
783-- delay x
866-- delay x
@@ -788,24 +871,24 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
788-- ThreadId 38: Delay 3
871-- ThreadId 38: Delay 3
791−-- As you can see the code after the @fromFoldable@ statement is run three
874+-- As we can see the code after the @fromFoldable@ statement is run three
792-- times, once for each value of @x@. All the three iterations are concurrent
875-- times, once for each value of @x@. All the three iterations are concurrent
793-- and run in different threads. The iteration with least delay finishes first.
876-- and run in different threads. The iteration with least delay finishes first.
794-- When compared to imperative programming, this can be viewed as a @for@ loop
877-- When compared to imperative programming, this can be viewed as a @for@ loop
795-- with three concurrent iterations.
878-- with three concurrent iterations.
797−-- Concurrency is demand driven just as in the case of 'parAhead' merging.
880+-- Concurrency is demand driven just as in the case of 'async' merging.
798-- When multiple streams are composed using this style, the iterations are
881-- When multiple streams are composed using this style, the iterations are
799−-- triggered in a DFS manner just like 'Stream' i.e. nested iterations are
882+-- triggered in a depth first manner just like 'Serial' i.e. nested iterations are
800-- executed before we proceed to the next iteration at higher level. However,
883-- executed before we proceed to the next iteration at higher level. However,
801−-- unlike 'Stream' more than one iterations may be started concurrently based
884+-- unlike 'Serial' more than one iterations may be started concurrently based
802−-- on the demand from the consumer.
885+-- on the demand from the consumer of the stream.
805-- import "Streamly"
888-- import "Streamly"
806-- import qualified "Streamly.Prelude" as S
889-- import qualified "Streamly.Prelude" as S
808−-- main = 'runStream' . 'asParAhead' $ do
891+-- main = 'runStream' . 'asyncly' $ do
809-- x <- S.'fromFoldable' [1,2]
892-- x <- S.'fromFoldable' [1,2]
810-- y <- S.'fromFoldable' [3,4]
893-- y <- S.'fromFoldable' [3,4]
811-- S.'once' $ putStrLn $ show (x, y)
894-- S.'once' $ putStrLn $ show (x, y)
@@ -819,18 +902,18 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
820-- $interleavedNesting
903-- $interleavedNesting
822−-- The 'Monad' composition of 'Costream' type interleaves the iterations of
905+-- The 'Monad' composition of 'WSerial' type interleaves the iterations of
823-- outer and inner loops in a nested loop composition. This works exactly the
906-- outer and inner loops in a nested loop composition. This works exactly the
824−-- same way as the merging of two streams in 'asCostream' fashion works. The
907+-- same way as the merging of two streams in 'wSerially' fashion works. The
825−-- 'asCostream' type combinator can be used to switch to this style of
908+-- 'wSerially' type combinator can be used to switch to this style of
826-- composition. Alternatively, a type annotation can be used to specify the
909-- composition. Alternatively, a type annotation can be used to specify the
827−-- type of the stream as 'Costream'.
910+-- type of the stream as 'WSerial'.
830-- import "Streamly"
913-- import "Streamly"
831-- import qualified "Streamly.Prelude" as S
914-- import qualified "Streamly.Prelude" as S
833−-- main = 'runStream' . 'asCostream' $ do
916+-- main = 'runStream' . 'wSerially' $ do
834-- x <- S.'fromFoldable' [1,2]
917-- x <- S.'fromFoldable' [1,2]
835-- y <- S.'fromFoldable' [3,4]
918-- y <- S.'fromFoldable' [3,4]
836-- S.once $ putStrLn $ show (x, y)
919-- S.once $ putStrLn $ show (x, y)
@@ -843,14 +926,42 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
846−-- $fairlyConcurrentNesting
929+-- $wasyncNesting
848−-- The 'Monad' composition of 'Parallel' type starts all the iterations of a
931+-- Just like 'Async' the 'Monad' composition of 'WAsync' runs the iterations of
849−-- loop concurrently instead of demand driven as in the case of 'ParAhead'.
932+-- a loop concurrently. The difference is in the nested loop behavior. The
933+-- nested loops in this type are traversed and executed in a breadth first
934+-- manner rather than the depth first manner of 'Async' style.
935+-- The loop nesting works exactly the same way as the merging of streams
936+-- 'wAsyncly' works. The 'wAsyncly' type combinator can be used to switch to
937+-- this style of composition. Alternatively, a type annotation can be used to
938+-- specify the type of the stream as 'WAsync'.
942+-- import qualified "Streamly.Prelude" as S
944+-- main = 'runStream' . 'wAsyncly' $ do
945+-- x <- S.'fromFoldable' [1,2]
946+-- y <- S.'fromFoldable' [3,4]
947+-- S.'once' $ putStrLn $ show (x, y)
958+-- Just like 'Async' or 'WAsync' the 'Monad' composition of 'Parallel' runs the
959+-- iterations of a loop concurrently. The difference is in the nested loop
960+-- behavior. The streams at each nest level is run fully concurrently
961+-- irrespective of the demand. The loop nesting works exactly the same way as
850−-- This works exactly the same way as the merging streams 'parallely' works.
962+-- the merging of streams 'parallely' works. The 'parallely' type combinator
851−-- The 'parallely' type combinator can be used to switch to this style of
963+-- can be used to switch to this style of composition. Alternatively, a type
852−-- composition. Alternatively, a type annotation can be used to specify the
853−-- type of the stream as 'Parallel'.
964+-- annotation can be used to specify the type of the stream as 'Parallel'.
856-- import "Streamly"
967-- import "Streamly"
@@ -868,7 +979,7 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
869-- $monadExercise
980-- $monadExercise
871−-- The streamly code is usually written in a way that is agnostic of the
982+-- Streamly code is usually written in a way that is agnostic of the
872-- specific monadic composition type. We use a polymorphic type with a
983-- specific monadic composition type. We use a polymorphic type with a
873-- 'IsStream' type class constraint. When running the stream we can choose the
984-- 'IsStream' type class constraint. When running the stream we can choose the
874-- specific mode of composition. For example take a look at the following code.
985-- specific mode of composition. For example take a look at the following code.
@@ -894,10 +1005,11 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
894-- Now we can interpret this in whatever way we want:
1005-- Now we can interpret this in whatever way we want:
897−-- main = 'runStream' . 'asStream' $ composed
1008+-- main = 'runStream' . 'serially' $ composed
898−-- main = 'runStream' . 'asCostream' $ composed
899−-- main = 'runStream' . 'asParAhead' $ composed
1009+-- main = 'runStream' . 'wSerially' $ composed
900−-- main = 'runStream' . 'asCoparAhead' $ composed
1010+-- main = 'runStream' . 'asyncly' $ composed
1011+-- main = 'runStream' . 'wAsyncly' $ composed
1012+-- main = 'runStream' . 'parallely' $ composed
903-- As an exercise try to figure out the output of this code for each mode of
1015-- As an exercise try to figure out the output of this code for each mode of
@@ -922,10 +1034,10 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
922-- $applicative
1034-- $applicative
924-- Applicative is precisely the same as the 'ap' operation of 'Monad'. For
1036-- Applicative is precisely the same as the 'ap' operation of 'Monad'. For
925−-- zipping applicatives separate types 'ZipStream' and 'ZipParallel' are
1037+-- zipping applicatives separate types 'ZipSerial' and 'ZipAsync' are
926-- provided.
1038-- provided.
928−-- The following example uses the 'Stream' applicative, it runs all iterations
1040+-- The following example uses the 'Serial' applicative, it runs all iterations
929-- serially and takes a total 17 seconds (1 + 3 + 4 + 2 + 3 + 4):
1041-- serially and takes a total 17 seconds (1 + 3 + 4 + 2 + 3 + 4):
@@ -937,7 +1049,7 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
937-- s2 = d 3 <> d 4
1049-- s2 = d 3 <> d 4
938-- d n = delay n >> return n
1050-- d n = delay n >> return n
940−-- main = (S.'toList' . 'asStream' $ (,) \<$> s1 \<*> s2) >>= print
1052+-- main = (S.'toList' . 'serially' $ (,) \<$> s1 \<*> s2) >>= print
943-- ThreadId 36: Delay 1
1055-- ThreadId 36: Delay 1
@@ -949,11 +1061,11 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
949-- [(1,3),(1,4),(2,3),(2,4)]
1061-- [(1,3),(1,4),(2,3),(2,4)]
952−-- Similalrly 'Costream' applicative runs the iterations in an interleaved
1064+-- Similalrly 'WSerial' applicative runs the iterations in an interleaved
953-- order but since it is serial it takes a total of 17 seconds:
1065-- order but since it is serial it takes a total of 17 seconds:
956−-- main = (S.'toList' . 'asCostream' $ (,) \<$> s1 \<*> s2) >>= print
1068+-- main = (S.'toList' . 'wSerially' $ (,) \<$> s1 \<*> s2) >>= print
959-- ThreadId 36: Delay 1
1071-- ThreadId 36: Delay 1
@@ -965,11 +1077,11 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
965-- [(1,3),(2,3),(1,4),(2,4)]
1077-- [(1,3),(2,3),(1,4),(2,4)]
968−-- 'ParAhead' can run the iterations concurrently and therefore takes a total
1080+-- 'Async' can run the iterations concurrently and therefore takes a total
969-- of 10 seconds (1 + 2 + 3 + 4):
1081-- of 10 seconds (1 + 2 + 3 + 4):
972−-- main = (S.'toList' . 'asParAhead' $ (,) \<$> s1 \<*> s2) >>= print
1084+-- main = (S.'toList' . 'asyncly' $ (,) \<$> s1 \<*> s2) >>= print
975-- ThreadId 34: Delay 1
1087-- ThreadId 34: Delay 1
@@ -981,11 +1093,11 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
981-- [(1,3),(2,3),(1,4),(2,4)]
1093-- [(1,3),(2,3),(1,4),(2,4)]
984−-- Similalrly 'CoparAhead' as well can run the iterations concurrently and
1096+-- Similalrly 'WAsync' as well can run the iterations concurrently and
985-- therefore takes a total of 10 seconds (1 + 2 + 3 + 4):
1097-- therefore takes a total of 10 seconds (1 + 2 + 3 + 4):
988−-- main = (S.'toList' . 'asCoparAhead' $ (,) \<$> s1 \<*> s2) >>= print
1100+-- main = (S.'toList' . 'wAsyncly' $ (,) \<$> s1 \<*> s2) >>= print
991-- ThreadId 34: Delay 1
1103-- ThreadId 34: Delay 1
@@ -997,21 +1109,6 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
997-- [(1,3),(2,3),(1,4),(2,4)]
1109-- [(1,3),(2,3),(1,4),(2,4)]
1000−-- $compositionSummary
1002−-- The following table summarizes the types for monadic and sum style
1006−-- +-----+--------------+--------------+
1007−-- | | Serial | Concurrent |
1008−-- +=====+==============+==============+
1009−-- | DFS | 'Stream' | 'ParAhead' |
1010−-- +-----+--------------+--------------+
1011−-- | BFS | 'Costream' | 'CoparAhead' |
1012−-- +-----+--------------+--------------+
1015-- $zipping
1112-- $zipping
1017-- Zipping is a special transformation where the corresponding elements of two
1114-- Zipping is a special transformation where the corresponding elements of two
@@ -1023,8 +1120,8 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
1024-- $serialzip
1121-- $serialzip
1026−-- The applicative instance of 'ZipStream' type zips streams serially.
1123+-- The applicative instance of 'ZipSerial' type zips streams serially.
1027−-- 'asZipStream' type combinator can be used to switch to serial applicative
1124+-- 'zipSerially' type combinator can be used to switch to serial applicative
1028-- zip composition:
1125-- zip composition:
@@ -1036,7 +1133,7 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
1036-- s1 = 'streamly' $ d 1 <> d 2
1133-- s1 = 'streamly' $ d 1 <> d 2
1037-- s2 = 'streamly' $ d 3 <> d 4
1134-- s2 = 'streamly' $ d 3 <> d 4
1039−-- main = (S.'toList' . 'asZipStream' $ (,) \<$> s1 \<*> s2) >>= print
1136+-- main = (S.'toList' . 'zipSerially' $ (,) \<$> s1 \<*> s2) >>= print
1042-- This takes total 10 seconds to zip, which is (1 + 2 + 3 + 4) since
1139-- This takes total 10 seconds to zip, which is (1 + 2 + 3 + 4) since
@@ -1052,8 +1149,8 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
1053-- $parallelzip
1150-- $parallelzip
1055−-- The applicative instance of 'ZipParallel' type zips streams concurrently.
1152+-- The applicative instance of 'ZipAsync' type zips streams concurrently.
1056−-- 'asZipParallel' type combinator can be used to switch to parallel applicative
1153+-- 'zipAsyncly' type combinator can be used to switch to parallel applicative
1057-- zip composition:
1154-- zip composition:
@@ -1069,7 +1166,7 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
1070-- main = do
1167-- main = do
1071-- hSetBuffering stdout LineBuffering
1168-- hSetBuffering stdout LineBuffering
1072−-- (S.'toList' . 'asZipParallel' $ (,) \<$> s1 \<*> s2) >>= print
1169+-- (S.'toList' . 'zipAsyncly' $ (,) \<$> s1 \<*> s2) >>= print
1075-- This takes 7 seconds to zip, which is max (1,3) + max (2,4) because 1 and 3
1172-- This takes 7 seconds to zip, which is max (1,3) + max (2,4) because 1 and 3
@@ -1093,11 +1190,11 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
1093-- choose the desired type of concurrency.
1190-- choose the desired type of concurrency.
1095-- In the following example the squares of @x@ and @y@ are computed
1192-- In the following example the squares of @x@ and @y@ are computed
1096−-- concurrently using the 'parAhead' operation and the square roots of their
1193+-- concurrently using the 'async' operation and the square roots of their
1097-- sum are computed serially because of the 'streamly' combinator. We can
1194-- sum are computed serially because of the 'streamly' combinator. We can
1098-- choose different combinators for the monadic processing and the stream
1195-- choose different combinators for the monadic processing and the stream
1099−-- generation, to control the concurrency. We can also use the 'asParAhead'
1196+-- generation, to control the concurrency. We can also use the 'asyncly'
1100−-- combinator instead of explicitly folding with 'parAhead'.
1197+-- combinator instead of explicitly folding with 'async'.
1103-- import "Streamly"
1200-- import "Streamly"
@@ -1106,17 +1203,17 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
1107-- main = do
1204-- main = do
1108-- z \<- S.'toList'
1205-- z \<- S.'toList'
1109−-- $ 'asStream' -- Serial monadic processing (sqrt below)
1206+-- $ 'serially' -- Serial monadic processing (sqrt below)
1111−-- x2 \<- 'forEachWith' 'parAhead' [1..100] $ -- Concurrent @"for"@ loop
1208+-- x2 \<- 'forEachWith' 'async' [1..100] $ -- Concurrent @"for"@ loop
1112-- \\x -> return $ x * x -- body of the loop
1209-- \\x -> return $ x * x -- body of the loop
1113−-- y2 \<- 'forEachWith' 'parAhead' [1..100] $
1210+-- y2 \<- 'forEachWith' 'async' [1..100] $
1114-- \\y -> return $ y * y
1211-- \\y -> return $ y * y
1115-- return $ sqrt (x2 + y2)
1212-- return $ sqrt (x2 + y2)
1116-- print $ sum z
1213-- print $ sum z
1119−-- You can see how this directly maps to the imperative style
1216+-- We can see how this directly maps to the imperative style
1120-- <https://en.wikipedia.org/wiki/OpenMP OpenMP> model, we use combinators
1217-- <https://en.wikipedia.org/wiki/OpenMP OpenMP> model, we use combinators
1121-- and operators instead of the ugly pragmas.
1218-- and operators instead of the ugly pragmas.
@@ -1151,7 +1248,7 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
1152-- data Event = Harm Int | Heal Int | Quit deriving (Show)
1249-- data Event = Harm Int | Heal Int | Quit deriving (Show)
1154−-- userAction :: MonadIO m => 'StreamT' m Event
1251+-- userAction :: MonadIO m => 'SerialT' m Event
1155-- userAction = cycle1 $ liftIO askUser
1252-- userAction = cycle1 $ liftIO askUser
1157-- askUser = do
1254-- askUser = do
@@ -1161,10 +1258,10 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
1161-- "quit" -> return Quit
1258-- "quit" -> return Quit
1162-- _ -> putStrLn "What?" >> askUser
1259-- _ -> putStrLn "What?" >> askUser
1164−-- acidRain :: MonadIO m => 'StreamT' m Event
1261+-- acidRain :: MonadIO m => 'SerialT' m Event
1165-- acidRain = cycle1 $ liftIO (threadDelay 1000000) >> return (Harm 1)
1262-- acidRain = cycle1 $ liftIO (threadDelay 1000000) >> return (Harm 1)
1167−-- game :: ('MonadParallel' m, MonadState Int m) => 'StreamT' m ()
1264+-- game :: ('MonadAsync' m, MonadState Int m) => 'SerialT' m ()
1168-- game = do
1265-- game = do
1169-- event \<- userAction \`parallel` acidRain
1266-- event \<- userAction \`parallel` acidRain
1170-- case event of
1267-- case event of
@@ -1356,7 +1453,7 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
1356-- When it comes to concurrency, streamly can do everything that the @async@
1453-- When it comes to concurrency, streamly can do everything that the @async@
1357-- package can do and more. async provides applicative concurrency whereas
1454-- package can do and more. async provides applicative concurrency whereas
1358-- streamly provides both applicative and monadic concurrency. The
1455-- streamly provides both applicative and monadic concurrency. The
1359−-- 'ZipParallel' type behaves like the applicative instance of async. In
1456+-- 'ZipAsync' type behaves like the applicative instance of async. In
1360-- comparison to transient streamly has a first class streaming interface and
1457-- comparison to transient streamly has a first class streaming interface and
1361-- is a monad transformer that can be used universally in any Haskell monad
1458-- is a monad transformer that can be used universally in any Haskell monad
1362-- transformer stack. Streamly was in fact originally inspired by the
1459-- transformer stack. Streamly was in fact originally inspired by the