on master help sign in
Update the docs of AheadT for brevity/clarity
commit1f1e3bdb1a3f01f7d73732f19ecb592dc53d3b82 authorHarendra Kumar <harendra@composewell.com> dateTue 30 Mar 2021, 16:47 (6 years ago) parentf8a84cc
2 files changed+50−63
src/Streamly/Internal/Data/Stream/Ahead.hs+41−36 src/Streamly/Prelude.hs+9−27
src/Streamly/Internal/Data/Stream/Ahead.hs+41−36
@@ -595,8 +595,16 @@ forkSVarAhead m1 m2 = mkStream $ \st yld sng stp -> do
595595
596596infixr 6 `ahead`
597597
598−-- | Polymorphic version of the 'Semigroup' operation '<>' of 'AheadT'.
599−-- Merges two streams sequentially but with concurrent lookahead.
598+-- | Appends two streams, some future actions may be evaluated concurrently,
599+-- ahead of time. The behavior is similar to 'consM' for 'AheadT' streams:
600+--
601+-- >>> stream = Stream.yieldM (delay 2) `ahead` Stream.yieldM (delay 1)
602+-- >>> Stream.toList stream -- IO [Int]
603+-- 1 sec
604+-- 2 sec
605+-- [2,1]
606+--
607+-- This operation can be used to fold an infinite lazy container of streams.
600608--
601609-- /Since: 0.3.0 ("Streamly")/
602610--
@@ -625,46 +633,43 @@ consMAhead m r = fromStream $ K.yieldM m `ahead` (toStream r)
625633-- AheadT
626634------------------------------------------------------------------------------
627635
628−-- | The 'Semigroup' operation for 'AheadT' appends two streams. The combined
629−-- stream behaves like a single stream with the actions from the second stream
630−-- appended to the first stream. The combined stream is evaluated in the
631−-- speculative style. This operation can be used to fold an infinite lazy
632−-- container of streams.
636+-- | For 'AheadT' streams:
633637--
634638-- @
635−-- import "Streamly.Prelude"
636−-- import qualified "Streamly.Prelude" as S
637−-- import Control.Concurrent
638−--
639−-- main = do
640−-- xs \<- S.'toList' . S.'aheadly' $ (p 1 |: p 2 |: nil) <> (p 3 |: p 4 |: nil)
641−-- print xs
642−-- where p n = threadDelay 1000000 >> return n
643−-- @
644−-- @
645−-- [1,2,3,4]
639+-- (<>) = 'Streamly.Prelude.ahead'
640+-- (>>=) = flip . 'Streamly.Prelude.concatMapWith' 'Streamly.Prelude.ahead'
646641-- @
647642--
648−-- Any exceptions generated by a constituent stream are propagated to the
649−-- output stream.
643+-- Any exceptions generated by concurrent evaluation are propagated to the
644+-- output stream as soon as they occur.
650645--
651−-- The monad instance of 'AheadT' may run each monadic continuation (bind)
652−-- concurrently in a speculative manner, performing side effects in a partially
653−-- ordered manner but producing the outputs in an ordered manner like
654−-- 'SerialT'.
646+-- A single 'Monad' bind behaves like a @for@ loop with iterations executed
647+-- concurrently, ahead of time, producing side effects of iterations out of
648+-- order, but results in order:
655649--
656−-- @
657−-- main = S.drain . S.'aheadly' $ do
658−-- n <- return 3 \<\> return 2 \<\> return 1
659−-- S.yieldM $ do
660−-- threadDelay (n * 1000000)
661−-- myThreadId >>= \\tid -> putStrLn (show tid ++ ": Delay " ++ show n)
662−-- @
663−-- @
664−-- ThreadId 40: Delay 1
665−-- ThreadId 39: Delay 2
666−-- ThreadId 38: Delay 3
667−-- @
650+-- >>> :{
651+-- Stream.toList $ Stream.aheadly $ do
652+-- x <- Stream.fromList [2,1] -- foreach x in stream
653+-- Stream.yieldM $ delay x
654+-- :}
655+-- 1 sec
656+-- 2 sec
657+-- [2,1]
658+--
659+-- Nested monad binds behave like nested @for@ loops with nested iterations
660+-- executed concurrently, ahead of time:
661+--
662+-- >>> :{
663+-- Stream.toList $ Stream.aheadly $ do
664+-- x <- Stream.fromList [1,2] -- foreach x in stream
665+-- y <- Stream.fromList [2,4] -- foreach y in stream
666+-- Stream.yieldM $ delay (x + y)
667+-- :}
668+-- 3 sec
669+-- 4 sec
670+-- 5 sec
671+-- 6 sec
672+-- [3,5,4,6]
668673--
669674-- /Since: 0.3.0 ("Streamly")/
670675--
src/Streamly/Prelude.hs+9−27
@@ -907,33 +907,15 @@ import Streamly.Internal.Data.Stream.IsStream
907907
908908-- $ahead
909909--
910−-- When a stream consumer demands an element from a speculative stream
911−-- constructed as @a \`consM` b \`consM` ... nil@, the action @a@ at the head
912−-- of the stream is executed and the output of the action is supplied to the
913−-- consumer. However, in addition to the action at the head multiple actions
914−-- following it may also be executed concurrently and the results buffered.
915−-- When the next element is demanded it may be served from the buffer and we
916−-- may execute the next action in the sequence to keep the buffer adequately
917−-- filled. Thus, the actions are executed concurrently but results consumed in
918−-- serial order just like serial streams. `consM` can be used to fold an
919−-- infinite lazy container of effects, as the number of concurrent executions
920−-- is limited.
921−--
922−-- Similar to 'consM', the monadic stream generation (e.g. replicateM) and
923−-- transformation operations (e.g. mapM) on speculative streams can execute
924−-- multiple effects concurrently in a speculative manner.
925−--
926−-- How many effects can be executed concurrently and how many results can be
927−-- buffered are controlled by 'maxThreads' and 'maxBuffer' combinators
928−-- respectively. The actual number of concurrent threads is adjusted according
929−-- to the rate at which the consumer is consuming the stream. It may even
930−-- execute actions serially in a single thread if that is enough to match the
931−-- consumer's speed.
932−--
933−-- Speculative streams enforce ordering of the results of actions in the stream
934−-- but the side effects are only partially ordered. Therefore, the semigroup
935−-- operation for speculative streams is not commutative from the pure outputs
936−-- perspective but commutative from side effects perspective.
910+-- Speculative streams evaluate some future actions speculatively and
911+-- concurrently, and keep the results ready for consumption. As in serial
912+-- streams, results are consumed in the same order as the actions in the
913+-- stream.
914+--
915+-- Even though the results of actions are ordered, the side effects are only
916+-- partially ordered. Therefore, the semigroup operation is not commutative
917+-- from the pure outputs perspective but commutative from side effects
918+-- perspective.
937919
938920-- $async
939921--