on master help sign in
Rework the Streamly.Tutorial module
a0386cbHarendra Kumar
src/Streamly/Tutorial.hs+228−358
@@ -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))
180
180
181+-- CAUTION: please keep setup and imports sections in sync
182+--
181-- $setup
183-- $setup
182-- >>> :m
184-- >>> :m
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)
194+-- tid <- myThreadId
195+-- putStrLn (show tid ++ ": Delay " ++ show n)
196+-- :}
197+--
195-- >>> import System.IO (stdout, hSetBuffering, BufferMode(LineBuffering))
198-- >>> import System.IO (stdout, hSetBuffering, BufferMode(LineBuffering))
196−-- >>> import Streamly.Prelude
199+-- >>> hSetBuffering stdout LineBuffering
200+--
201+
202+-- $imports
203+--
204+-- In most of example snippets we do not repeat the imports. Where imports are
205+-- not explicitly specified use the imports shown below.
197--
206--
207+-- >>> :m
208+-- >>> import Data.Function ((&))
209+-- >>> import Streamly.Prelude ((|:), (|&))
210+-- >>> import qualified Streamly.Prelude as Stream
211+-- >>> import qualified Streamly.Data.Fold as Fold
212+--
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.
216+--
217+-- >>> import Control.Concurrent (threadDelay, myThreadId)
198-- >>> :{
218-- >>> :{
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)
203-- :}
223-- :}
204--
224--
225+-- For concurrent examples, use line buffering, otherwise output from different
226+-- threads may get mixed:
227+--
228+-- >>> import System.IO (stdout, hSetBuffering, BufferMode(LineBuffering))
229+-- >>> hSetBuffering stdout LineBuffering
205--
230--
231+
206-- $streams
232-- $streams
207--
233--
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'.
358--
384--
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!
362--
388--
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!
365--
392--
366−-- @
367−--
368
393
369-- $generating
394-- $generating
370--
395--
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.
373--
398--
374−-- @
375-- >>> Stream.toList Stream.nil
399-- >>> Stream.toList Stream.nil
376-- []
400-- []
377--
401--
@@ -380,14 +404,11 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
380-- world
404-- world
381-- ["hello","world"]
405-- ["hello","world"]
382--
406--
383−-- @
384−--
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.
389--
411--
390−-- @
391-- >>> Stream.toList $ pure 1
412-- >>> Stream.toList $ pure 1
392-- [1]
413-- [1]
393--
414--
@@ -398,29 +419,21 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
398-- hello
419-- hello
399-- ["hello"]
420-- ["hello"]
400--
421--
401−-- @
402−--
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':
405--
424--
406−-- @
407-- >>> Stream.toList $ Stream.fromFoldable [1..3]
425-- >>> Stream.toList $ Stream.fromFoldable [1..3]
408-- [1,2,3]
426-- [1,2,3]
409--
427--
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]
412--
430--
413−-- @
414−--
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':
417--
433--
418−-- @
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!
421--
436--
422−-- @
423−--
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".
425
438
426-- $generatingConcurrently
439-- $generatingConcurrently
@@ -434,23 +447,16 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
434--
447--
435-- The following code finishes in 3 seconds (6 seconds when serial):
448-- The following code finishes in 3 seconds (6 seconds when serial):
436--
449--
437−-- @
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]
441--
453--
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]
445--
456--
446−-- (3.01 secs, 2,055,880 bytes)
447−-- @
448-- The following finishes in 10 seconds (100 seconds when serial):
457-- The following finishes in 10 seconds (100 seconds when serial):
449--
458--
450−-- @
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)
453−-- @
454--
460--
455
461
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:
477--
483--
478−-- @
484+-- >>> :{
485+-- echo =
479−-- Stream.'drain' $ Stream.'repeatM' getLine & Stream.'mapM' putStrLn
486+-- Stream.repeatM getLine
480−-- @
487+-- & Stream.mapM putStrLn
488+-- & Stream.drain
489+-- :}
481--
490--
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:
485--
494--
486−-- @
495+-- >>> import Data.Char (toUpper)
496+-- >>> :{
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
506+-- :}
507+--
496
508
497-- $concurrentTransformation
509-- $concurrentTransformation
498--
510--
@@ -503,10 +515,15 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
503--
515--
504-- This would print a value every second (2 seconds when serial):
516-- This would print a value every second (2 seconds when serial):
505--
517--
506−-- @
507−-- let p n = threadDelay (n * 1000000) >> return n
518+-- >>> let p n = threadDelay (n * 1000000) >> return n
519+-- >>> :{
520+-- parMap =
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
525+-- & Stream.drain
509−-- @
526+-- :}
510--
527--
511
528
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:
520--
537--
521−-- @
522−-- let p n = threadDelay (n * 1000000) >> return n
538+-- >>> let p n = threadDelay (n * 1000000) >> return n
539+-- >>> :{
540+-- parApp =
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
544+-- :}
525
545
526-- $semigroup
546-- $semigroup
527--
547--
@@ -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.
534
554
535−-- $imports
536−--
537−-- In most of example snippets we do not repeat the imports. Where imports are
538−-- not explicitly specified use the imports shown below.
539−--
540−-- @
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
555−-- @
556−--
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.
560−--
561−-- @
562−-- >>> :{
563−-- delay n = Stream.fromEffect $ do
564−-- threadDelay (n * 1000000)
565−-- tid <- myThreadId
566−-- putStrLn (show tid ++ ": Delay " ++ show n)
567−-- :}
568−--
569−-- @
570−
571-- $serial
555-- $serial
572--
556--
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,
587-- 3, 4:
571-- 3, 4:
588--
572--
589−-- @
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
591-- 1
576-- 1
592-- 2
577-- 2
593-- 3
578-- 3
594-- 4
579-- 4
595--
580--
596−-- @
597−--
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:
601--
584--
602−-- @
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
607--
589--
608−-- @
609−--
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:
613--
593--
614−-- @
615−-- >>> Stream.drain $ (print 1 |: print 2 |: Stream.nil) `Stream.serial` (print 3 |: print 4 |: Stream.nil)
594+-- >>> Stream.drain $ stream1 `Stream.serial` stream2
616-- 1
595-- 1
617-- 2
596-- 2
618-- 3
597-- 3
619-- 4
598-- 4
620--
599--
621−-- @
622
600
623-- $interleaved
601-- $interleaved
624--
602--
@@ -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
635--
613--
636−-- @
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
638-- 1
617-- 1
639-- 3
618-- 3
640-- 2
619-- 2
641-- 4
620-- 4
642--
621--
643−-- @
644−--
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:
649--
626--
650−-- @
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
655--
631--
656−-- @
657−--
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:
662--
636--
663−-- @
664−-- >>> Stream.drain $ (print 1 |: print 2 |: Stream.nil) `Stream.wSerial` (print 3 |: print 4 |: Stream.nil)
637+-- >>> Stream.drain $ stream1 `Stream.wSerial` stream2
665-- 1
638-- 1
666-- 3
639-- 3
667-- 2
640-- 2
668-- 4
641-- 4
669--
642--
670−-- @
671−--
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.
674
645
@@ -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:
690--
661--
691−-- @
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
696−-- print xs
697−-- :}
698-- [1,2,3,4]
666-- [1,2,3,4]
699--
667--
700−-- @
701−--
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.
705--
671--
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:
728--
694--
729−-- @
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+-- ...
734−--
735−-- [1,3,4,2]
736−-- @
737--
700--
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:
742--
705--
743−-- @
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+-- ...
747−--
748−-- @
749--
710--
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:
754--
715--
755−-- @
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
760--
720--
761−-- @
762−--
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.
772--
730--
773−-- @
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
779--
736--
780−-- @
781−--
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:
788--
743--
789−-- @
744+-- >>> :{
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
794−-- ThreadId 40
795−-- ThreadId 40
796−-- ThreadId 40
797−-- @
748+-- :}
798--
749--
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:
806--
757--
807−-- @
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
812--
762--
813−-- @
814−--
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.
848--
796--
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)
854−-- :}
855-- 1
800-- 1
856-- 3
801-- 3
857-- 2
802-- 2
858-- 4
803-- 4
859--
804--
860−-- @
861−--
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:
866--
809--
867−-- @
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
872--
814--
873−-- @
874−--
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.
899--
839--
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:
904−--
905−-- @
906−-- import qualified Streamly.Prelude as Stream
907−-- import Network.HTTP.Simple
908−--
909−-- main = Stream.'drain' . Stream.'fromParallel' $ google \<> bing \<> duckduckgo
910−-- where
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))
915−-- @
916−--
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:
921--
844--
922−-- @
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
927--
849--
928−-- @
929−--
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.
932--
852--
@@ -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:
962--
882--
963−-- @
883+-- >>> :{
964−-- import qualified "Streamly.Prelude" as Stream
965−-- import Control.Concurrent
966−--
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+-- :}
973−-- @
890+--
974
891
975-- $nesting
892-- $nesting
976--
893--
@@ -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.
1015--
932--
1016−-- @
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
1025--
941--
1026−-- @
1027−--
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.
1032--
946--
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:
1035--
949--
1036−-- @
950+-- >>> :{
951+-- main =
952+-- Stream.drain $ do
953+-- x <- Stream.repeatM getLine
1037−-- main = Stream.'drain' $ forever $ Stream.'fromEffect' getLine >>= Stream.'fromEffect' . putStrLn
954+-- Stream.fromEffect $ putStrLn x
1038−-- @
955+-- :}
1039--
956--
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.
1044--
959--
1045−-- @
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))
1054-- (2,3)
968-- (2,3)
1055-- (2,4)
969-- (2,4)
1056--
970--
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.
1058--
974--
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.
1067--
983--
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'.
1071−--
1072−-- @
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]
987+-- delay x
1076−-- delay x >> return x
988+-- return x
1077-- :}
989-- :}
1078−--
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]
1084--
994--
1085−-- @
1086−--
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.
1096--
1004--
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'.
1008+--
1097
1009
1098-- $concurrentNesting
1010-- $concurrentNesting
1099--
1011--
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.
1106−--
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'.
1110--
1014--
1111−-- @
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
1116-- :}
1019-- :}
@@ -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
1120--
1023--
1121−-- @
1122−--
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.
1128--
1029--
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.
1135--
1034--
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'.
1137--
1038--
1039+-- When multiple streams are nested using this style, the iterations are
1040+-- concurrently evaluated in a depth first manner:
1041+--
1042+--
1043+-- >>> :{
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)
1142−--
1048+-- :}
1143-- (1,3)
1049-- (1,3)
1144-- (1,4)
1050-- (1,4)
1145-- (2,3)
1051-- (2,3)
1146-- (2,4)
1052-- (2,4)
1147--
1053--
1148−-- @
1054+-- Nested iterations are given preference for concurrent evaluation i.e.
1055+-- (1,4) will be scheduled in preference to (2,3).
1149
1056
1150-- $interleavedNesting
1057-- $interleavedNesting
1151--
1058--
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'.
1158--
1061--
1159−-- @
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))
1168-- (1,4)
1070-- (1,4)
1169-- (2,4)
1071-- (2,4)
1170--
1072--
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.
1075+--
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'.
1172--
1079--
1173
1080
1174-- $wasyncNesting
1081-- $wasyncNesting
1175--
1082--
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'.
1184--
1087--
1185−-- @
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)
1191-- :}
1093-- :}
1192-- (1,3)
1094-- (1,3)
1193−-- ...
1095+-- (1,4)
1194−-- ...
1096+-- (2,3)
1195-- (2,4)
1097-- (2,4)
1196--
1098--
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.
1102+--
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'.
1106+--
1198
1107
1199-- $parallelNesting
1108-- $parallelNesting
1200--
1109--
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'.
1208--
1112--
1209−-- @
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
1214-- :}
1117-- :}
@@ -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
1218--
1121--
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.
1126+--
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'.
1130+--
1220
1131
1221-- $monadExercise
1132-- $monadExercise
1222--
1133--
@@ -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.
1227--
1138--
1228−-- @
1139+-- >>> :{
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)
1235−--
1236-- where
1146-- where
1237−--
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"]
1241−-- @
1150+-- :}
1242--
1151--
1243-- Now we can interpret this in whatever way we want:
1152-- Now we can interpret this in whatever way we want:
1244--
1153--
1245-- @
1154-- @
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
1251-- @
1160-- @
1252--
1161--
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.
1261--
1170--
1262−-- @
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"]
1265--
1173--
1266−-- @
1267−--
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.
1270
1176
@@ -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.
1276--
1182--
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):
1279--
1185--
1280−-- @
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
1284--
1189--
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)]
1293--
1198--
1294−-- @
1199+-- Similarly, 'WSerial' applicative runs the iterations in an interleaved
1200+-- order but being serial it too takes a total of 17 seconds:
1295--
1201--
1296−-- Similarly 'WSerial' applicative runs the iterations in an interleaved
1297−-- order but since it is serial it takes a total of 17 seconds:
1298−--
1299−-- @
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)]
1308--
1210--
1309−-- @
1310−--
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):
1313--
1213--
1314−-- @
1315−-- main = (Stream.'toList' . Stream.'fromAsync' $ (,) \<$> s1 \<*> s2) >>= print
1214+-- >>> (Stream.toList $ Stream.fromAsync $ (,) <$> s1 <*> s2) >>= print
1316−-- @
1215+-- ...
1216+--
1317-- @
1217-- @
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)]
1325-- @
1225-- @
1326--
1226--
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):
1230+--
1231+-- >>> (Stream.toList $ Stream.fromWAsync $ (,) <$> s1 <*> s2) >>= print
1232+-- ...
1329--
1233--
1330−-- @
1331−-- main = (Stream.'toList' . Stream.'fromWAsync' $ (,) \<$> s1 \<*> s2) >>= print
1332−-- @
1333-- @
1234-- @
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:
1357--
1258--
1358−-- @
1359−--
1360−-- d n = delay n >> return n
1361−-- s1 = Stream.'fromSerial' $ d 1 <> d 2
1362−-- s2 = Stream.'fromSerial' $ d 3 <> d 4
1363−--
1364−-- main = (Stream.'toList' . Stream.'fromZipSerial' $ (,) \<$> s1 \<*> s2) >>= print
1365−-- @
1366−--
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:
1369--
1261--
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:
1386--
1278--
1387−--
1388−-- @
1389−-- import System.IO (stdout, hSetBuffering, BufferMode(LineBuffering))
1390−--
1391−-- d n = delay n >> return n
1392−-- s1 = Stream.'fromSerial' $ d 1 <> d 2
1393−-- s2 = Stream.'fromSerial' $ d 3 <> d 4
1394−--
1395−-- main = do
1396−-- hSetBuffering stdout LineBuffering
1397−-- (Stream.'toList' . Stream.'fromZipAsync' $ (,) \<$> s1 \<*> s2) >>= print
1398−-- @
1399−--
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:
1402--
1281--
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
1406−--
1407−-- >>> :{
1408−-- do
1409−-- hSetBuffering stdout LineBuffering
1410−-- (Stream.toList . Stream.fromZipAsync $ (,) <$> s1 <*> s2) >>= print
1285+-- >>> (Stream.toList $ Stream.fromZipAsync $ (,) <$> s1 <*> s2) >>= print
1411−-- :}
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))
1427--
1301--
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'.
1434--
1308--
1435−-- @
1436−-- import qualified "Streamly.Prelude" as Stream
1437−-- import Data.List (sum)
1309+-- >>> import Data.List (sum)
1438−--
1310+-- >>> :{
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)
1442-- $ do
1314-- $ do
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
1449−-- @
1321+-- :}
1450--
1322--
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.
1454--
1326--
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.
1459
1329
1460-- $reactive
1330-- $reactive
1461--
1331--