@@ -13,6 +13,9 @@
1313
1414module User.Tutorials.Tutorial
1515 (
16+ -- * Imports
17+ -- $setup
18+
1619 -- * Stream Types
1720 -- $streams
1821
@@ -86,22 +89,16 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
8689-- XXX This tutorial has to be re-written.
8790
8891-- $setup
89−-- >>> :m
90−-- >>> :set -fno-warn-deprecations
91−-- >>> import Data.Function ((&))
92−-- >>> import Streamly.Prelude ((|:), (|&))
93−-- >>> import qualified Streamly.Prelude as Stream
94−-- >>> import qualified Streamly.Data.Fold as Fold
95−--
96−
97−-- $imports
9892--
99−-- In most of example snippets we do not repeat the imports. Where imports are
100−-- not explicitly specified use the imports shown below.
93+-- In most of example snippets we do not repeat the imports. Where
94+-- imports are not explicitly specified use the imports shown below.
10195--
10296-- >>> :m
97+-- >>> :set -fno-warn-deprecations
10398-- >>> import Data.Function ((&))
10499-- >>> import Streamly.Prelude ((|:), (|&))
100+-- >>> import Streamly.Data.Stream (Stream)
101+-- >>> import Streamly.Internal.Data.Stream.Cross (CrossStream(..))
105102-- >>> import qualified Streamly.Prelude as Stream
106103-- >>> import qualified Streamly.Data.Fold as Fold
107104--
@@ -134,13 +131,8 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
134131-- world
135132-- ["hello","world"]
136133--
137−-- To create a singleton stream from a pure value use 'fromPure' or 'pure' and to
138−-- create a singleton stream from a monadic action use 'fromEffect'. Note that in
139−-- case of Zip applicative streams "pure" repeats the value to generate an
140−-- infinite stream.
141−--
142−-- >>> Stream.toList $ pure 1
143−-- [1]
134+-- To create a singleton stream from a pure value use 'fromPure' and to
135+-- create a singleton stream from a monadic action use 'fromEffect'.
144136--
145137-- >>> Stream.toList $ Stream.fromPure 1
146138-- [1]
@@ -354,11 +346,8 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
354346
355347-- $regularSerial
356348--
357−-- The 'Monad' composition of the 'Serial' type behaves like a standard list
358−-- transformer. This is the default when we do not use an explicit type
359−-- combinator. However, the 'fromSerial' type combinator can be used to switch to
360−-- this style of composition. We will see how this style of composition works
361−-- in the following examples.
349+-- The 'Monad' composition of the 'CrossStream' type behaves like a standard list
350+-- transformer.
362351--
363352-- Let's start with an example with a simple @for@ loop without any nesting.
364353-- For simplicity of illustration we are using streams of pure values in all
@@ -366,9 +355,9 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
366355-- instead.
367356--
368357-- >>> :{
369−-- Stream.drain $ do
370−-- x <- Stream.fromFoldable [3,2,1]
371−-- Stream.fromEffect $ print x
358+-- Stream.drain $ getCrossStream $ do
359+-- x <- CrossStream (Stream.fromFoldable [3,2,1])
360+-- CrossStream (Stream.fromEffect $ print x)
372361-- :}
373362-- 3
374363-- 2
@@ -384,19 +373,19 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
384373--
385374-- >>> :{
386375-- main =
387−-- Stream.drain $ do
388−-- x <- Stream.repeatM getLine
389−-- Stream.fromEffect $ putStrLn x
376+-- Stream.drain $ getCrossStream $ do
377+-- x <- CrossStream (Stream.repeatM getLine)
378+-- CrossStream (Stream.fromEffect $ putStrLn x)
390379-- :}
391380--
392381-- When multiple streams are composed using this style they nest in a DFS
393382-- manner:
394383--
395384-- >>> :{
396−-- Stream.drain $ do
397−-- x <- Stream.fromFoldable [1,2]
398−-- y <- Stream.fromFoldable [3,4]
399−-- Stream.fromEffect $ print (x, y)
385+-- Stream.drain $ getCrossStream $ do
386+-- x <- CrossStream (Stream.fromFoldable [1,2])
387+-- y <- CrossStream (Stream.fromFoldable [3,4])
388+-- CrossStream (Stream.fromEffect $ print (x, y))
400389-- :}
401390-- (1,3)
402391-- (1,4)
@@ -412,14 +401,16 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
412401
413402-- $interleavedNesting
414403--
404+-- TBD: generate the WSerial type using the TH utils.
405+--
415406-- The 'Monad' composition of 'WSerial' type interleaves the iterations of
416407-- outer and inner loops in a nested loop composition.
417408--
418−-- >>> :{
419−-- Stream.drain $ Stream.fromWSerial $ do
420−-- x <- Stream.fromFoldable [1,2]
421−-- y <- Stream.fromFoldable [3,4]
422−-- Stream.fromEffect $ print (x, y)
409+-- >> :{
410+-- Stream.drain $ getWSerial $ do
411+-- x <- WSerialStream (Stream.fromFoldable [1,2])
412+-- y <- WSerialStream (Stream.fromFoldable [3,4])
413+-- WSerialStream (Stream.fromEffect $ print (x, y))
423414-- :}
424415-- (1,3)
425416-- (2,3)
@@ -436,36 +427,19 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
436427
437428-- $monadExercise
438429--
439−-- Streamly code is usually written in a way that is agnostic of the
440−-- specific monadic composition type. We use a polymorphic type with a
441−-- 'IsStream' type class constraint. When running the stream we can choose the
442−-- specific mode of composition. For example take a look at the following code.
443−--
444430-- >>> :{
445−-- composed :: (Stream.IsStream t, Monad (t IO)) => t IO ()
446−-- composed = do
447−-- sz <- sizes
448−-- cl <- colors
449−-- sh <- shapes
450−-- Stream.fromEffect $ print (sz, cl, sh)
431+-- composed :: Stream IO ()
432+-- composed = getCrossStream $ do
433+-- sz <- CrossStream sizes
434+-- cl <- CrossStream colors
435+-- sh <- CrossStream shapes
436+-- CrossStream (Stream.fromEffect $ print (sz, cl, sh))
451437-- where
452438-- sizes = Stream.fromFoldable [1, 2, 3]
453439-- colors = Stream.fromFoldable ["red", "green", "blue"]
454440-- shapes = Stream.fromFoldable ["triangle", "square", "circle"]
455441-- :}
456442--
457−-- Now we can interpret this in whatever way we want:
458−--
459−-- @
460−-- main = Stream.'drain' $ Stream.'fromSerial' $ composed
461−-- main = Stream.'drain' $ Stream.'fromWSerial' $ composed
462−-- main = Stream.'drain' $ Stream.'fromAsync' $ composed
463−-- main = Stream.'drain' $ Stream.'fromWAsync' $ composed
464−-- main = Stream.'drain' $ Stream.'fromParallel' $ composed
465−-- @
466−--
467−-- As an exercise try to figure out the output of this code for each mode of
468−-- composition.
469443
470444-- $functor
471445--
@@ -482,17 +456,17 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
482456-- $applicative
483457--
484458-- Applicative is precisely the same as the 'ap' operation of 'Monad'. For
485−-- zipping applicatives separate types 'ZipSerial' and 'ZipAsync' are
459+-- zipping applicatives separate types 'ZipStream' and 'ZipAsync' are
486460-- provided.
487461--
488−-- The following is an example of 'Serial' applicative, it runs all iterations
462+-- The following is an example of 'CrossStream' applicative, it runs all iterations
489463-- serially:
490464--
491−-- >>> p n = Stream.fromEffect (print n) >> return n
465+-- >>> p n = Stream.fromEffect (print n >> pure n)
492466-- >>> s1 = p 1 <> p 2
493467-- >>> s2 = p 3 <> p 4
494468--
495−-- >>> (Stream.toList $ Stream.fromSerial $ (,) <$> s1 <*> s2) >>= print
469+-- >>> (Stream.toList $ getCrossStream $ (,) <$> CrossStream s1 <*> CrossStream s2) >>= print
496470-- 1
497471-- 3
498472-- 4
@@ -504,7 +478,7 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
504478-- Similarly, 'WSerial' applicative runs the iterations in an interleaved
505479-- order but being serial it too takes a total of 17 seconds:
506480--
507−-- >>> (Stream.toList $ Stream.fromWSerial $ (,) <$> s1 <*> s2) >>= print
481+-- >> (Stream.toList $ Stream.WSerialStream $ (,) <$> WSerialStream s1 <*> WSerialStream s2) >>= print
508482-- 1
509483-- 3
510484-- 2
@@ -528,7 +502,7 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
528502-- 'fromZipSerial' type combinator can be used to switch to serial applicative
529503-- zip composition:
530504--
531−-- >>> p n = Stream.fromEffect (print n) >> return n
505+-- >>> p n = Stream.fromEffect (print n >> pure n)
532506-- >>> s1 = Stream.fromSerial $ p 1 <> p 2
533507-- >>> s2 = Stream.fromSerial $ p 3 <> p 4
534508-- >>> (Stream.toList $ Stream.fromZipSerial $ (,) <$> s1 <*> s2) >>= print