@@ -18,8 +18,6 @@
19module Streamly.Streams
19module Streamly.Streams
21− -- * Product Style Composition
23 Streaming (..)
21 Streaming (..)
24 , MonadAsync
22 , MonadAsync
@@ -99,48 +97,6 @@ import Data.Semigroup (Semigroup(..))
99import Prelude hiding (drop, take, zipWith)
97import Prelude hiding (drop, take, zipWith)
100import Streamly.Core
98import Streamly.Core
104−-- Different styles of streams represented by different types dictate the
105−-- manner in which a stream is processed in monadic or applicative composition.
106−-- Each type differs in the processing order of the elements or processing
107−-- parallelism. The types have the same underlying representation and
108−-- therefore can be converted back and forth easily to switch the composition
109−-- style at any point.
111−-- 'StreamT' and 'InterleavedT' process the streams serially but differ in the
112−-- order in which the elements of the streams are processed. 'StreamT' goes
113−-- depth first that is it combine one element of the first stream to every
114−-- element of the second stream before it comes back to process the second
115−-- element of the first stream. 'InterleavedT' takes turns when processing
116−-- elements from each stream and therefore all iterations finish at the same
117−-- time rather than one iteration at a time as in the case of 'StreamT'.
118−-- Depending on the cache behavior or IO behavior 'InterleavedT' might be
119−-- slightly more efficient than 'StreamT' or vice-versa.
121−-- 'AsyncT' and 'ParallelT' can process the individual elements of the streams
122−-- in parallel. 'AsyncT' is the parallel version of 'StreamT', it follows the
123−-- order of 'StreamT', processing multiple elements of a stream concurrently.
124−-- 'ParallelT' follows the order of 'InterleavedT', processing and interleaving
125−-- both streams concurrently. Also, note that 'fmap' on these streams would
126−-- also work in a concurrent fashion i.e. multiple elements in a stream or
127−-- multiple streams can be mapped concurrently.
129−-- Zipping types have a different style of composition altogether, they zip the
130−-- streams rather than multiplying them. These types provide only Applicative
131−-- composition and no Monad instances. 'ZipStream' zips serially i.e. it
132−-- produces one element from each stream in a serial manner and then zips the
133−-- two items. 'ZipAsync' on the other hand zips in parallel, it produces one
134−-- element from each stream concurrently and then zips the two.
136−-- It may help develop a better understanding if we think in terms of stream
137−-- generation (production) side parallelism versus stream processing
138−-- (consumption) side parallelism. The sum style operators (e.g. '<|' or '<|>')
139−-- generate streams in parallel and then combine the results into a unified
140−-- stream. On the other hand the product style composition (e.g. 'AsyncT' or
141−-- 'ParallelT' or 'ZipAsync') dictate how the elements of a stream are
142−-- processed when it is consumed.
144------------------------------------------------------------------------------
100------------------------------------------------------------------------------
145-- Types that can behave as a Stream
101-- Types that can behave as a Stream
146------------------------------------------------------------------------------
102------------------------------------------------------------------------------
@@ -231,12 +187,19 @@ async m = do
231 return $ fromSVar sv
187 return $ fromSVar sv
233------------------------------------------------------------------------------
189------------------------------------------------------------------------------
234−-- StreamT iterates serially in the Monad and Applicative compositions
190+-- StreamT
235------------------------------------------------------------------------------
191------------------------------------------------------------------------------
193+-- | The 'Monad' instance of 'StreamT' combines two streams serially in the
194+-- most straightforward manner, just like the nested 'for' loops in imperative
195+-- paradigm. It moves to the next element in the first stream only after the
196+-- first element has been combined with every element in the second stream. In
197+-- other words, 'StreamT' nests loops in a depth first manner.
237−-- | Note that 'StreamT' style composition works well operationally for
199+-- Note that 'StreamT' style composition works well operationally even when the
238−-- infinite streams. However if the second stream is infinite we will never
200+-- streams being composed are infinite. However, if the second stream is
239−-- come back to the second iteration of the first stream.
201+-- infinite we will never come back to the second iteration of the first
241newtype StreamT m a = StreamT {getStreamT :: Stream m a}
204newtype StreamT m a = StreamT {getStreamT :: Stream m a}
242 deriving (Semigroup, Monoid, MonadTrans, MonadIO, MonadThrow)
205 deriving (Semigroup, Monoid, MonadTrans, MonadIO, MonadThrow)
@@ -261,8 +224,6 @@ instance Streaming StreamT where
262------------------------------------------------------------------------------
225------------------------------------------------------------------------------
264−-- | Execute a monadic action sequentially for each element in the 'AsyncT'
265−-- stream, i.e. an iteration finishes completely before the next one starts.
266instance Monad m => Monad (StreamT m) where
227instance Monad m => Monad (StreamT m) where
267 return = pure
228 return = pure
268 (StreamT (Stream m)) >>= f = StreamT $ Stream $ \_ stp yld ->
229 (StreamT (Stream m)) >>= f = StreamT $ Stream $ \_ stp yld ->
@@ -336,13 +297,16 @@ instance (Monad m, Floating a) => Floating (StreamT m a) where
336 logBase = liftA2 logBase
297 logBase = liftA2 logBase
338------------------------------------------------------------------------------
299------------------------------------------------------------------------------
339−-- InterleavedT interleaves the iterations in the Monad and Applicative
300+-- InterleavedT
341------------------------------------------------------------------------------
301------------------------------------------------------------------------------
303+-- | The 'Monad' instance of 'InterleavedT' fairly interleaves the iterations
304+-- of the inner and the outer loop, nesting loops in a breadth first manner.
343−-- | Note that 'InterleavedT' style composition cannot work well operationally
306+-- Note that 'InterleavedT' style composition cannot work well operationally on
344−-- on infinite streams. It will keep accumulating the elements of the stream
307+-- infinite streams. Since the next iteration of the outer loop is started even
308+-- before the first one has finsihed, it will keep accumulating space resulting
345−-- resulting in continuous increase in space consumption.
309+-- in a continuous increase in space consumption.
347newtype InterleavedT m a = InterleavedT {getInterleavedT :: Stream m a}
311newtype InterleavedT m a = InterleavedT {getInterleavedT :: Stream m a}
348 deriving (Semigroup, Monoid, MonadTrans, MonadIO, MonadThrow)
312 deriving (Semigroup, Monoid, MonadTrans, MonadIO, MonadThrow)
@@ -358,8 +322,6 @@ instance Streaming InterleavedT where
358 toStream = getInterleavedT
322 toStream = getInterleavedT
359 fromStream = InterleavedT
323 fromStream = InterleavedT
361−-- | Execute a monadic action for each element in the stream, in a fairly
362−-- interleaved manner i.e. iterations yield alternately.
363instance Monad m => Monad (InterleavedT m) where
325instance Monad m => Monad (InterleavedT m) where
364 return = pure
326 return = pure
365 (InterleavedT (Stream m)) >>= f = InterleavedT $ Stream $ \_ stp yld ->
327 (InterleavedT (Stream m)) >>= f = InterleavedT $ Stream $ \_ stp yld ->
@@ -434,16 +396,18 @@ instance (Monad m, Floating a) => Floating (InterleavedT m a) where
434 logBase = liftA2 logBase
396 logBase = liftA2 logBase
436------------------------------------------------------------------------------
398------------------------------------------------------------------------------
437−-- AsyncT runs the iterations asynchronously in the Monad and Applicative
399+-- AsyncT
438−-- compositions. More iterations are started in parallel on demand. It can work
439−-- with infinite streams.
440------------------------------------------------------------------------------
400------------------------------------------------------------------------------
442−-- | Just like 'StreamT', 'AsyncT' style composition works well operationally
402+-- | 'AsyncT' is the concurrent equivalent of 'StreamT'. The type 'AsyncT'
443−-- for infinite streams. However, if the second stream is infinite we will
403+-- follows the same composition scheme as 'StreamT' except that it can run
444−-- never be able to finish the first stream.
404+-- multiple iterations concurrently. More concurrent iterations are started
405+-- only if the previous iterations are not able to produce enough output for
446−-- Note that 'fmap' on 'AsyncT' would map on multiple elements concurrently.
408+-- Just like 'StreamT', 'AsyncT' style composition works well operationally
409+-- for infinite streams. However, if the second stream is infinite we will
410+-- never be able to start the second iteration of the first stream.
448newtype AsyncT m a = AsyncT {getAsyncT :: Stream m a}
412newtype AsyncT m a = AsyncT {getAsyncT :: Stream m a}
449 deriving (Semigroup, Monoid, MonadTrans)
413 deriving (Semigroup, Monoid, MonadTrans)
@@ -476,9 +440,6 @@ parbind par m f = go m
476 yield a (Just r) = run $ f a `par` (go r)
440 yield a (Just r) = run $ f a `par` (go r)
477 in g Nothing stp yield
441 in g Nothing stp yield
479−-- | Execute a monadic action for each element in the stream, running
480−-- iterations in parallel, but giving preference to iterations started
482instance MonadAsync m => Monad (AsyncT m) where
443instance MonadAsync m => Monad (AsyncT m) where
483 return = pure
444 return = pure
484 (AsyncT m) >>= f = AsyncT $ parbind par m g
445 (AsyncT m) >>= f = AsyncT $ parbind par m g
@@ -548,17 +509,20 @@ instance (MonadAsync m, Floating a) => Floating (AsyncT m a) where
548 logBase = liftA2 logBase
509 logBase = liftA2 logBase
550------------------------------------------------------------------------------
511------------------------------------------------------------------------------
551−-- ParallelT runs all iterations in parallel in the Monad and Applicative
512+-- ParallelT
552−-- compositions. Iterations are scheduled in a round-robin fashion.
553------------------------------------------------------------------------------
513------------------------------------------------------------------------------
515+-- | 'ParallelT' is the concurrent equivalent of 'InterleavedT'. It follows the
516+-- same composition scheme as 'InterleavedT' i.e. fairly interleaving the inner
517+-- and outer loops in a round robin fashion except that it can run multiple
518+-- iterations concurrently.
555−-- | Note that, just like 'InterleavedT', 'ParallelT' style composition cannot
520+-- Note that, just like 'InterleavedT', 'ParallelT' style composition cannot
556−-- work well operationally on infinite streams. It will keep accumulating the
521+-- work well operationally on infinite streams. Because earlier iterations do
522+-- not finish before the new ones are started, it will keep on accumulating the
557-- elements of the stream resulting in continuous increase in space
523-- elements of the stream resulting in continuous increase in space
558-- consumption.
524-- consumption.
560−-- Note that 'fmap' on 'ParallelT' would map on both streams concurrently.
562newtype ParallelT m a = ParallelT {getParallelT :: Stream m a}
526newtype ParallelT m a = ParallelT {getParallelT :: Stream m a}
563 deriving (Semigroup, Monoid, MonadTrans)
527 deriving (Semigroup, Monoid, MonadTrans)
@@ -575,9 +539,6 @@ instance Streaming ParallelT where
575 toStream = getParallelT
539 toStream = getParallelT
576 fromStream = ParallelT
540 fromStream = ParallelT
578−-- | Execute a monadic action for each element in the stream, running
579−-- iterations in a fairly parallel manner, i.e. all iterations are equally
581instance MonadAsync m => Monad (ParallelT m) where
542instance MonadAsync m => Monad (ParallelT m) where
582 return = pure
543 return = pure
583 (ParallelT m) >>= f = ParallelT $ parbind par m g
544 (ParallelT m) >>= f = ParallelT $ parbind par m g
@@ -870,7 +831,8 @@ infixr 5 <=>
870-- | Sequential interleaved composition, in contrast to '<>' this operator
831-- | Sequential interleaved composition, in contrast to '<>' this operator
871-- fairly interleaves the two streams instead of appending them; yielding one
832-- fairly interleaves the two streams instead of appending them; yielding one
872-- element from each stream alternately. Unlike '<>' it cannot be used to fold
833-- element from each stream alternately. Unlike '<>' it cannot be used to fold
873−-- an infinite container of streams.
834+-- an infinite container of streams. This operator corresponds to the
835+-- 'InterleavedT' type for product style composition.
874{-# INLINE (<=>) #-}
836{-# INLINE (<=>) #-}
875(<=>) :: Streaming t => t m a -> t m a -> t m a
837(<=>) :: Streaming t => t m a -> t m a -> t m a
876m1 <=> m2 = fromStream $ interleave (toStream m1) (toStream m2)
838m1 <=> m2 = fromStream $ interleave (toStream m1) (toStream m2)
@@ -880,7 +842,8 @@ m1 <=> m2 = fromStream $ interleave (toStream m1) (toStream m2)
880-- them. It keeps yielding from the stream on the left as long as it can. If
842-- them. It keeps yielding from the stream on the left as long as it can. If
881-- the left stream blocks or cannot keep up with the pace of the consumer it
843-- the left stream blocks or cannot keep up with the pace of the consumer it
882-- can yield from the stream on the right in parallel. Unlike '<|>' it can be
844-- can yield from the stream on the right in parallel. Unlike '<|>' it can be
883−-- used to fold infinite containers of streams.
845+-- used to fold infinite containers of streams. This operator corresponds to
846+-- the 'AsyncT' type for product style composition.
884{-# INLINE (<|) #-}
847{-# INLINE (<|) #-}
885(<|) :: (Streaming t, MonadAsync m) => t m a -> t m a -> t m a
848(<|) :: (Streaming t, MonadAsync m) => t m a -> t m a -> t m a
886m1 <| m2 = fromStream $ parLeft (toStream m1) (toStream m2)
849m1 <| m2 = fromStream $ parLeft (toStream m1) (toStream m2)