on master help sign in
Update tutorial with zip types & composition summary
fa3d53dHarendra Kumar
src/Streamly/Tutorial.hs+107−12
@@ -91,6 +91,12 @@ module Streamly.Tutorial
91 -- * Zipping Streams
91 -- * Zipping Streams
92 -- $zipping
92 -- $zipping
93
93
94+ -- ** Serial Zipping
95+ -- $serialzip
96+
97+ -- ** Parallel Zipping
98+ -- $parallelzip
99+
94 -- * Concurrent Programming Examples
100 -- * Concurrent Programming Examples
95 -- $concurrent
101 -- $concurrent
96
102
@@ -587,6 +593,10 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
587-- total 17 seconds (1 + 3 + 4 + 2 + 3 + 4):
593-- total 17 seconds (1 + 3 + 4 + 2 + 3 + 4):
588--
594--
589-- @
595-- @
596+-- import Streamly
597+-- import Streamly.Prelude
598+-- import Control.Concurrent
599+--
590-- s1 = d 1 <> d 2
600-- s1 = d 1 <> d 2
591-- s2 = d 3 <> d 4
601-- s2 = d 3 <> d 4
592-- d n = delay n >> return n
602-- d n = delay n >> return n
@@ -655,10 +665,89 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
655-- Folds
665-- Folds
656
666
657-- $compositionSummary
667-- $compositionSummary
658−-- Summary of compositions
668+--
669+-- The following table summarizes the types for monadic compositions and the
670+-- operators for sum style compositions. This table captures the essence of
671+-- streamly.
672+--
673+-- @
674+-- +-----+--------------+------------+
675+-- | | Serial | Concurrent |
676+-- +=====+==============+============+
677+-- | DFS | 'StreamT' | 'AsyncT' |
678+-- | +--------------+------------+
679+-- | | '<>' | '<|' |
680+-- +-----+--------------+------------+
681+-- | BFS | 'InterleavedT' | 'ParallelT' |
682+-- | +--------------+------------+
683+-- | | '<=>' | '<|>' |
684+-- +-----+--------------+------------+
685+-- @
659
686
660-- $zipping
687-- $zipping
661−-- Applicative composition, Parallel applicative
688+--
689+-- Zipping is a special transformation where the corresponding elements of two
690+-- streams are combined together using a zip function producing a new
691+-- stream of outputs. Two different types are provided for serial and
692+-- concurrent zipping. These types provide an applicative instance that zips
693+-- the argument streams.
694+
695+-- $serialzip
696+--
697+-- 'StreamZip' zips streams serially:
698+--
699+-- @
700+-- import Streamly
701+-- import Streamly.Prelude
702+-- import Control.Concurrent
703+--
704+-- d n = delay n >> return n
705+-- s1 = adapt . serially $ d 1 <> d 2
706+-- s2 = adapt . serially $ d 3 <> d 4
707+--
708+-- main = (toList . zipping $ (,) \<$> s1 \<*> s2) >>= print
709+-- @
710+--
711+-- This takes total 10 seconds to zip, which is (1 + 2 + 3 + 4) since
712+-- everything runs serially:
713+--
714+-- @
715+-- ThreadId 29: Delay 1
716+-- ThreadId 29: Delay 3
717+-- ThreadId 29: Delay 2
718+-- ThreadId 29: Delay 4
719+-- [(1,3),(2,4)]
720+-- @
721+
722+-- $parallelzip
723+--
724+-- 'AsyncZip' zips streams concurrently:
725+--
726+-- @
727+-- import Streamly
728+-- import Streamly.Prelude
729+-- import Control.Concurrent
730+-- import System.IO (stdout, hSetBuffering, BufferMode(LineBuffering))
731+--
732+-- d n = delay n >> return n
733+-- s1 = adapt . serially $ d 1 <> d 2
734+-- s2 = adapt . serially $ d 3 <> d 4
735+--
736+-- main = do
737+-- liftIO $ hSetBuffering stdout LineBuffering
738+-- (toList . zippingAsync $ (,) \<$> s1 \<*> s2) >>= print
739+-- @
740+--
741+-- This takes 7 seconds to zip, which is max (1,3) + max (2,4) because 1 and 3
742+-- are produced concurrently, and 2 and 4 are produced concurrently:
743+--
744+-- @
745+-- ThreadId 32: Delay 1
746+-- ThreadId 32: Delay 2
747+-- ThreadId 33: Delay 3
748+-- ThreadId 33: Delay 4
749+-- [(1,3),(2,4)]
750+-- @
662
751
663-- $concurrent
752-- $concurrent
664--
753--
@@ -671,6 +760,7 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
671--
760--
672-- @
761-- @
673-- import Streamly
762-- import Streamly
763+-- import Streamly.Prelude (toList)
674-- import Data.List (sum)
764-- import Data.List (sum)
675--
765--
676-- main = do
766-- main = do
@@ -684,11 +774,13 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
684--
774--
685-- @
775-- @
686-- import Streamly
776-- import Streamly
777+-- import Streamly.Prelude (toList)
687-- import Data.List (sum)
778-- import Data.List (sum)
688--
779--
689-- main = do
780-- main = do
690−-- z \<- toList $ asyncly $ foldMapWith (\<|) (\\x -> return $ x * x) [1..100] >>= \\xsq ->
781+-- z \<- toList $ asyncly $ do
691−-- foldMapWith (\<|) (\\x -> return $ x * x) [1..100] >>= \\ysq ->
782+-- xsq \<- foldMapWith (\<|) (\\x -> return $ x * x) [1..100]
783+-- ysq \<- foldMapWith (\<|) (\\x -> return $ x * x) [1..100]
692-- return $ sqrt (xsq + ysq)
784-- return $ sqrt (xsq + ysq)
693-- print $ sum z
785-- print $ sum z
694-- @
786-- @
@@ -698,6 +790,8 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
698-- Let us see a reactive programming example:
790-- Let us see a reactive programming example:
699--
791--
700-- @
792-- @
793+-- {-\# LANGUAGE FlexibleContexts #-}
794+--
701-- import Streamly
795-- import Streamly
702-- import Control.Concurrent (threadDelay)
796-- import Control.Concurrent (threadDelay)
703-- import Control.Monad (when)
797-- import Control.Monad (when)
@@ -706,7 +800,7 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
706--
800--
707-- data Event = Harm Int | Heal Int | Quit deriving (Show)
801-- data Event = Harm Int | Heal Int | Quit deriving (Show)
708--
802--
709−-- userAction :: MonadIO m => AsyncT m Event
803+-- userAction :: MonadIO m => StreamT m Event
710-- userAction = cycle1 $ liftIO askUser
804-- userAction = cycle1 $ liftIO askUser
711-- where
805-- where
712-- askUser = do
806-- askUser = do
@@ -716,15 +810,15 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
716-- "quit" -> return Quit
810-- "quit" -> return Quit
717-- _ -> putStrLn "What?" >> askUser
811-- _ -> putStrLn "What?" >> askUser
718--
812--
719−-- acidRain :: MonadIO m => AsyncT m Event
813+-- acidRain :: MonadIO m => StreamT m Event
720-- acidRain = cycle1 $ liftIO (threadDelay 1000000) >> return (Harm 1)
814-- acidRain = cycle1 $ liftIO (threadDelay 1000000) >> return (Harm 1)
721--
815--
722−-- game :: (MonadAsync m, MonadState Int m) => AsyncT m ()
816+-- game :: (MonadAsync m, MonadState Int m) => StreamT m ()
723-- game = do
817-- game = do
724-- event \<- userAction \<|> acidRain
818-- event \<- userAction \<|> acidRain
725-- case event of
819-- case event of
726−-- Harm n -> modify $ \h -> h - n
820+-- Harm n -> modify $ \\h -> h - n
727−-- Heal n -> modify $ \h -> h + n
821+-- Heal n -> modify $ \\h -> h + n
728-- Quit -> fail "quit"
822-- Quit -> fail "quit"
729--
823--
730-- h <- get
824-- h <- get
@@ -732,9 +826,10 @@ import Control.Monad.Trans.Class (MonadTrans (lift))
732-- liftIO $ putStrLn $ "Health = " ++ show h
826-- liftIO $ putStrLn $ "Health = " ++ show h
733--
827--
734-- main = do
828-- main = do
735−-- putStrLn "Your health is deteriorating due to acid rain,\
829+-- putStrLn "Your health is deteriorating due to acid rain,\\
736−-- \ type \"potion\" or \"quit\""
830+-- \\ type \\"potion\\" or \\"quit\\""
737−-- runStateT (runStreaming $ serially $ game) 60
831+-- _ <- runStateT (runStreamT game) 60
832+-- return ()
738-- @
833-- @
739
834
740-- $statemachine
835-- $statemachine