@@ -178,23 +178,43 @@ import Control.Monad
178178import Control.Monad.IO.Class (MonadIO(..))
179179import Control.Monad.Trans.Class (MonadTrans (lift))
180180
181+-- CAUTION: please keep setup and imports sections in sync
182+--
181183-- $setup
182184-- >>> :m
183−-- >>> import Prelude hiding (break, map, span, splitAt)
185+-- >>> import Data.Function ((&))
186+-- >>> import Streamly.Prelude ((|:), (|&))
184187-- >>> import qualified Streamly.Prelude as Stream
185−-- >>> import qualified Streamly.Internal.Data.Stream.IsStream as Stream (parse, foldMany)
186188-- >>> import qualified Streamly.Data.Fold as Fold
187−-- >>> import qualified Streamly.Internal.Data.Fold as Fold
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
194−-- >>> import Control.Monad (forever)
189+--
190+-- >>> import Control.Concurrent (threadDelay, myThreadId)
191+-- >>> :{
192+-- delay n = Stream.fromEffect $ do
193+-- threadDelay (n * 1000000)
194+-- tid <- myThreadId
195+-- putStrLn (show tid ++ ": Delay " ++ show n)
196+-- :}
197+--
195198-- >>> 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.
197206--
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)
198218-- >>> :{
199219-- delay n = Stream.fromEffect $ do
200220-- threadDelay (n * 1000000)
@@ -202,7 +222,13 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
202222-- putStrLn (show tid ++ ": Delay " ++ show n)
203223-- :}
204224--
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
205230--
231+
206232-- $streams
207233--
208234-- The monadic stream API offered by Streamly is very close to the Haskell
@@ -356,22 +382,20 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
356382-- To lift a value from an underlying monad in a monad transformer stack into a
357383-- singleton stream use 'lift' and to lift from an IO action use 'liftIO'.
358384--
359−-- @
385+-- >>> import Control.Monad.IO.Class (liftIO)
360386-- >>> Stream.drain $ liftIO $ putStrLn "Hello world!"
361387-- Hello world!
362388--
389+-- >>> import Control.Monad.Trans.Class (MonadTrans(lift))
363390-- >>> Stream.drain $ lift $ putStrLn "Hello world!"
364391-- Hello world!
365392--
366−-- @
367−--
368393
369394-- $generating
370395--
371396-- 'nil' represents an empty stream and 'consM' or its operator form '|:' adds
372397-- a monadic action at the head of the stream.
373398--
374−-- @
375399-- >>> Stream.toList Stream.nil
376400-- []
377401--
@@ -380,14 +404,11 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
380404-- world
381405-- ["hello","world"]
382406--
383−-- @
384−--
385407-- To create a singleton stream from a pure value use 'fromPure' or 'pure' and to
386408-- create a singleton stream from a monadic action use 'fromEffect'. Note that in
387409-- case of Zip applicative streams "pure" repeats the value to generate an
388410-- infinite stream.
389411--
390−-- @
391412-- >>> Stream.toList $ pure 1
392413-- [1]
393414--
@@ -398,29 +419,21 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
398419-- hello
399420-- ["hello"]
400421--
401−-- @
402−--
403422-- To create a stream from pure values in a 'Foldable' container use
404423-- 'fromFoldable' which is equivalent to a fold using 'cons' and 'nil':
405424--
406−-- @
407425-- >>> Stream.toList $ Stream.fromFoldable [1..3]
408426-- [1,2,3]
409427--
410428-- >>> Stream.toList $ Prelude.foldr Stream.cons Stream.nil [1..3]
411429-- [1,2,3]
412430--
413−-- @
414−--
415431-- To create a stream from monadic actions in a 'Foldable' container just use a
416432-- right fold using 'consM' and 'nil':
417433--
418−-- @
419434-- >>> Stream.drain $ Prelude.foldr (|:) Stream.nil [putStr "Hello ", putStrLn "world!"]
420435-- Hello world!
421436--
422−-- @
423−--
424437-- For more ways to construct a stream see the module "Streamly.Prelude".
425438
426439-- $generatingConcurrently
@@ -434,23 +447,16 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
434447--
435448-- The following code finishes in 3 seconds (6 seconds when serial):
436449--
437−-- @
438450-- >>> let p n = threadDelay (n * 1000000) >> return n
439451-- >>> Stream.toList $ Stream.fromParallel $ p 3 |: p 2 |: p 1 |: Stream.nil
440452-- [1,2,3]
441453--
442−-- (3.01 secs, 2,018,432 bytes)
443454-- >>> Stream.toList $ Stream.fromAhead $ p 3 |: p 2 |: p 1 |: Stream.nil
444455-- [3,2,1]
445456--
446−-- (3.01 secs, 2,055,880 bytes)
447−-- @
448457-- The following finishes in 10 seconds (100 seconds when serial):
449458--
450−-- @
451−-- Stream.'drain' $ Stream.'fromAsync' $ Stream.'replicateM' 10 $ p 10
452−-- (10.01 secs, 2,080,320 bytes)
453−-- @
459+-- >>> Stream.drain $ Stream.fromAsync $ Stream.replicateM 10 $ p 10
454460--
455461
456462-- $eliminating
@@ -475,24 +481,30 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
475481-- Here is a simple console echo program that just echoes every input line,
476482-- forever:
477483--
478−-- @
479−-- Stream.'drain' $ Stream.'repeatM' getLine & Stream.'mapM' putStrLn
480−-- @
484+-- >>> :{
485+-- echo =
486+-- Stream.repeatM getLine
487+-- & Stream.mapM putStrLn
488+-- & Stream.drain
489+-- :}
481490--
482491-- The following code snippet reads lines from standard input, filters blank
483492-- lines, drops the first non-blank line, takes the next two, up cases them,
484493-- numbers them and prints them:
485494--
486−-- @
487−-- main = Stream.'drain' $
488−-- Stream.'repeatM' getLine
489−-- & Stream.'filter' (not . null)
490−-- & Stream.'drop' 1
491−-- & Stream.'take' 2
492−-- & fmap (map toUpper)
493−-- & Stream.'zipWith' (\\n s -> show n ++ " " ++ s) (Stream.'fromFoldable' [1..])
494−-- & Stream.'mapM' putStrLn
495−-- @
495+-- >>> import Data.Char (toUpper)
496+-- >>> :{
497+-- main =
498+-- Stream.repeatM getLine
499+-- & Stream.filter (not . null)
500+-- & Stream.drop 1
501+-- & Stream.take 2
502+-- & fmap (map toUpper)
503+-- & Stream.zipWith (\n s -> show n ++ " " ++ s) (Stream.fromFoldable [1..])
504+-- & Stream.mapM putStrLn
505+-- & Stream.drain
506+-- :}
507+--
496508
497509-- $concurrentTransformation
498510--
@@ -503,10 +515,15 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
503515--
504516-- This would print a value every second (2 seconds when serial):
505517--
506−-- @
507−-- let p n = threadDelay (n * 1000000) >> return n
508−-- Stream.'drain' $ Stream.'fromAhead' $ Stream.'mapM' (\\x -> p 1 >> print x) (Stream.'fromSerial' $ Stream.'repeatM' (p 1))
509−-- @
518+-- >>> let p n = threadDelay (n * 1000000) >> return n
519+-- >>> :{
520+-- parMap =
521+-- Stream.repeatM (p 1)
522+-- & Stream.fromSerial -- repeatM is serial
523+-- & Stream.mapM (\x -> p 1 >> print x)
524+-- & Stream.fromAhead -- mapM is cocnurrent using Ahead style
525+-- & Stream.drain
526+-- :}
510527--
511528
512529-- $concurrentApplication
@@ -518,10 +535,13 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
518535-- Because both the stages run concurrently, we would see a delay of only 1
519536-- second instead of 2 seconds in the following:
520537--
521−-- @
522−-- let p n = threadDelay (n * 1000000) >> return n
523−-- Stream.'drain' $ Stream.'repeatM' (p 1) '|&' Stream.'mapM' (\\x -> p 1 >> print x)
524−-- @
538+-- >>> let p n = threadDelay (n * 1000000) >> return n
539+-- >>> :{
540+-- parApp =
541+-- Stream.repeatM (p 1)
542+-- |& Stream.mapM (\x -> p 1 >> print x)
543+-- & Stream.drain
544+-- :}
525545
526546-- $semigroup
527547--
@@ -532,42 +552,6 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
532552-- style can be changed at any point using one of the type combinators as
533553-- discussed earlier.
534554
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−
571555-- $serial
572556--
573557-- The 'Semigroup' operation '<>' of the 'Serial' type combines the two streams
@@ -586,39 +570,33 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
586570-- before we move to the next. The following example prints the sequence 1, 2,
587571-- 3, 4:
588572--
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
591576-- 1
592577-- 2
593578-- 3
594579-- 4
595580--
596−-- @
597−--
598581-- All actions in both the streams are performed serially in the same thread.
599582-- In the following example we can see that all actions are performed in the
600583-- same thread and take a combined total of @3 + 2 + 1 = 6@ seconds:
601584--
602−-- @
603585-- >>> Stream.drain $ delay 3 <> delay 2 <> delay 1
604586-- ThreadId ... Delay 3
605587-- ThreadId ... Delay 2
606588-- ThreadId ... Delay 1
607589--
608−-- @
609−--
610590-- The polymorphic version of the binary operation '<>' of the 'Serial' type is
611591-- 'serial'. We can use 'serial' to join streams in a sequential manner
612592-- irrespective of the type of stream:
613593--
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
616595-- 1
617596-- 2
618597-- 3
619598-- 4
620599--
621−-- @
622600
623601-- $interleaved
624602--
@@ -633,42 +611,35 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
633611-- to the first stream again and so on.
634612-- The following example prints the sequence 1, 3, 2, 4
635613--
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
638617-- 1
639618-- 3
640619-- 2
641620-- 4
642621--
643−-- @
644−--
645622-- Even though the monadic actions of the two streams are performed in an
646623-- interleaved manner they are all performed serially in the same thread. In
647624-- the following example we can see that all actions are performed in the same
648625-- thread and take a combined total of @3 + 2 + 1 = 6@ seconds:
649626--
650−-- @
651−-- >>> Stream.drain . Stream.fromWSerial $ delay 3 <> delay 2 <> delay 1
627+-- >>> Stream.drain $ Stream.fromWSerial $ delay 3 <> delay 2 <> delay 1
652628-- ThreadId ...: Delay 3
653629-- ThreadId ...: Delay 2
654630-- ThreadId ...: Delay 1
655631--
656−-- @
657−--
658632-- The polymorphic version of the 'WSerial' binary operation '<>' is called
659633-- 'wSerial'. We can use 'wSerial' to join streams in an interleaved manner
660634-- irrespective of the type, notice that we have not used the fromWSerial
661635-- combinator in the following example:
662636--
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
665638-- 1
666639-- 3
667640-- 2
668641-- 4
669642--
670−-- @
671−--
672643-- Note that this composition cannot be used to fold infinite number of streams
673644-- since it requires preserving the state until a stream is finished.
674645
@@ -688,19 +659,14 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
688659-- demand. The following example would print the result in a second even
689660-- though each action in each stream takes one second:
690661--
691−-- @
692662-- >>> p n = threadDelay 1000000 >> return n
693−-- >>> :{
694−-- do
695−-- xs <- Stream.toList . Stream.fromAhead $ (p 1 |: p 2 |: Stream.nil) <> (p 3 |: p 4 |: Stream.nil)
696−-- print xs
697−-- :}
663+-- >>> stream1 = p 1 |: p 2 |: Stream.nil
664+-- >>> stream2 = p 3 |: p 4 |: Stream.nil
665+-- >>> Stream.toList $ Stream.fromAhead $ stream1 <> stream2
698666-- [1,2,3,4]
699667--
700−-- @
701−--
702−-- Each stream is constructed 'aheadly' and then both the streams are merged
703−-- 'aheadly', therefore, all the actions can run concurrently but the result is
668+-- Each stream is constructed 'fromAhead' and then both the streams are merged
669+-- 'fromAhead', therefore, all the actions can run concurrently but the result is
704670-- presented in serial order.
705671--
706672-- You can also use the polymorphic combinator 'ahead' in place of '<>' to
@@ -726,40 +692,32 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
726692-- of 1 second, however, it takes just one second to produce all the results.
727693-- The results are not guaranteed to be in any particular order:
728694--
729−-- @
730−-- p n = threadDelay 1000000 >> return n
731−-- do
732−-- xs <- Stream.toList . Stream.fromAsync $ (p 1 |: p 2 |: Stream.nil) <> (p 3 |: p 4 |: Stream.nil)
733−-- print xs
734−--
735−-- [1,3,4,2]
736−-- @
695+-- >>> p n = threadDelay 1000000 >> return n
696+-- >>> stream1 = p 1 |: p 2 |: Stream.nil
697+-- >>> stream2 = p 3 |: p 4 |: Stream.nil
698+-- >>> Stream.toList $ Stream.fromAsync $ stream1 <> stream2
699+-- ...
737700--
738701-- The constituent streams are also composed in 'Async' manner and the
739702-- composition of streams too. We can compose the constituent streams to run
740703-- serially, in that case it would take 2 seconds to produce all the results.
741704-- The elements in the serial streams would be in serial order in the results:
742705--
743−-- @
744−-- > p n = threadDelay 1000000 >> return n
745−-- > Stream.toList . Stream.fromAsync $ (Stream.fromSerial $ p 1 |: p 2 |: Stream.nil) <> (fromSerial $ p 3 |: p 4 |: Stream.nil)
746−-- [1,3,4,2] -- order is not predictable
747−--
748−-- @
706+-- >>> p n = threadDelay 1000000 >> return n
707+-- >>> stream = (Stream.fromSerial stream1) <> (Stream.fromSerial stream2)
708+-- >>> Stream.toList $ Stream.fromAsync stream
709+-- ...
749710--
750711-- In the following example we can see that new threads are started when a
751712-- computation blocks. Notice that the output from the stream with the
752713-- shortest delay is printed first. The whole computation takes @maximum of
753714-- (3, 2, 1) = 3@ seconds:
754715--
755−-- @
756−-- >>> Stream.drain . Stream.fromAsync $ delay 3 <> delay 2 <> delay 1
716+-- >>> Stream.drain $ Stream.fromAsync $ delay 3 <> delay 2 <> delay 1
757717-- ThreadId ...: Delay 1
758718-- ThreadId ...: Delay 2
759719-- ThreadId ...: Delay 3
760720--
761−-- @
762−--
763721-- When we have a tree of computations composed using this style, the tree is
764722-- traversed in DFS style just like the 'Serial' style, the only difference is
765723-- 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))
770728-- the pull rate of the consumer. The following example prints an output every
771729-- second as all of the actions are concurrent.
772730--
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)
775732-- ThreadId ...: Delay 1
776733-- ThreadId ...: Delay 2
777734-- ThreadId ...: Delay 3
778735-- ThreadId ...: Delay 4
779736--
780−-- @
781−--
782737-- All the computations may even run in a single thread when more threads are
783738-- not needed. As you can see, in the following example the computations are
784739-- run in a single thread one after another, because none of them blocks.
@@ -786,15 +741,11 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
786741-- then it would have started parallel threads for each computation to keep up
787742-- even if none of them blocks:
788743--
789−-- @
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
792−-- @
793−-- @
794−-- ThreadId 40
795−-- ThreadId 40
796−-- ThreadId 40
797−-- @
744+-- >>> :{
745+-- traced m = Stream.fromEffect (myThreadId >>= print) >> return m
746+-- stream = traced (sqrt 9) <> traced (sqrt 16) <> traced (sqrt 25)
747+-- main = Stream.drain $ Stream.fromAsync stream
748+-- :}
798749--
799750-- Note that the order of printing in the above examples may change due to
800751-- variations in scheduling latencies for concurrent threads.
@@ -804,14 +755,11 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
804755-- adaptively concurrent manner irrespective of the type, notice that we have
805756-- not used the 'fromAsync' combinator in the following example:
806757--
807−-- @
808758-- >>> Stream.drain $ delay 3 `Stream.async` delay 2 `Stream.async` delay 1
809759-- ThreadId ...: Delay 1
810760-- ThreadId ...: Delay 2
811761-- ThreadId ...: Delay 3
812762--
813−-- @
814−--
815763-- Since the concurrency provided by this operator is demand driven it cannot
816764-- be used when the composed computations start timers that are relative to
817765-- 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))
846794-- In the following example we can see that outputs are produced in the breadth
847795-- first traversal order but this is not guaranteed.
848796--
849−-- @
850−-- >>> :{
851−-- do
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−-- :}
797+-- >>> stream1 = print 1 |: print 2 |: Stream.nil
798+-- >>> stream2 = print 3 |: print 4 |: Stream.nil
799+-- >>> Stream.drain $ Stream.fromWAsync $ stream1 <> stream2
855800-- 1
856801-- 3
857802-- 2
858803-- 4
859804--
860−-- @
861−--
862805-- The polymorphic version of the binary operation '<>' of the 'WAsync' type is
863806-- 'wAsync'. We can use 'wAsync' to join streams using a breadth first
864807-- concurrent traversal irrespective of the type, notice that we have not used
865808-- the 'fromWAsync' combinator in the following example:
866809--
867−-- @
868810-- >>> Stream.drain $ delay 3 `Stream.wAsync` delay 2 `Stream.wAsync` delay 1
869811-- ThreadId ...: Delay 1
870812-- ThreadId ...: Delay 2
871813-- ThreadId ...: Delay 3
872814--
873−-- @
874−--
875815-- Since the concurrency provided by this style is demand driven it may not
876816-- be used when the composed computations start timers that are relative to
877817-- 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))
897837-- may not execute all actions in parallel depending on the demand, whereas
898838-- 'Parallel' runs all the streams in parallel irrespective of the demand.
899839--
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−--
917840-- The polymorphic version of the binary operation '<>' of the 'Parallel' type
918841-- is 'parallel'. We can use 'parallel' to join streams in a fairly concurrent
919842-- manner irrespective of the type, notice that we have not used the
920843-- 'fromParallel' combinator in the following example:
921844--
922−-- @
923845-- >>> Stream.drain $ delay 3 `Stream.parallel` delay 2 `Stream.wAsync` delay 1
924846-- ThreadId ...: Delay 1
925847-- ThreadId ...: Delay 2
926848-- ThreadId ...: Delay 3
927849--
928−-- @
929−--
930850-- Note that this style of composition cannot be used to combine infinite
931851-- number of streams, as it will lead to an infinite sized scheduling queue.
932852--
@@ -960,17 +880,14 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
960880-- a delay from 1 to 10 seconds, resulting in the printing of each number every
961881-- second:
962882--
963−-- @
964−-- import qualified "Streamly.Prelude" as Stream
965−-- import Control.Concurrent
966−--
883+-- >>> :{
967884-- main = do
968−-- Stream.'drain' $ Stream.'fromAsync' $ foldMap delay [1..10]
969−-- Stream.'drain' $ Stream.'concatFoldableWith' Stream.'async' (map delay [1..10])
970−-- Stream.'drain' $ Stream.'concatMapFoldableWith' Stream.'async' delay [1..10]
971−-- Stream.'drain' $ Stream.'concatForFoldableWith' Stream.'async' [1..10] delay
972−-- where delay n = Stream.'fromEffect' $ threadDelay (n * 1000000) >> print n
973−-- @
885+-- Stream.drain $ Stream.fromAsync $ foldMap delay [1..10]
886+-- Stream.drain $ Stream.concatFoldableWith Stream.async (map delay [1..10])
887+-- Stream.drain $ Stream.concatMapFoldableWith Stream.async delay [1..10]
888+-- Stream.drain $ Stream.concatForFoldableWith Stream.async [1..10] delay
889+-- :}
890+--
974891
975892-- $nesting
976893--
@@ -1013,7 +930,6 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
1013930-- the examples. However, the streams could also be made of monadic actions
1014931-- instead.
1015932--
1016−-- @
1017933-- >>> :{
1018934-- Stream.drain $ do
1019935-- x <- Stream.fromFoldable [3,2,1]
@@ -1023,26 +939,24 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
1023939-- ThreadId ...: Delay 2
1024940-- ThreadId ...: Delay 1
1025941--
1026−-- @
1027−--
1028942-- As we can see, the code after the @fromFoldable@ statement is run three
1029943-- times, once for each value of @x@ drawn from the stream. All the three
1030944-- iterations are serial and run in the same thread one after another. In
1031945-- imperative terms this is equivalent to a @for@ loop with three iterations.
1032946--
1033−-- A console echo loop copying standard input to standard output can simply be
1034−-- written like this:
947+-- We can write the console echo program that we wrote earlier using the monad
948+-- instance:
1035949--
1036−-- @
1037−-- main = Stream.'drain' $ forever $ Stream.'fromEffect' getLine >>= Stream.'fromEffect' . putStrLn
1038−-- @
950+-- >>> :{
951+-- main =
952+-- Stream.drain $ do
953+-- x <- Stream.repeatM getLine
954+-- Stream.fromEffect $ putStrLn x
955+-- :}
1039956--
1040957-- 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
1042−-- the next iteration of the parent loop. This behaves just like nested @for@
1043−-- loops in imperative programming.
958+-- manner:
1044959--
1045−-- @
1046960-- >>> :{
1047961-- Stream.drain $ do
1048962-- x <- Stream.fromFoldable [1,2]
@@ -1054,7 +968,9 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
1054968-- (2,3)
1055969-- (2,4)
1056970--
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.
1058974--
1059975-- Notice that this is analogous to merging streams of type 'Serial' or merging
1060976-- streams using 'serial'.
@@ -1065,25 +981,17 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
1065981-- that it can speculatively perform a bounded number of next iterations of a
1066982-- loop concurrently.
1067983--
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−-- @
1073984-- >>> :{
1074−-- comp = Stream.toList . Stream.fromAhead $ do
1075−-- x <- Stream.fromFoldable [3,2,1]
1076−-- delay x >> return x
985+-- Stream.toList $ Stream.fromAhead $ do
986+-- x <- Stream.fromFoldable [3,2,1]
987+-- delay x
988+-- return x
1077989-- :}
1078−--
1079−-- >>> comp >>= print
1080990-- ThreadId ...: Delay 1
1081991-- ThreadId ...: Delay 2
1082992-- ThreadId ...: Delay 3
1083993-- [3,2,1]
1084994--
1085−-- @
1086−--
1087995-- This code finishes in 3 seconds, 'Serial' would take 6 seconds. As we can
1088996-- see all the three iterations are concurrent and run in different threads,
1089997-- however, the results are returned in the serial order.
@@ -1094,23 +1002,18 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
10941002-- outer iteration. The only difference is that we may execute multiple future
10951003-- iterations concurrently and keep the results ready.
10961004--
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+--
10971009
10981010-- $concurrentNesting
10991011--
11001012-- The 'Monad' composition of 'Async' type can perform the iterations of a
1101−-- loop concurrently. Concurrency is demand driven i.e. more concurrent
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'.
1013+-- loop concurrently.
11101014--
1111−-- @
11121015-- >>> :{
1113−-- Stream.drain . Stream.fromAsync $ do
1016+-- Stream.drain $ Stream.fromAsync $ do
11141017-- x <- Stream.fromFoldable [3,2,1]
11151018-- delay x
11161019-- :}
@@ -1118,47 +1021,46 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
11181021-- ThreadId ...: Delay 2
11191022-- ThreadId ...: Delay 3
11201023--
1121−-- @
1122−--
11231024-- As we can see the code after the @fromFoldable@ statement is run three
11241025-- times, once for each value of @x@. All the three iterations are concurrent
11251026-- and run in different threads. The iteration with least delay finishes first.
11261027-- When compared to imperative programming, this can be viewed as a @for@ loop
11271028-- with three concurrent iterations.
11281029--
1129−-- Concurrency is demand driven just as in the case of 'async' merging.
1130−-- When multiple streams are composed using this style, the iterations are
1131−-- triggered in a depth first manner just like 'Serial' i.e. nested iterations are
1132−-- executed before we proceed to the next iteration at higher level. However,
1133−-- unlike 'Serial' more than one iterations may be started concurrently based
1134−-- on the demand from the consumer of the stream.
1030+-- Concurrency is demand driven i.e. more concurrent iterations are started
1031+-- only if the previous iterations are not able to saturate the consumer of the
1032+-- output stream. This works exactly the same way as the merging of two
1033+-- streams using 'async' works.
11351034--
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'.
11371038--
1138−-- Stream.drain . Stream.fromAsync $ do
1039+-- When multiple streams are nested using this style, the iterations are
1040+-- concurrently evaluated in a depth first manner:
1041+--
1042+--
1043+-- >>> :{
1044+-- Stream.drain $ Stream.fromAsync $ do
11391045-- x <- Stream.fromFoldable [1,2]
11401046-- y <- Stream.fromFoldable [3,4]
11411047-- Stream.fromEffect $ putStrLn $ show (x, y)
1142−--
1048+-- :}
11431049-- (1,3)
11441050-- (1,4)
11451051-- (2,3)
11461052-- (2,4)
11471053--
1148−-- @
1054+-- Nested iterations are given preference for concurrent evaluation i.e.
1055+-- (1,4) will be scheduled in preference to (2,3).
11491056
11501057-- $interleavedNesting
11511058--
11521059-- The 'Monad' composition of 'WSerial' type interleaves the iterations of
1153−-- outer and inner loops in a nested loop composition. This works exactly the
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'.
1060+-- outer and inner loops in a nested loop composition.
11581061--
1159−-- @
11601062-- >>> :{
1161−-- Stream.drain . Stream.fromWSerial $ do
1063+-- Stream.drain $ Stream.fromWSerial $ do
11621064-- x <- Stream.fromFoldable [1,2]
11631065-- y <- Stream.fromFoldable [3,4]
11641066-- Stream.fromEffect $ putStrLn $ show (x, y)
@@ -1168,47 +1070,48 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
11681070-- (1,4)
11691071-- (2,4)
11701072--
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'.
11721079--
11731080
11741081-- $wasyncNesting
11751082--
1176−-- Just like 'Async' the 'Monad' composition of 'WAsync' runs the iterations of
1177−-- a loop concurrently. The difference is in the nested loop behavior. The
1178−-- nested loops in this type are traversed and executed in a breadth first
1179−-- 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'.
1083+-- Like 'Async', the 'Monad' composition of 'WAsync' runs the iterations of a
1084+-- loop concurrently. It differs from 'Async' in the nested loop behavior. Like
1085+-- 'WSerial', the nested loops in this type are traversed and executed in a
1086+-- breadth first manner rather than the depth first manner of 'Async' style.
11841087--
1185−-- @
11861088-- >>> :{
1187−-- Stream.drain . Stream.fromWAsync $ do
1188−-- x <- Stream.delay 1 $ Stream.fromFoldable [1,2]
1189−-- y <- Stream.delay 1 $ Stream.fromFoldable [3,4]
1089+-- Stream.drain $ Stream.fromWAsync $ do
1090+-- x <- Stream.fromSerial $ Stream.fromFoldable [1,2]
1091+-- y <- Stream.fromSerial $ Stream.fromFoldable [3,4]
11901092-- Stream.fromEffect $ putStrLn $ show (x, y)
11911093-- :}
11921094-- (1,3)
1193−-- ...
1194−-- ...
1095+-- (1,4)
1096+-- (2,3)
11951097-- (2,4)
11961098--
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+--
11981107
11991108-- $parallelNesting
12001109--
12011110-- 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
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'.
1111+-- iterations of a loop concurrently.
12081112--
1209−-- @
12101113-- >>> :{
1211−-- Stream.drain . Stream.fromParallel $ do
1114+-- Stream.drain $ Stream.fromParallel $ do
12121115-- x <- Stream.fromFoldable [3,2,1]
12131116-- delay x
12141117-- :}
@@ -1216,7 +1119,15 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
12161119-- ThreadId ...: Delay 2
12171120-- ThreadId ...: Delay 3
12181121--
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+--
12201131
12211132-- $monadExercise
12221133--
@@ -1225,29 +1136,27 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
12251136-- 'IsStream' type class constraint. When running the stream we can choose the
12261137-- specific mode of composition. For example take a look at the following code.
12271138--
1228−-- @
1139+-- >>> :{
12291140-- composed :: (Stream.IsStream t, Monad (t IO)) => t IO ()
12301141-- composed = do
12311142-- sz <- sizes
12321143-- cl <- colors
12331144-- sh <- shapes
1234−-- Stream.'fromEffect' $ putStrLn $ show (sz, cl, sh)
1235−--
1145+-- Stream.fromEffect $ putStrLn $ show (sz, cl, sh)
12361146-- where
1237−--
1238−-- sizes = Stream.'fromFoldable' [1, 2, 3]
1239−-- colors = Stream.'fromFoldable' ["red", "green", "blue"]
1240−-- shapes = Stream.'fromFoldable' ["triangle", "square", "circle"]
1241−-- @
1147+-- sizes = Stream.fromFoldable [1, 2, 3]
1148+-- colors = Stream.fromFoldable ["red", "green", "blue"]
1149+-- shapes = Stream.fromFoldable ["triangle", "square", "circle"]
1150+-- :}
12421151--
12431152-- Now we can interpret this in whatever way we want:
12441153--
12451154-- @
1246−-- main = Stream.'drain' . Stream.'fromSerial' $ composed
1247−-- main = Stream.'drain' . Stream.'fromWSerial' $ composed
1248−-- main = Stream.'drain' . Stream.'fromAsync' $ composed
1249−-- main = Stream.'drain' . Stream.'fromWAsync' $ composed
1250−-- main = Stream.'drain' . Stream.'fromParallel' $ composed
1155+-- main = Stream.'drain' $ Stream.'fromSerial' $ composed
1156+-- main = Stream.'drain' $ Stream.'fromWSerial' $ composed
1157+-- main = Stream.'drain' $ Stream.'fromAsync' $ composed
1158+-- main = Stream.'drain' $ Stream.'fromWAsync' $ composed
1159+-- main = Stream.'drain' $ Stream.'fromParallel' $ composed
12511160-- @
12521161--
12531162-- 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))
12591168-- stream. 'fmap' behaves in the same way for all stream types, it is always
12601169-- serial.
12611170--
1262−-- @
12631171-- >>> (Stream.toList $ fmap show $ Stream.fromFoldable [1..10]) >>= print
12641172-- ["1","2","3","4","5","6","7","8","9","10"]
12651173--
1266−-- @
1267−--
12681174-- Also see functions 'mapM' and 'sequence' from "Streamly.Prelude" module
12691175-- which can map actions concurrently depending on the type of the input stream.
12701176
@@ -1274,15 +1180,14 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
12741180-- zipping applicatives separate types 'ZipSerial' and 'ZipAsync' are
12751181-- provided.
12761182--
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
12781184-- serially and takes a total 17 seconds (1 + 3 + 4 + 2 + 3 + 4):
12791185--
1280−-- @
12811186-- >>> d n = delay n >> return n
12821187-- >>> s1 = d 1 <> d 2
12831188-- >>> s2 = d 3 <> d 4
12841189--
1285−-- >>> (Stream.toList . Stream.fromSerial $ (,) <$> s1 <*> s2) >>= print
1190+-- >>> (Stream.toList $ Stream.fromSerial $ (,) <$> s1 <*> s2) >>= print
12861191-- ThreadId ...: Delay 1
12871192-- ThreadId ...: Delay 3
12881193-- ThreadId ...: Delay 4
@@ -1291,13 +1196,10 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
12911196-- ThreadId ...: Delay 4
12921197-- [(1,3),(1,4),(2,3),(2,4)]
12931198--
1294−-- @
1199+-- Similarly, 'WSerial' applicative runs the iterations in an interleaved
1200+-- order but being serial it too takes a total of 17 seconds:
12951201--
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
13011203-- ThreadId ...: Delay 1
13021204-- ThreadId ...: Delay 3
13031205-- ThreadId ...: Delay 2
@@ -1306,14 +1208,12 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
13061208-- ThreadId ...: Delay 4
13071209-- [(1,3),(2,3),(1,4),(2,4)]
13081210--
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
13121212-- of 6 seconds which is max (1, 2) + max (3, 4):
13131213--
1314−-- @
1315−-- main = (Stream.'toList' . Stream.'fromAsync' $ (,) \<$> s1 \<*> s2) >>= print
1316−-- @
1214+-- >>> (Stream.toList $ Stream.fromAsync $ (,) <$> s1 <*> s2) >>= print
1215+-- ...
1216+--
13171217-- @
13181218-- ThreadId 34: Delay 1
13191219-- ThreadId 36: Delay 2
@@ -1324,12 +1224,13 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
13241224-- [(1,3),(2,3),(1,4),(2,4)]
13251225-- @
13261226--
1327−-- Similarly 'WAsync' as well can run the iterations concurrently and
1328−-- therefore takes a total of 6 seconds (2 + 4):
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
1229+-- section, therefore, it too takes a total of 6 seconds (2 + 4):
1230+--
1231+-- >>> (Stream.toList $ Stream.fromWAsync $ (,) <$> s1 <*> s2) >>= print
1232+-- ...
13291233--
1330−-- @
1331−-- main = (Stream.'toList' . Stream.'fromWAsync' $ (,) \<$> s1 \<*> s2) >>= print
1332−-- @
13331234-- @
13341235-- ThreadId 34: Delay 1
13351236-- ThreadId 36: Delay 2
@@ -1355,22 +1256,13 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
13551256-- 'fromZipSerial' type combinator can be used to switch to serial applicative
13561257-- zip composition:
13571258--
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−--
13671259-- This takes total 10 seconds to zip, which is (1 + 2 + 3 + 4) since
13681260-- everything runs serially:
13691261--
13701262-- >>> d n = delay n >> return n
13711263-- >>> s1 = Stream.fromSerial $ d 1 <> d 2
13721264-- >>> s2 = Stream.fromSerial $ d 3 <> d 4
1373−-- >>> (Stream.toList . Stream.fromZipSerial $ (,) <$> s1 <*> s2) >>= print
1265+-- >>> (Stream.toList $ Stream.fromZipSerial $ (,) <$> s1 <*> s2) >>= print
13741266-- ThreadId ...: Delay 1
13751267-- ThreadId ...: Delay 3
13761268-- ThreadId ...: Delay 2
@@ -1384,31 +1276,13 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
13841276-- 'fromZipAsync' type combinator can be used to switch to parallel applicative
13851277-- zip composition:
13861278--
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−--
14001279-- This takes 7 seconds to zip, which is max (1,3) + max (2,4) because 1 and 3
14011280-- are produced concurrently, and 2 and 4 are produced concurrently:
14021281--
14031282-- >>> d n = delay n >> return n
14041283-- >>> s1 = Stream.fromSerial $ d 1 <> d 2
14051284-- >>> s2 = Stream.fromSerial $ d 3 <> d 4
1406−--
1407−-- >>> :{
1408−-- do
1409−-- hSetBuffering stdout LineBuffering
1410−-- (Stream.toList . Stream.fromZipAsync $ (,) <$> s1 <*> s2) >>= print
1411−-- :}
1285+-- >>> (Stream.toList $ Stream.fromZipAsync $ (,) <$> s1 <*> s2) >>= print
14121286-- ThreadId ...: Delay 1
14131287-- ThreadId ...: Delay 2
14141288-- ThreadId ...: Delay 3
@@ -1427,35 +1301,31 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
14271301--
14281302-- In the following example the squares of @x@ and @y@ are computed
14291303-- 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
14311305-- choose different combinators for the monadic processing and the stream
14321306-- generation, to control the concurrency. We can also use the 'fromAsync'
14331307-- combinator instead of explicitly folding with 'async'.
14341308--
1435−-- @
1436−-- import qualified "Streamly.Prelude" as Stream
1437−-- import Data.List (sum)
1438−--
1309+-- >>> import Data.List (sum)
1310+-- >>> :{
14391311-- main = do
1440−-- z \<- Stream.'toList'
1441−-- $ Stream.'fromSerial' -- Serial monadic processing (sqrt below)
1312+-- z <- Stream.toList
1313+-- $ Stream.fromSerial -- Serial monadic processing (sqrt below)
14421314-- $ do
1443−-- x2 \<- Stream.'concatForFoldableWith' Stream.'async' [1..100] $ -- Concurrent @"for"@ loop
1444−-- \\x -> return $ x * x -- body of the loop
1445−-- y2 \<- Stream.'concatForFoldableWith' Stream.'async' [1..100] $
1446−-- \\y -> return $ y * y
1315+-- x2 <- Stream.concatForFoldableWith Stream.async [1..100] $ -- Concurrent @"for"@ loop
1316+-- \x -> return $ x * x -- body of the loop
1317+-- y2 <- Stream.concatForFoldableWith Stream.async [1..100] $
1318+-- \y -> return $ y * y
14471319-- return $ sqrt (x2 + y2)
14481320-- print $ sum z
1449−-- @
1321+-- :}
14501322--
14511323-- We can see how this directly maps to the imperative style
14521324-- <https://en.wikipedia.org/wiki/OpenMP OpenMP> model, we use combinators
14531325-- and operators instead of the ugly pragmas.
14541326--
14551327-- For more concurrent programming examples see,
1456−-- <https://github.com/composewell/streamly-examples/tree/master/ListDir.hs ListDir.hs>,
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.
1328+-- <https://github.com/composewell/streamly-examples>.
14591329
14601330-- $reactive
14611331--