@@ -178,23 +178,43 @@ import Control.Monad
178import Control.Monad.IO.Class (MonadIO(..))
178import Control.Monad.IO.Class (MonadIO(..))
179import Control.Monad.Trans.Class (MonadTrans (lift))
179import Control.Monad.Trans.Class (MonadTrans (lift))
181+-- CAUTION: please keep setup and imports sections in sync
183−-- >>> import Prelude hiding (break, map, span, splitAt)
185+-- >>> import Data.Function ((&))
186+-- >>> import Streamly.Prelude ((|:), (|&))
184-- >>> import qualified Streamly.Prelude as Stream
187-- >>> import qualified Streamly.Prelude as Stream
185−-- >>> import qualified Streamly.Internal.Data.Stream.IsStream as Stream (parse, foldMany)
186-- >>> import qualified Streamly.Data.Fold as Fold
188-- >>> import qualified Streamly.Data.Fold as Fold
187−-- >>> import qualified Streamly.Internal.Data.Fold as Fold
189+--
188−-- >>> import qualified Streamly.Internal.Data.Parser as Parser
189−-- >>> import Control.Monad.IO.Class (MonadIO(..))
190−-- >>> import Control.Monad.Trans.Class (MonadTrans(lift))
191−-- >>> import Data.Function ((&))
192−-- >>> import Data.Char (toUpper)
193−-- >>> import Control.Concurrent
190+-- >>> import Control.Concurrent (threadDelay, myThreadId)
194−-- >>> import Control.Monad (forever)
191+-- >>> :{
192+-- delay n = Stream.fromEffect $ do
193+-- threadDelay (n * 1000000)
195+-- putStrLn (show tid ++ ": Delay " ++ show n)
195-- >>> import System.IO (stdout, hSetBuffering, BufferMode(LineBuffering))
198-- >>> import System.IO (stdout, hSetBuffering, BufferMode(LineBuffering))
196−-- >>> import Streamly.Prelude
199+-- >>> hSetBuffering stdout LineBuffering
204+-- In most of example snippets we do not repeat the imports. Where imports are
205+-- not explicitly specified use the imports shown below.
208+-- >>> import Data.Function ((&))
209+-- >>> import Streamly.Prelude ((|:), (|&))
210+-- >>> import qualified Streamly.Prelude as Stream
211+-- >>> import qualified Streamly.Data.Fold as Fold
213+-- To illustrate concurrent vs serial composition aspects, we will use the
214+-- following @delay@ function to introduce a sleep or delay specified in
215+-- seconds. After the delay it prints the number of seconds it slept.
217+-- >>> import Control.Concurrent (threadDelay, myThreadId)
199-- delay n = Stream.fromEffect $ do
219-- delay n = Stream.fromEffect $ do
200-- threadDelay (n * 1000000)
220-- threadDelay (n * 1000000)
@@ -202,7 +222,13 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
202-- putStrLn (show tid ++ ": Delay " ++ show n)
222-- putStrLn (show tid ++ ": Delay " ++ show n)
225+-- For concurrent examples, use line buffering, otherwise output from different
226+-- threads may get mixed:
228+-- >>> import System.IO (stdout, hSetBuffering, BufferMode(LineBuffering))
229+-- >>> hSetBuffering stdout LineBuffering
206-- $streams
232-- $streams
208-- The monadic stream API offered by Streamly is very close to the Haskell
234-- The monadic stream API offered by Streamly is very close to the Haskell
@@ -356,22 +382,20 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
356-- To lift a value from an underlying monad in a monad transformer stack into a
382-- To lift a value from an underlying monad in a monad transformer stack into a
357-- singleton stream use 'lift' and to lift from an IO action use 'liftIO'.
383-- singleton stream use 'lift' and to lift from an IO action use 'liftIO'.
359−-- @
385+-- >>> import Control.Monad.IO.Class (liftIO)
360-- >>> Stream.drain $ liftIO $ putStrLn "Hello world!"
386-- >>> Stream.drain $ liftIO $ putStrLn "Hello world!"
361-- Hello world!
387-- Hello world!
389+-- >>> import Control.Monad.Trans.Class (MonadTrans(lift))
363-- >>> Stream.drain $ lift $ putStrLn "Hello world!"
390-- >>> Stream.drain $ lift $ putStrLn "Hello world!"
364-- Hello world!
391-- Hello world!
369-- $generating
394-- $generating
371-- 'nil' represents an empty stream and 'consM' or its operator form '|:' adds
396-- 'nil' represents an empty stream and 'consM' or its operator form '|:' adds
372-- a monadic action at the head of the stream.
397-- a monadic action at the head of the stream.
375-- >>> Stream.toList Stream.nil
399-- >>> Stream.toList Stream.nil
@@ -380,14 +404,11 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
381-- ["hello","world"]
405-- ["hello","world"]
385-- To create a singleton stream from a pure value use 'fromPure' or 'pure' and to
407-- To create a singleton stream from a pure value use 'fromPure' or 'pure' and to
386-- create a singleton stream from a monadic action use 'fromEffect'. Note that in
408-- create a singleton stream from a monadic action use 'fromEffect'. Note that in
387-- case of Zip applicative streams "pure" repeats the value to generate an
409-- case of Zip applicative streams "pure" repeats the value to generate an
388-- infinite stream.
410-- infinite stream.
391-- >>> Stream.toList $ pure 1
412-- >>> Stream.toList $ pure 1
@@ -398,29 +419,21 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
399-- ["hello"]
420-- ["hello"]
403-- To create a stream from pure values in a 'Foldable' container use
422-- To create a stream from pure values in a 'Foldable' container use
404-- 'fromFoldable' which is equivalent to a fold using 'cons' and 'nil':
423-- 'fromFoldable' which is equivalent to a fold using 'cons' and 'nil':
407-- >>> Stream.toList $ Stream.fromFoldable [1..3]
425-- >>> Stream.toList $ Stream.fromFoldable [1..3]
408-- [1,2,3]
426-- [1,2,3]
410-- >>> Stream.toList $ Prelude.foldr Stream.cons Stream.nil [1..3]
428-- >>> Stream.toList $ Prelude.foldr Stream.cons Stream.nil [1..3]
411-- [1,2,3]
429-- [1,2,3]
415-- To create a stream from monadic actions in a 'Foldable' container just use a
431-- To create a stream from monadic actions in a 'Foldable' container just use a
416-- right fold using 'consM' and 'nil':
432-- right fold using 'consM' and 'nil':
419-- >>> Stream.drain $ Prelude.foldr (|:) Stream.nil [putStr "Hello ", putStrLn "world!"]
434-- >>> Stream.drain $ Prelude.foldr (|:) Stream.nil [putStr "Hello ", putStrLn "world!"]
420-- Hello world!
435-- Hello world!
424-- For more ways to construct a stream see the module "Streamly.Prelude".
437-- For more ways to construct a stream see the module "Streamly.Prelude".
426-- $generatingConcurrently
439-- $generatingConcurrently
@@ -434,23 +447,16 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
435-- The following code finishes in 3 seconds (6 seconds when serial):
448-- The following code finishes in 3 seconds (6 seconds when serial):
438-- >>> let p n = threadDelay (n * 1000000) >> return n
450-- >>> let p n = threadDelay (n * 1000000) >> return n
439-- >>> Stream.toList $ Stream.fromParallel $ p 3 |: p 2 |: p 1 |: Stream.nil
451-- >>> Stream.toList $ Stream.fromParallel $ p 3 |: p 2 |: p 1 |: Stream.nil
440-- [1,2,3]
452-- [1,2,3]
442−-- (3.01 secs, 2,018,432 bytes)
443-- >>> Stream.toList $ Stream.fromAhead $ p 3 |: p 2 |: p 1 |: Stream.nil
454-- >>> Stream.toList $ Stream.fromAhead $ p 3 |: p 2 |: p 1 |: Stream.nil
444-- [3,2,1]
455-- [3,2,1]
446−-- (3.01 secs, 2,055,880 bytes)
448-- The following finishes in 10 seconds (100 seconds when serial):
457-- The following finishes in 10 seconds (100 seconds when serial):
451−-- Stream.'drain' $ Stream.'fromAsync' $ Stream.'replicateM' 10 $ p 10
459+-- >>> Stream.drain $ Stream.fromAsync $ Stream.replicateM 10 $ p 10
452−-- (10.01 secs, 2,080,320 bytes)
456-- $eliminating
462-- $eliminating
@@ -475,24 +481,30 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
475-- Here is a simple console echo program that just echoes every input line,
481-- Here is a simple console echo program that just echoes every input line,
476-- forever:
482-- forever:
479−-- Stream.'drain' $ Stream.'repeatM' getLine & Stream.'mapM' putStrLn
486+-- Stream.repeatM getLine
480−-- @
487+-- & Stream.mapM putStrLn
482-- The following code snippet reads lines from standard input, filters blank
491-- The following code snippet reads lines from standard input, filters blank
483-- lines, drops the first non-blank line, takes the next two, up cases them,
492-- lines, drops the first non-blank line, takes the next two, up cases them,
484-- numbers them and prints them:
493-- numbers them and prints them:
486−-- @
495+-- >>> import Data.Char (toUpper)
487−-- main = Stream.'drain' $
497+-- main =
488−-- Stream.'repeatM' getLine
498+-- Stream.repeatM getLine
489−-- & Stream.'filter' (not . null)
499+-- & Stream.filter (not . null)
490−-- & Stream.'drop' 1
500+-- & Stream.drop 1
491−-- & Stream.'take' 2
501+-- & Stream.take 2
492−-- & fmap (map toUpper)
502+-- & fmap (map toUpper)
493−-- & Stream.'zipWith' (\\n s -> show n ++ " " ++ s) (Stream.'fromFoldable' [1..])
503+-- & Stream.zipWith (\n s -> show n ++ " " ++ s) (Stream.fromFoldable [1..])
494−-- & Stream.'mapM' putStrLn
504+-- & Stream.mapM putStrLn
495−-- @
505+-- & Stream.drain
497-- $concurrentTransformation
509-- $concurrentTransformation
@@ -503,10 +515,15 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
504-- This would print a value every second (2 seconds when serial):
516-- This would print a value every second (2 seconds when serial):
507−-- let p n = threadDelay (n * 1000000) >> return n
518+-- >>> let p n = threadDelay (n * 1000000) >> return n
521+-- Stream.repeatM (p 1)
522+-- & Stream.fromSerial -- repeatM is serial
508−-- Stream.'drain' $ Stream.'fromAhead' $ Stream.'mapM' (\\x -> p 1 >> print x) (Stream.'fromSerial' $ Stream.'repeatM' (p 1))
523+-- & Stream.mapM (\x -> p 1 >> print x)
524+-- & Stream.fromAhead -- mapM is cocnurrent using Ahead style
512-- $concurrentApplication
529-- $concurrentApplication
@@ -518,10 +535,13 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
518-- Because both the stages run concurrently, we would see a delay of only 1
535-- Because both the stages run concurrently, we would see a delay of only 1
519-- second instead of 2 seconds in the following:
536-- second instead of 2 seconds in the following:
522−-- let p n = threadDelay (n * 1000000) >> return n
538+-- >>> let p n = threadDelay (n * 1000000) >> return n
541+-- Stream.repeatM (p 1)
523−-- Stream.'drain' $ Stream.'repeatM' (p 1) '|&' Stream.'mapM' (\\x -> p 1 >> print x)
542+-- |& Stream.mapM (\x -> p 1 >> print x)
524−-- @
543+-- & Stream.drain
526-- $semigroup
546-- $semigroup
@@ -532,42 +552,6 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
532-- style can be changed at any point using one of the type combinators as
552-- style can be changed at any point using one of the type combinators as
533-- discussed earlier.
553-- discussed earlier.
537−-- In most of example snippets we do not repeat the imports. Where imports are
538−-- not explicitly specified use the imports shown below.
541−-- import Control.Concurrent
542−-- import Control.Monad (forever)
543−-- import Control.Monad.IO.Class (MonadIO(..))
544−-- import Control.Monad.Trans.Class (MonadTrans(lift))
545−-- import Data.Function ((&))
546−-- import Data.Char (toUpper)
547−-- import Prelude hiding (break, map, span, splitAt)
548−-- import System.IO (stdout, hSetBuffering, BufferMode(LineBuffering))
549−-- import qualified Streamly.Prelude as Stream
550−-- import qualified Streamly.Internal.Data.Stream.IsStream as Stream (parse, foldMany)
551−-- import qualified Streamly.Data.Fold as Fold
552−-- import qualified Streamly.Internal.Data.Fold as Fold
553−-- import qualified Streamly.Internal.Data.Parser as Parser
554−-- import Streamly.Prelude
557−-- To illustrate concurrent vs serial composition aspects, we will use the
558−-- following @delay@ function to introduce a sleep or delay specified in
559−-- seconds. After the delay it prints the number of seconds it slept.
563−-- delay n = Stream.fromEffect $ do
564−-- threadDelay (n * 1000000)
566−-- putStrLn (show tid ++ ": Delay " ++ show n)
571-- $serial
555-- $serial
573-- The 'Semigroup' operation '<>' of the 'Serial' type combines the two streams
557-- The 'Semigroup' operation '<>' of the 'Serial' type combines the two streams
@@ -586,39 +570,33 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
586-- before we move to the next. The following example prints the sequence 1, 2,
570-- before we move to the next. The following example prints the sequence 1, 2,
590−-- >>> Stream.drain $ (print 1 |: print 2 |: Stream.nil) <> (print 3 |: print 4 |: Stream.nil)
573+-- >>> stream1 = print 1 |: print 2 |: Stream.nil
574+-- >>> stream2 = print 3 |: print 4 |: Stream.nil
575+-- >>> Stream.drain $ stream1 <> stream2
598-- All actions in both the streams are performed serially in the same thread.
581-- All actions in both the streams are performed serially in the same thread.
599-- In the following example we can see that all actions are performed in the
582-- In the following example we can see that all actions are performed in the
600-- same thread and take a combined total of @3 + 2 + 1 = 6@ seconds:
583-- same thread and take a combined total of @3 + 2 + 1 = 6@ seconds:
603-- >>> Stream.drain $ delay 3 <> delay 2 <> delay 1
585-- >>> Stream.drain $ delay 3 <> delay 2 <> delay 1
604-- ThreadId ... Delay 3
586-- ThreadId ... Delay 3
605-- ThreadId ... Delay 2
587-- ThreadId ... Delay 2
606-- ThreadId ... Delay 1
588-- ThreadId ... Delay 1
610-- The polymorphic version of the binary operation '<>' of the 'Serial' type is
590-- The polymorphic version of the binary operation '<>' of the 'Serial' type is
611-- 'serial'. We can use 'serial' to join streams in a sequential manner
591-- 'serial'. We can use 'serial' to join streams in a sequential manner
612-- irrespective of the type of stream:
592-- irrespective of the type of stream:
615−-- >>> Stream.drain $ (print 1 |: print 2 |: Stream.nil) `Stream.serial` (print 3 |: print 4 |: Stream.nil)
594+-- >>> Stream.drain $ stream1 `Stream.serial` stream2
623-- $interleaved
601-- $interleaved
@@ -633,42 +611,35 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
633-- to the first stream again and so on.
611-- to the first stream again and so on.
634-- The following example prints the sequence 1, 3, 2, 4
612-- The following example prints the sequence 1, 3, 2, 4
637−-- >>> Stream.drain . Stream.fromWSerial $ (print 1 |: print 2 |: Stream.nil) <> (print 3 |: print 4 |: Stream.nil)
614+-- >>> stream1 = print 1 |: print 2 |: Stream.nil
615+-- >>> stream2 = print 3 |: print 4 |: Stream.nil
616+-- >>> Stream.drain $ Stream.fromWSerial $ stream1 <> stream2
645-- Even though the monadic actions of the two streams are performed in an
622-- Even though the monadic actions of the two streams are performed in an
646-- interleaved manner they are all performed serially in the same thread. In
623-- interleaved manner they are all performed serially in the same thread. In
647-- the following example we can see that all actions are performed in the same
624-- the following example we can see that all actions are performed in the same
648-- thread and take a combined total of @3 + 2 + 1 = 6@ seconds:
625-- thread and take a combined total of @3 + 2 + 1 = 6@ seconds:
651−-- >>> Stream.drain . Stream.fromWSerial $ delay 3 <> delay 2 <> delay 1
627+-- >>> Stream.drain $ Stream.fromWSerial $ delay 3 <> delay 2 <> delay 1
652-- ThreadId ...: Delay 3
628-- ThreadId ...: Delay 3
653-- ThreadId ...: Delay 2
629-- ThreadId ...: Delay 2
654-- ThreadId ...: Delay 1
630-- ThreadId ...: Delay 1
658-- The polymorphic version of the 'WSerial' binary operation '<>' is called
632-- The polymorphic version of the 'WSerial' binary operation '<>' is called
659-- 'wSerial'. We can use 'wSerial' to join streams in an interleaved manner
633-- 'wSerial'. We can use 'wSerial' to join streams in an interleaved manner
660-- irrespective of the type, notice that we have not used the fromWSerial
634-- irrespective of the type, notice that we have not used the fromWSerial
661-- combinator in the following example:
635-- combinator in the following example:
664−-- >>> Stream.drain $ (print 1 |: print 2 |: Stream.nil) `Stream.wSerial` (print 3 |: print 4 |: Stream.nil)
637+-- >>> Stream.drain $ stream1 `Stream.wSerial` stream2
672-- Note that this composition cannot be used to fold infinite number of streams
643-- Note that this composition cannot be used to fold infinite number of streams
673-- since it requires preserving the state until a stream is finished.
644-- since it requires preserving the state until a stream is finished.
@@ -688,19 +659,14 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
688-- demand. The following example would print the result in a second even
659-- demand. The following example would print the result in a second even
689-- though each action in each stream takes one second:
660-- though each action in each stream takes one second:
692-- >>> p n = threadDelay 1000000 >> return n
662-- >>> p n = threadDelay 1000000 >> return n
693−-- >>> :{
663+-- >>> stream1 = p 1 |: p 2 |: Stream.nil
694−-- do
664+-- >>> stream2 = p 3 |: p 4 |: Stream.nil
695−-- xs <- Stream.toList . Stream.fromAhead $ (p 1 |: p 2 |: Stream.nil) <> (p 3 |: p 4 |: Stream.nil)
665+-- >>> Stream.toList $ Stream.fromAhead $ stream1 <> stream2
698-- [1,2,3,4]
666-- [1,2,3,4]
702−-- Each stream is constructed 'aheadly' and then both the streams are merged
668+-- Each stream is constructed 'fromAhead' and then both the streams are merged
703−-- 'aheadly', therefore, all the actions can run concurrently but the result is
669+-- 'fromAhead', therefore, all the actions can run concurrently but the result is
704-- presented in serial order.
670-- presented in serial order.
706-- You can also use the polymorphic combinator 'ahead' in place of '<>' to
672-- You can also use the polymorphic combinator 'ahead' in place of '<>' to
@@ -726,40 +692,32 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
726-- of 1 second, however, it takes just one second to produce all the results.
692-- of 1 second, however, it takes just one second to produce all the results.
727-- The results are not guaranteed to be in any particular order:
693-- The results are not guaranteed to be in any particular order:
730−-- p n = threadDelay 1000000 >> return n
695+-- >>> p n = threadDelay 1000000 >> return n
731−-- do
696+-- >>> stream1 = p 1 |: p 2 |: Stream.nil
697+-- >>> stream2 = p 3 |: p 4 |: Stream.nil
732−-- xs <- Stream.toList . Stream.fromAsync $ (p 1 |: p 2 |: Stream.nil) <> (p 3 |: p 4 |: Stream.nil)
698+-- >>> Stream.toList $ Stream.fromAsync $ stream1 <> stream2
733−-- print xs
699+-- ...
738-- The constituent streams are also composed in 'Async' manner and the
701-- The constituent streams are also composed in 'Async' manner and the
739-- composition of streams too. We can compose the constituent streams to run
702-- composition of streams too. We can compose the constituent streams to run
740-- serially, in that case it would take 2 seconds to produce all the results.
703-- serially, in that case it would take 2 seconds to produce all the results.
741-- The elements in the serial streams would be in serial order in the results:
704-- The elements in the serial streams would be in serial order in the results:
744−-- > p n = threadDelay 1000000 >> return n
706+-- >>> p n = threadDelay 1000000 >> return n
707+-- >>> stream = (Stream.fromSerial stream1) <> (Stream.fromSerial stream2)
745−-- > Stream.toList . Stream.fromAsync $ (Stream.fromSerial $ p 1 |: p 2 |: Stream.nil) <> (fromSerial $ p 3 |: p 4 |: Stream.nil)
708+-- >>> Stream.toList $ Stream.fromAsync stream
746−-- [1,3,4,2] -- order is not predictable
709+-- ...
750-- In the following example we can see that new threads are started when a
711-- In the following example we can see that new threads are started when a
751-- computation blocks. Notice that the output from the stream with the
712-- computation blocks. Notice that the output from the stream with the
752-- shortest delay is printed first. The whole computation takes @maximum of
713-- shortest delay is printed first. The whole computation takes @maximum of
753-- (3, 2, 1) = 3@ seconds:
714-- (3, 2, 1) = 3@ seconds:
756−-- >>> Stream.drain . Stream.fromAsync $ delay 3 <> delay 2 <> delay 1
716+-- >>> Stream.drain $ Stream.fromAsync $ delay 3 <> delay 2 <> delay 1
757-- ThreadId ...: Delay 1
717-- ThreadId ...: Delay 1
758-- ThreadId ...: Delay 2
718-- ThreadId ...: Delay 2
759-- ThreadId ...: Delay 3
719-- ThreadId ...: Delay 3
763-- When we have a tree of computations composed using this style, the tree is
721-- When we have a tree of computations composed using this style, the tree is
764-- traversed in DFS style just like the 'Serial' style, the only difference is
722-- traversed in DFS style just like the 'Serial' style, the only difference is
765-- that here we can move on to executing the next stream if a stream blocks.
723-- that here we can move on to executing the next stream if a stream blocks.
@@ -770,15 +728,12 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
770-- the pull rate of the consumer. The following example prints an output every
728-- the pull rate of the consumer. The following example prints an output every
771-- second as all of the actions are concurrent.
729-- second as all of the actions are concurrent.
774−-- >>> Stream.drain . Stream.fromAsync $ (delay 1 <> delay 2) <> (delay 3 <> delay 4)
731+-- >>> Stream.drain $ Stream.fromAsync $ (delay 1 <> delay 2) <> (delay 3 <> delay 4)
775-- ThreadId ...: Delay 1
732-- ThreadId ...: Delay 1
776-- ThreadId ...: Delay 2
733-- ThreadId ...: Delay 2
777-- ThreadId ...: Delay 3
734-- ThreadId ...: Delay 3
778-- ThreadId ...: Delay 4
735-- ThreadId ...: Delay 4
782-- All the computations may even run in a single thread when more threads are
737-- All the computations may even run in a single thread when more threads are
783-- not needed. As you can see, in the following example the computations are
738-- not needed. As you can see, in the following example the computations are
784-- run in a single thread one after another, because none of them blocks.
739-- run in a single thread one after another, because none of them blocks.
@@ -786,15 +741,11 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
786-- then it would have started parallel threads for each computation to keep up
741-- then it would have started parallel threads for each computation to keep up
787-- even if none of them blocks:
742-- even if none of them blocks:
790−-- main = Stream.'drain' . Stream.'fromAsync' $ traced (sqrt 9) '<>' traced (sqrt 16) '<>' traced (sqrt 25)
791−-- where traced m = Stream.'fromEffect' (myThreadId >>= print) >> return m
745+-- traced m = Stream.fromEffect (myThreadId >>= print) >> return m
792−-- @
746+-- stream = traced (sqrt 9) <> traced (sqrt 16) <> traced (sqrt 25)
793−-- @
747+-- main = Stream.drain $ Stream.fromAsync stream
799-- Note that the order of printing in the above examples may change due to
750-- Note that the order of printing in the above examples may change due to
800-- variations in scheduling latencies for concurrent threads.
751-- variations in scheduling latencies for concurrent threads.
@@ -804,14 +755,11 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
804-- adaptively concurrent manner irrespective of the type, notice that we have
755-- adaptively concurrent manner irrespective of the type, notice that we have
805-- not used the 'fromAsync' combinator in the following example:
756-- not used the 'fromAsync' combinator in the following example:
808-- >>> Stream.drain $ delay 3 `Stream.async` delay 2 `Stream.async` delay 1
758-- >>> Stream.drain $ delay 3 `Stream.async` delay 2 `Stream.async` delay 1
809-- ThreadId ...: Delay 1
759-- ThreadId ...: Delay 1
810-- ThreadId ...: Delay 2
760-- ThreadId ...: Delay 2
811-- ThreadId ...: Delay 3
761-- ThreadId ...: Delay 3
815-- Since the concurrency provided by this operator is demand driven it cannot
763-- Since the concurrency provided by this operator is demand driven it cannot
816-- be used when the composed computations start timers that are relative to
764-- be used when the composed computations start timers that are relative to
817-- each other because all computations may not be started at the same time and
765-- each other because all computations may not be started at the same time and
@@ -846,32 +794,24 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
846-- In the following example we can see that outputs are produced in the breadth
794-- In the following example we can see that outputs are produced in the breadth
847-- first traversal order but this is not guaranteed.
795-- first traversal order but this is not guaranteed.
849−-- @
797+-- >>> stream1 = print 1 |: print 2 |: Stream.nil
850−-- >>> :{
798+-- >>> stream2 = print 3 |: print 4 |: Stream.nil
851−-- do
799+-- >>> Stream.drain $ Stream.fromWAsync $ stream1 <> stream2
852−-- hSetBuffering stdout LineBuffering
853−-- Stream.drain . Stream.fromWAsync $ (Stream.fromSerial $ print 1 |: print 2 |: Stream.nil) <> (Stream.fromSerial $ print 3 |: print 4 |: Stream.nil)
862-- The polymorphic version of the binary operation '<>' of the 'WAsync' type is
805-- The polymorphic version of the binary operation '<>' of the 'WAsync' type is
863-- 'wAsync'. We can use 'wAsync' to join streams using a breadth first
806-- 'wAsync'. We can use 'wAsync' to join streams using a breadth first
864-- concurrent traversal irrespective of the type, notice that we have not used
807-- concurrent traversal irrespective of the type, notice that we have not used
865-- the 'fromWAsync' combinator in the following example:
808-- the 'fromWAsync' combinator in the following example:
868-- >>> Stream.drain $ delay 3 `Stream.wAsync` delay 2 `Stream.wAsync` delay 1
810-- >>> Stream.drain $ delay 3 `Stream.wAsync` delay 2 `Stream.wAsync` delay 1
869-- ThreadId ...: Delay 1
811-- ThreadId ...: Delay 1
870-- ThreadId ...: Delay 2
812-- ThreadId ...: Delay 2
871-- ThreadId ...: Delay 3
813-- ThreadId ...: Delay 3
875-- Since the concurrency provided by this style is demand driven it may not
815-- Since the concurrency provided by this style is demand driven it may not
876-- be used when the composed computations start timers that are relative to
816-- be used when the composed computations start timers that are relative to
877-- each other because all computations may not be started at the same time and
817-- each other because all computations may not be started at the same time and
@@ -897,36 +837,16 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
897-- may not execute all actions in parallel depending on the demand, whereas
837-- may not execute all actions in parallel depending on the demand, whereas
898-- 'Parallel' runs all the streams in parallel irrespective of the demand.
838-- 'Parallel' runs all the streams in parallel irrespective of the demand.
900−-- The following example sends a query to all the three search engines in
901−-- parallel and prints the name of the search engines in the order in which the
902−-- responses arrive. You need the [http-conduit](http://hackage.haskell.org/package/http-conduit)
903−-- package to run this example:
906−-- import qualified Streamly.Prelude as Stream
907−-- import Network.HTTP.Simple
909−-- main = Stream.'drain' . Stream.'fromParallel' $ google \<> bing \<> duckduckgo
911−-- google = get "https://www.google.com/search?q=haskell"
912−-- bing = get "https://www.bing.com/search?q=haskell"
913−-- duckduckgo = get "https://www.duckduckgo.com/?q=haskell"
914−-- get s = Stream.'fromEffect' (httpNoBody (parseRequest_ s) >> putStrLn (show s))
917-- The polymorphic version of the binary operation '<>' of the 'Parallel' type
840-- The polymorphic version of the binary operation '<>' of the 'Parallel' type
918-- is 'parallel'. We can use 'parallel' to join streams in a fairly concurrent
841-- is 'parallel'. We can use 'parallel' to join streams in a fairly concurrent
919-- manner irrespective of the type, notice that we have not used the
842-- manner irrespective of the type, notice that we have not used the
920-- 'fromParallel' combinator in the following example:
843-- 'fromParallel' combinator in the following example:
923-- >>> Stream.drain $ delay 3 `Stream.parallel` delay 2 `Stream.wAsync` delay 1
845-- >>> Stream.drain $ delay 3 `Stream.parallel` delay 2 `Stream.wAsync` delay 1
924-- ThreadId ...: Delay 1
846-- ThreadId ...: Delay 1
925-- ThreadId ...: Delay 2
847-- ThreadId ...: Delay 2
926-- ThreadId ...: Delay 3
848-- ThreadId ...: Delay 3
930-- Note that this style of composition cannot be used to combine infinite
850-- Note that this style of composition cannot be used to combine infinite
931-- number of streams, as it will lead to an infinite sized scheduling queue.
851-- number of streams, as it will lead to an infinite sized scheduling queue.
@@ -960,17 +880,14 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
960-- a delay from 1 to 10 seconds, resulting in the printing of each number every
880-- a delay from 1 to 10 seconds, resulting in the printing of each number every
961-- second:
881-- second:
964−-- import qualified "Streamly.Prelude" as Stream
965−-- import Control.Concurrent
967-- main = do
884-- main = do
968−-- Stream.'drain' $ Stream.'fromAsync' $ foldMap delay [1..10]
885+-- Stream.drain $ Stream.fromAsync $ foldMap delay [1..10]
969−-- Stream.'drain' $ Stream.'concatFoldableWith' Stream.'async' (map delay [1..10])
886+-- Stream.drain $ Stream.concatFoldableWith Stream.async (map delay [1..10])
970−-- Stream.'drain' $ Stream.'concatMapFoldableWith' Stream.'async' delay [1..10]
887+-- Stream.drain $ Stream.concatMapFoldableWith Stream.async delay [1..10]
971−-- Stream.'drain' $ Stream.'concatForFoldableWith' Stream.'async' [1..10] delay
888+-- Stream.drain $ Stream.concatForFoldableWith Stream.async [1..10] delay
972−-- where delay n = Stream.'fromEffect' $ threadDelay (n * 1000000) >> print n
889+-- :}
975-- $nesting
892-- $nesting
@@ -1013,7 +930,6 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
1013-- the examples. However, the streams could also be made of monadic actions
930-- the examples. However, the streams could also be made of monadic actions
1014-- instead.
931-- instead.
1017-- >>> :{
933-- >>> :{
1018-- Stream.drain $ do
934-- Stream.drain $ do
1019-- x <- Stream.fromFoldable [3,2,1]
935-- x <- Stream.fromFoldable [3,2,1]
@@ -1023,26 +939,24 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
1023-- ThreadId ...: Delay 2
939-- ThreadId ...: Delay 2
1024-- ThreadId ...: Delay 1
940-- ThreadId ...: Delay 1
1028-- As we can see, the code after the @fromFoldable@ statement is run three
942-- As we can see, the code after the @fromFoldable@ statement is run three
1029-- times, once for each value of @x@ drawn from the stream. All the three
943-- times, once for each value of @x@ drawn from the stream. All the three
1030-- iterations are serial and run in the same thread one after another. In
944-- iterations are serial and run in the same thread one after another. In
1031-- imperative terms this is equivalent to a @for@ loop with three iterations.
945-- imperative terms this is equivalent to a @for@ loop with three iterations.
1033−-- A console echo loop copying standard input to standard output can simply be
947+-- We can write the console echo program that we wrote earlier using the monad
1034−-- written like this:
948+-- instance:
953+-- x <- Stream.repeatM getLine
1037−-- main = Stream.'drain' $ forever $ Stream.'fromEffect' getLine >>= Stream.'fromEffect' . putStrLn
954+-- Stream.fromEffect $ putStrLn x
1040-- When multiple streams are composed using this style they nest in a DFS
957-- When multiple streams are composed using this style they nest in a DFS
1041−-- manner i.e. nested iterations of a loop are executed before we proceed to
958+-- manner:
1042−-- the next iteration of the parent loop. This behaves just like nested @for@
1043−-- loops in imperative programming.
1046-- >>> :{
960-- >>> :{
1047-- Stream.drain $ do
961-- Stream.drain $ do
1048-- x <- Stream.fromFoldable [1,2]
962-- x <- Stream.fromFoldable [1,2]
@@ -1054,7 +968,9 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
1057−-- @
971+-- i.e. inner loop iterations ((1,3), (1,4)) are executed before we proceed to
972+-- the next iteration of the outer loop ((2,3), (2,4)). This behaves just like
973+-- nested @for@ loops in imperative programming.
1059-- Notice that this is analogous to merging streams of type 'Serial' or merging
975-- Notice that this is analogous to merging streams of type 'Serial' or merging
1060-- streams using 'serial'.
976-- streams using 'serial'.
@@ -1065,25 +981,17 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
1065-- that it can speculatively perform a bounded number of next iterations of a
981-- that it can speculatively perform a bounded number of next iterations of a
1066-- loop concurrently.
982-- loop concurrently.
1068−-- The 'fromAhead' type combinator can be used to switch to this style of
1069−-- composition. Alternatively, a type annotation can be used to specify the
1070−-- type of the stream as 'Ahead'.
1073-- >>> :{
984-- >>> :{
1074−-- comp = Stream.toList . Stream.fromAhead $ do
985+-- Stream.toList $ Stream.fromAhead $ do
1075−-- x <- Stream.fromFoldable [3,2,1]
986+-- x <- Stream.fromFoldable [3,2,1]
1076−-- delay x >> return x
988+-- return x
1079−-- >>> comp >>= print
1080-- ThreadId ...: Delay 1
990-- ThreadId ...: Delay 1
1081-- ThreadId ...: Delay 2
991-- ThreadId ...: Delay 2
1082-- ThreadId ...: Delay 3
992-- ThreadId ...: Delay 3
1083-- [3,2,1]
993-- [3,2,1]
1087-- This code finishes in 3 seconds, 'Serial' would take 6 seconds. As we can
995-- This code finishes in 3 seconds, 'Serial' would take 6 seconds. As we can
1088-- see all the three iterations are concurrent and run in different threads,
996-- see all the three iterations are concurrent and run in different threads,
1089-- however, the results are returned in the serial order.
997-- however, the results are returned in the serial order.
@@ -1094,23 +1002,18 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
1094-- outer iteration. The only difference is that we may execute multiple future
1002-- outer iteration. The only difference is that we may execute multiple future
1095-- iterations concurrently and keep the results ready.
1003-- iterations concurrently and keep the results ready.
1005+-- The 'fromAhead' type combinator can be used to switch to this style of
1006+-- composition. Alternatively, a type annotation can be used to specify the
1007+-- type of the stream as 'Ahead'.
1098-- $concurrentNesting
1010-- $concurrentNesting
1100-- The 'Monad' composition of 'Async' type can perform the iterations of a
1012-- The 'Monad' composition of 'Async' type can perform the iterations of a
1101−-- loop concurrently. Concurrency is demand driven i.e. more concurrent
1013+-- loop concurrently.
1102−-- iterations are started only if the previous iterations are not able to
1103−-- produce enough output for the consumer of the output stream. This works
1104−-- exactly the same way as the merging of two streams 'asyncly' works.
1105−-- This is the concurrent analogue of 'Serial' style monadic composition.
1107−-- The 'fromAsync' type combinator can be used to switch to this style of
1108−-- composition. Alternatively, a type annotation can be used to specify the
1109−-- type of the stream as 'Async'.
1112-- >>> :{
1015-- >>> :{
1113−-- Stream.drain . Stream.fromAsync $ do
1016+-- Stream.drain $ Stream.fromAsync $ do
1114-- x <- Stream.fromFoldable [3,2,1]
1017-- x <- Stream.fromFoldable [3,2,1]
1115-- delay x
1018-- delay x
@@ -1118,47 +1021,46 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
1118-- ThreadId ...: Delay 2
1021-- ThreadId ...: Delay 2
1119-- ThreadId ...: Delay 3
1022-- ThreadId ...: Delay 3
1123-- As we can see the code after the @fromFoldable@ statement is run three
1024-- As we can see the code after the @fromFoldable@ statement is run three
1124-- times, once for each value of @x@. All the three iterations are concurrent
1025-- times, once for each value of @x@. All the three iterations are concurrent
1125-- and run in different threads. The iteration with least delay finishes first.
1026-- and run in different threads. The iteration with least delay finishes first.
1126-- When compared to imperative programming, this can be viewed as a @for@ loop
1027-- When compared to imperative programming, this can be viewed as a @for@ loop
1127-- with three concurrent iterations.
1028-- with three concurrent iterations.
1129−-- Concurrency is demand driven just as in the case of 'async' merging.
1030+-- Concurrency is demand driven i.e. more concurrent iterations are started
1130−-- When multiple streams are composed using this style, the iterations are
1031+-- only if the previous iterations are not able to saturate the consumer of the
1131−-- triggered in a depth first manner just like 'Serial' i.e. nested iterations are
1032+-- output stream. This works exactly the same way as the merging of two
1132−-- executed before we proceed to the next iteration at higher level. However,
1033+-- streams using 'async' works.
1133−-- unlike 'Serial' more than one iterations may be started concurrently based
1134−-- on the demand from the consumer of the stream.
1136−-- @
1035+-- The 'fromAsync' type combinator can be used to switch to this style of
1036+-- composition. Alternatively, a type annotation can be used to specify the
1037+-- type of the stream as 'Async'.
1039+-- When multiple streams are nested using this style, the iterations are
1040+-- concurrently evaluated in a depth first manner:
1138−-- Stream.drain . Stream.fromAsync $ do
1044+-- Stream.drain $ Stream.fromAsync $ do
1139-- x <- Stream.fromFoldable [1,2]
1045-- x <- Stream.fromFoldable [1,2]
1140-- y <- Stream.fromFoldable [3,4]
1046-- y <- Stream.fromFoldable [3,4]
1141-- Stream.fromEffect $ putStrLn $ show (x, y)
1047-- Stream.fromEffect $ putStrLn $ show (x, y)
1148−-- @
1054+-- Nested iterations are given preference for concurrent evaluation i.e.
1055+-- (1,4) will be scheduled in preference to (2,3).
1150-- $interleavedNesting
1057-- $interleavedNesting
1152-- The 'Monad' composition of 'WSerial' type interleaves the iterations of
1059-- The 'Monad' composition of 'WSerial' type interleaves the iterations of
1153−-- outer and inner loops in a nested loop composition. This works exactly the
1060+-- outer and inner loops in a nested loop composition.
1154−-- same way as the merging of two streams in 'wSerially' fashion works. The
1155−-- fromWSerial type combinator can be used to switch to this style of
1156−-- composition. Alternatively, a type annotation can be used to specify the
1157−-- type of the stream as 'WSerial'.
1160-- >>> :{
1062-- >>> :{
1161−-- Stream.drain . Stream.fromWSerial $ do
1063+-- Stream.drain $ Stream.fromWSerial $ do
1162-- x <- Stream.fromFoldable [1,2]
1064-- x <- Stream.fromFoldable [1,2]
1163-- y <- Stream.fromFoldable [3,4]
1065-- y <- Stream.fromFoldable [3,4]
1164-- Stream.fromEffect $ putStrLn $ show (x, y)
1066-- Stream.fromEffect $ putStrLn $ show (x, y)
@@ -1168,47 +1070,48 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
1171−-- @
1073+-- Note that (2,3) is preferred to (1,4). This works exactly the same way as
1074+-- the merging of two streams using 'wSerial' works.
1076+-- The fromWSerial type combinator can be used to switch to this style of
1077+-- composition. Alternatively, a type annotation can be used to specify the
1078+-- type of the stream as 'WSerial'.
1174-- $wasyncNesting
1081-- $wasyncNesting
1176−-- Just like 'Async' the 'Monad' composition of 'WAsync' runs the iterations of
1083+-- Like 'Async', the 'Monad' composition of 'WAsync' runs the iterations of a
1177−-- a loop concurrently. The difference is in the nested loop behavior. The
1084+-- loop concurrently. It differs from 'Async' in the nested loop behavior. Like
1178−-- nested loops in this type are traversed and executed in a breadth first
1085+-- 'WSerial', the nested loops in this type are traversed and executed in a
1179−-- manner rather than the depth first manner of 'Async' style.
1086+-- breadth first manner rather than the depth first manner of 'Async' style.
1180−-- The loop nesting works exactly the same way as the merging of streams
1181−-- 'wAsyncly' works. The 'fromWAsync' type combinator can be used to switch to
1182−-- this style of composition. Alternatively, a type annotation can be used to
1183−-- specify the type of the stream as 'WAsync'.
1186-- >>> :{
1088-- >>> :{
1187−-- Stream.drain . Stream.fromWAsync $ do
1089+-- Stream.drain $ Stream.fromWAsync $ do
1188−-- x <- Stream.delay 1 $ Stream.fromFoldable [1,2]
1090+-- x <- Stream.fromSerial $ Stream.fromFoldable [1,2]
1189−-- y <- Stream.delay 1 $ Stream.fromFoldable [3,4]
1091+-- y <- Stream.fromSerial $ Stream.fromFoldable [3,4]
1190-- Stream.fromEffect $ putStrLn $ show (x, y)
1092-- Stream.fromEffect $ putStrLn $ show (x, y)
1197−-- @
1099+-- Note that (2,3) is preferred to (1,4) when evaluating the iterations
1100+-- concurrently. This works exactly the same way as the merging of two streams
1101+-- using 'wAsync' works.
1103+-- The 'fromWAsync' type combinator can be used to switch to this style of
1104+-- composition. Alternatively, a type annotation can be used to specify the
1105+-- type of the stream as 'WAsync'.
1199-- $parallelNesting
1108-- $parallelNesting
1201-- Just like 'Async' or 'WAsync' the 'Monad' composition of 'Parallel' runs the
1110-- Just like 'Async' or 'WAsync' the 'Monad' composition of 'Parallel' runs the
1202−-- iterations of a loop concurrently. The difference is in the nested loop
1111+-- iterations of a loop concurrently.
1203−-- behavior. The streams at each nest level is run fully concurrently
1204−-- irrespective of the demand. The loop nesting works exactly the same way as
1205−-- the merging of streams 'parallely' works. The 'fromParallel' type combinator
1206−-- can be used to switch to this style of composition. Alternatively, a type
1207−-- annotation can be used to specify the type of the stream as 'Parallel'.
1210-- >>> :{
1113-- >>> :{
1211−-- Stream.drain . Stream.fromParallel $ do
1114+-- Stream.drain $ Stream.fromParallel $ do
1212-- x <- Stream.fromFoldable [3,2,1]
1115-- x <- Stream.fromFoldable [3,2,1]
1213-- delay x
1116-- delay x
@@ -1216,7 +1119,15 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
1216-- ThreadId ...: Delay 2
1119-- ThreadId ...: Delay 2
1217-- ThreadId ...: Delay 3
1120-- ThreadId ...: Delay 3
1219−-- @
1122+-- It differs from 'Async' and 'WAsync' in the nested loop behavior. All
1123+-- iterations of the loop are run fully concurrently irrespective of the
1124+-- demand. This works exactly the same way as the merging of streams using
1125+-- 'parallel' works.
1127+-- The 'fromParallel' type combinator can be used to switch to this style of
1128+-- composition. Alternatively, a type annotation can be used to specify the
1129+-- type of the stream as 'Parallel'.
1221-- $monadExercise
1132-- $monadExercise
@@ -1225,29 +1136,27 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
1225-- 'IsStream' type class constraint. When running the stream we can choose the
1136-- 'IsStream' type class constraint. When running the stream we can choose the
1226-- specific mode of composition. For example take a look at the following code.
1137-- specific mode of composition. For example take a look at the following code.
1229-- composed :: (Stream.IsStream t, Monad (t IO)) => t IO ()
1140-- composed :: (Stream.IsStream t, Monad (t IO)) => t IO ()
1230-- composed = do
1141-- composed = do
1231-- sz <- sizes
1142-- sz <- sizes
1232-- cl <- colors
1143-- cl <- colors
1233-- sh <- shapes
1144-- sh <- shapes
1234−-- Stream.'fromEffect' $ putStrLn $ show (sz, cl, sh)
1145+-- Stream.fromEffect $ putStrLn $ show (sz, cl, sh)
1238−-- sizes = Stream.'fromFoldable' [1, 2, 3]
1147+-- sizes = Stream.fromFoldable [1, 2, 3]
1239−-- colors = Stream.'fromFoldable' ["red", "green", "blue"]
1148+-- colors = Stream.fromFoldable ["red", "green", "blue"]
1240−-- shapes = Stream.'fromFoldable' ["triangle", "square", "circle"]
1149+-- shapes = Stream.fromFoldable ["triangle", "square", "circle"]
1243-- Now we can interpret this in whatever way we want:
1152-- Now we can interpret this in whatever way we want:
1246−-- main = Stream.'drain' . Stream.'fromSerial' $ composed
1155+-- main = Stream.'drain' $ Stream.'fromSerial' $ composed
1247−-- main = Stream.'drain' . Stream.'fromWSerial' $ composed
1156+-- main = Stream.'drain' $ Stream.'fromWSerial' $ composed
1248−-- main = Stream.'drain' . Stream.'fromAsync' $ composed
1157+-- main = Stream.'drain' $ Stream.'fromAsync' $ composed
1249−-- main = Stream.'drain' . Stream.'fromWAsync' $ composed
1158+-- main = Stream.'drain' $ Stream.'fromWAsync' $ composed
1250−-- main = Stream.'drain' . Stream.'fromParallel' $ composed
1159+-- main = Stream.'drain' $ Stream.'fromParallel' $ composed
1253-- As an exercise try to figure out the output of this code for each mode of
1162-- As an exercise try to figure out the output of this code for each mode of
@@ -1259,12 +1168,9 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
1259-- stream. 'fmap' behaves in the same way for all stream types, it is always
1168-- stream. 'fmap' behaves in the same way for all stream types, it is always
1260-- serial.
1169-- serial.
1263-- >>> (Stream.toList $ fmap show $ Stream.fromFoldable [1..10]) >>= print
1171-- >>> (Stream.toList $ fmap show $ Stream.fromFoldable [1..10]) >>= print
1264-- ["1","2","3","4","5","6","7","8","9","10"]
1172-- ["1","2","3","4","5","6","7","8","9","10"]
1268-- Also see functions 'mapM' and 'sequence' from "Streamly.Prelude" module
1174-- Also see functions 'mapM' and 'sequence' from "Streamly.Prelude" module
1269-- which can map actions concurrently depending on the type of the input stream.
1175-- which can map actions concurrently depending on the type of the input stream.
@@ -1274,15 +1180,14 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
1274-- zipping applicatives separate types 'ZipSerial' and 'ZipAsync' are
1180-- zipping applicatives separate types 'ZipSerial' and 'ZipAsync' are
1275-- provided.
1181-- provided.
1277−-- The following example uses the 'Serial' applicative, it runs all iterations
1183+-- The following is an example of 'Serial' applicative, it runs all iterations
1278-- serially and takes a total 17 seconds (1 + 3 + 4 + 2 + 3 + 4):
1184-- serially and takes a total 17 seconds (1 + 3 + 4 + 2 + 3 + 4):
1281-- >>> d n = delay n >> return n
1186-- >>> d n = delay n >> return n
1282-- >>> s1 = d 1 <> d 2
1187-- >>> s1 = d 1 <> d 2
1283-- >>> s2 = d 3 <> d 4
1188-- >>> s2 = d 3 <> d 4
1285−-- >>> (Stream.toList . Stream.fromSerial $ (,) <$> s1 <*> s2) >>= print
1190+-- >>> (Stream.toList $ Stream.fromSerial $ (,) <$> s1 <*> s2) >>= print
1286-- ThreadId ...: Delay 1
1191-- ThreadId ...: Delay 1
1287-- ThreadId ...: Delay 3
1192-- ThreadId ...: Delay 3
1288-- ThreadId ...: Delay 4
1193-- ThreadId ...: Delay 4
@@ -1291,13 +1196,10 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
1291-- ThreadId ...: Delay 4
1196-- ThreadId ...: Delay 4
1292-- [(1,3),(1,4),(2,3),(2,4)]
1197-- [(1,3),(1,4),(2,3),(2,4)]
1294−-- @
1199+-- Similarly, 'WSerial' applicative runs the iterations in an interleaved
1200+-- order but being serial it too takes a total of 17 seconds:
1296−-- Similarly 'WSerial' applicative runs the iterations in an interleaved
1297−-- order but since it is serial it takes a total of 17 seconds:
1300−-- >>> (Stream.toList . Stream.fromWSerial $ (,) <$> s1 <*> s2) >>= print
1202+-- >>> (Stream.toList $ Stream.fromWSerial $ (,) <$> s1 <*> s2) >>= print
1301-- ThreadId ...: Delay 1
1203-- ThreadId ...: Delay 1
1302-- ThreadId ...: Delay 3
1204-- ThreadId ...: Delay 3
1303-- ThreadId ...: Delay 2
1205-- ThreadId ...: Delay 2
@@ -1306,14 +1208,12 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
1306-- ThreadId ...: Delay 4
1208-- ThreadId ...: Delay 4
1307-- [(1,3),(2,3),(1,4),(2,4)]
1209-- [(1,3),(2,3),(1,4),(2,4)]
1311−-- 'Async' can run the iterations concurrently and therefore takes a total
1211+-- 'Async' can run the iterations concurrently, therefore, it takes a total
1312-- of 6 seconds which is max (1, 2) + max (3, 4):
1212-- of 6 seconds which is max (1, 2) + max (3, 4):
1315−-- main = (Stream.'toList' . Stream.'fromAsync' $ (,) \<$> s1 \<*> s2) >>= print
1214+-- >>> (Stream.toList $ Stream.fromAsync $ (,) <$> s1 <*> s2) >>= print
1318-- ThreadId 34: Delay 1
1218-- ThreadId 34: Delay 1
1319-- ThreadId 36: Delay 2
1219-- ThreadId 36: Delay 2
@@ -1324,12 +1224,13 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
1324-- [(1,3),(2,3),(1,4),(2,4)]
1224-- [(1,3),(2,3),(1,4),(2,4)]
1327−-- Similarly 'WAsync' as well can run the iterations concurrently and
1227+-- Similarly, 'WAsync' as well can run the iterations concurrently, but with a
1228+-- different style of scheduling than 'Async' as explained in the Monad
1328−-- therefore takes a total of 6 seconds (2 + 4):
1229+-- section, therefore, it too takes a total of 6 seconds (2 + 4):
1231+-- >>> (Stream.toList $ Stream.fromWAsync $ (,) <$> s1 <*> s2) >>= print
1331−-- main = (Stream.'toList' . Stream.'fromWAsync' $ (,) \<$> s1 \<*> s2) >>= print
1334-- ThreadId 34: Delay 1
1235-- ThreadId 34: Delay 1
1335-- ThreadId 36: Delay 2
1236-- ThreadId 36: Delay 2
@@ -1355,22 +1256,13 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
1355-- 'fromZipSerial' type combinator can be used to switch to serial applicative
1256-- 'fromZipSerial' type combinator can be used to switch to serial applicative
1356-- zip composition:
1257-- zip composition:
1360−-- d n = delay n >> return n
1361−-- s1 = Stream.'fromSerial' $ d 1 <> d 2
1362−-- s2 = Stream.'fromSerial' $ d 3 <> d 4
1364−-- main = (Stream.'toList' . Stream.'fromZipSerial' $ (,) \<$> s1 \<*> s2) >>= print
1367-- This takes total 10 seconds to zip, which is (1 + 2 + 3 + 4) since
1259-- This takes total 10 seconds to zip, which is (1 + 2 + 3 + 4) since
1368-- everything runs serially:
1260-- everything runs serially:
1370-- >>> d n = delay n >> return n
1262-- >>> d n = delay n >> return n
1371-- >>> s1 = Stream.fromSerial $ d 1 <> d 2
1263-- >>> s1 = Stream.fromSerial $ d 1 <> d 2
1372-- >>> s2 = Stream.fromSerial $ d 3 <> d 4
1264-- >>> s2 = Stream.fromSerial $ d 3 <> d 4
1373−-- >>> (Stream.toList . Stream.fromZipSerial $ (,) <$> s1 <*> s2) >>= print
1265+-- >>> (Stream.toList $ Stream.fromZipSerial $ (,) <$> s1 <*> s2) >>= print
1374-- ThreadId ...: Delay 1
1266-- ThreadId ...: Delay 1
1375-- ThreadId ...: Delay 3
1267-- ThreadId ...: Delay 3
1376-- ThreadId ...: Delay 2
1268-- ThreadId ...: Delay 2
@@ -1384,31 +1276,13 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
1384-- 'fromZipAsync' type combinator can be used to switch to parallel applicative
1276-- 'fromZipAsync' type combinator can be used to switch to parallel applicative
1385-- zip composition:
1277-- zip composition:
1389−-- import System.IO (stdout, hSetBuffering, BufferMode(LineBuffering))
1391−-- d n = delay n >> return n
1392−-- s1 = Stream.'fromSerial' $ d 1 <> d 2
1393−-- s2 = Stream.'fromSerial' $ d 3 <> d 4
1396−-- hSetBuffering stdout LineBuffering
1397−-- (Stream.'toList' . Stream.'fromZipAsync' $ (,) \<$> s1 \<*> s2) >>= print
1400-- This takes 7 seconds to zip, which is max (1,3) + max (2,4) because 1 and 3
1279-- This takes 7 seconds to zip, which is max (1,3) + max (2,4) because 1 and 3
1401-- are produced concurrently, and 2 and 4 are produced concurrently:
1280-- are produced concurrently, and 2 and 4 are produced concurrently:
1403-- >>> d n = delay n >> return n
1282-- >>> d n = delay n >> return n
1404-- >>> s1 = Stream.fromSerial $ d 1 <> d 2
1283-- >>> s1 = Stream.fromSerial $ d 1 <> d 2
1405-- >>> s2 = Stream.fromSerial $ d 3 <> d 4
1284-- >>> s2 = Stream.fromSerial $ d 3 <> d 4
1409−-- hSetBuffering stdout LineBuffering
1410−-- (Stream.toList . Stream.fromZipAsync $ (,) <$> s1 <*> s2) >>= print
1285+-- >>> (Stream.toList $ Stream.fromZipAsync $ (,) <$> s1 <*> s2) >>= print
1412-- ThreadId ...: Delay 1
1286-- ThreadId ...: Delay 1
1413-- ThreadId ...: Delay 2
1287-- ThreadId ...: Delay 2
1414-- ThreadId ...: Delay 3
1288-- ThreadId ...: Delay 3
@@ -1427,35 +1301,31 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
1428-- In the following example the squares of @x@ and @y@ are computed
1302-- In the following example the squares of @x@ and @y@ are computed
1429-- concurrently using the 'async' operation and the square roots of their
1303-- concurrently using the 'async' operation and the square roots of their
1430−-- sum are computed serially because of the 'streamly' combinator. We can
1304+-- sum are computed serially because of the 'fromSerial' combinator. We can
1431-- choose different combinators for the monadic processing and the stream
1305-- choose different combinators for the monadic processing and the stream
1432-- generation, to control the concurrency. We can also use the 'fromAsync'
1306-- generation, to control the concurrency. We can also use the 'fromAsync'
1433-- combinator instead of explicitly folding with 'async'.
1307-- combinator instead of explicitly folding with 'async'.
1436−-- import qualified "Streamly.Prelude" as Stream
1437−-- import Data.List (sum)
1309+-- >>> import Data.List (sum)
1439-- main = do
1311-- main = do
1440−-- z \<- Stream.'toList'
1312+-- z <- Stream.toList
1441−-- $ Stream.'fromSerial' -- Serial monadic processing (sqrt below)
1313+-- $ Stream.fromSerial -- Serial monadic processing (sqrt below)
1443−-- x2 \<- Stream.'concatForFoldableWith' Stream.'async' [1..100] $ -- Concurrent @"for"@ loop
1315+-- x2 <- Stream.concatForFoldableWith Stream.async [1..100] $ -- Concurrent @"for"@ loop
1444−-- \\x -> return $ x * x -- body of the loop
1316+-- \x -> return $ x * x -- body of the loop
1445−-- y2 \<- Stream.'concatForFoldableWith' Stream.'async' [1..100] $
1317+-- y2 <- Stream.concatForFoldableWith Stream.async [1..100] $
1446−-- \\y -> return $ y * y
1318+-- \y -> return $ y * y
1447-- return $ sqrt (x2 + y2)
1319-- return $ sqrt (x2 + y2)
1448-- print $ sum z
1320-- print $ sum z
1451-- We can see how this directly maps to the imperative style
1323-- We can see how this directly maps to the imperative style
1452-- <https://en.wikipedia.org/wiki/OpenMP OpenMP> model, we use combinators
1324-- <https://en.wikipedia.org/wiki/OpenMP OpenMP> model, we use combinators
1453-- and operators instead of the ugly pragmas.
1325-- and operators instead of the ugly pragmas.
1455-- For more concurrent programming examples see,
1327-- For more concurrent programming examples see,
1456−-- <https://github.com/composewell/streamly-examples/tree/master/ListDir.hs ListDir.hs>,
1328+-- <https://github.com/composewell/streamly-examples>.
1457−-- <https://github.com/composewell/streamly-examples/tree/master/MergeSort.hs MergeSort.hs> and
1458−-- <https://github.com/composewell/streamly-examples/tree/master/SearchQuery.hs SearchQuery.hs> in the examples directory.
1460-- $reactive
1330-- $reactive