on 992195e help sign in
streamly/src/Asyncly/Streams.hs
906 lines 32 kB history raw
1{-# LANGUAGE FlexibleContexts #-}
2{-# LANGUAGE FlexibleInstances #-}
3{-# LANGUAGE GeneralizedNewtypeDeriving#-}
4{-# LANGUAGE MultiParamTypeClasses #-}
5{-# LANGUAGE RankNTypes #-}
6{-# LANGUAGE StandaloneDeriving #-}
7{-# LANGUAGE UndecidableInstances #-} -- XXX
9-- |
10-- Module : Asyncly.Streams
11-- Copyright : (c) 2017 Harendra Kumar
12--
13-- License : BSD3
14-- Maintainer : harendra.kumar@gmail.com
15-- Stability : experimental
16-- Portability : GHC
17--
18--
19module Asyncly.Streams
20 (
21 -- * Product Style Composition
22 -- $product
23 Streaming (..)
24 , MonadAsync
26 -- * SVars
27 , SVarSched (..)
28 , SVarTag (..)
29 , SVarStyle (..)
30 , SVar
31 , newEmptySVar
33 -- * Stream Styles
34 , StreamT
35 , InterleavedT
36 , AsyncT
37 , ParallelT
38 , ZipStream
39 , ZipAsync
41 -- * Type Adapters
42 , serially
43 , interleaving
44 , asyncly
45 , parallely
46 , zipping
47 , zippingAsync
48 , adapt
50 -- * Construction
51 , streamBuild
52 , fromCallback
53 , fromSVar
55 -- * Elimination
56 , cons
57 , nil
58 , streamFold
59 , runStreaming
60 , toSVar
62 -- * Running Streams
63 , runStreamT
64 , runInterleavedT
65 , runAsyncT
66 , runParallelT
67 , runZipStream
68 , runZipAsync
70 -- * Transformation
71 , async
73 -- * Zipping
74 , zipWith
75 , zipAsyncWith
77 -- * Sum Style Composition
78 , (<=>)
79 , (<|)
81 -- * Fold Utilities
82 -- $foldutils
83 , foldWith
84 , foldMapWith
85 , forEachWith
86 )
87where
89import Control.Applicative (Alternative (..), liftA2)
90import Control.Monad (MonadPlus(..), ap, liftM)
91import Control.Monad.Base (MonadBase (..))
92import Control.Monad.Catch (MonadThrow)
93import Control.Monad.Error.Class (MonadError(..))
94import Control.Monad.IO.Class (MonadIO(..))
95import Control.Monad.Reader.Class (MonadReader(..))
96import Control.Monad.State.Class (MonadState(..))
97import Control.Monad.Trans.Class (MonadTrans)
98import Data.Semigroup (Semigroup(..))
99import Prelude hiding (drop, take, zipWith)
100import Asyncly.Core
102-- $product
103--
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.
110--
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.
120--
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.
128--
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.
135--
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------------------------------------------------------------------------------
145-- Types that can behave as a Stream
146------------------------------------------------------------------------------
148-- | Class of types that can represent a stream of elements of some type 'a' in
149-- some monad 'm'.
150class Streaming t where
151 toStream :: t m a -> Stream m a
152 fromStream :: Stream m a -> t m a
154------------------------------------------------------------------------------
155-- StreamT iterates serially in the Monad and Applicative compositions
156------------------------------------------------------------------------------
158-- | Note that 'StreamT' style composition works well operationally for
159-- infinite streams. However if the second stream is infinite we will never
160-- come back to the second iteration of the first stream.
162newtype StreamT m a = StreamT {getStreamT :: Stream m a}
163 deriving (Semigroup, Monoid, MonadTrans, MonadIO, MonadThrow)
165deriving instance MonadAsync m => Alternative (StreamT m)
166deriving instance MonadAsync m => MonadPlus (StreamT m)
167deriving instance (MonadBase b m, Monad m) => MonadBase b (StreamT m)
168deriving instance MonadError e m => MonadError e (StreamT m)
169deriving instance MonadReader r m => MonadReader r (StreamT m)
170deriving instance MonadState s m => MonadState s (StreamT m)
172instance Streaming StreamT where
173 toStream = getStreamT
174 fromStream = StreamT
176-- XXX The Functor/Applicative/Num instances for all the types are exactly the
177-- same, how can we reduce this boilerplate (use TH)? We cannot derive them
178-- from a single base type because they depend on the Monad instance which is
179-- different for each type.
181------------------------------------------------------------------------------
182-- Monad
183------------------------------------------------------------------------------
185-- | Execute a monadic action sequentially for each element in the 'AsyncT'
186-- stream, i.e. an iteration finishes completely before the next one starts.
187instance Monad m => Monad (StreamT m) where
188 return = pure
189 (StreamT (Stream m)) >>= f = StreamT $ Stream $ \_ stp yld ->
190 let run x = (runStream x) Nothing stp yld
191 yield a Nothing = run $ getStreamT (f a)
192 yield a (Just r) = run $ getStreamT (f a)
193 <> getStreamT (StreamT r >>= f)
194 in m Nothing stp yield
196------------------------------------------------------------------------------
197-- Applicative
198------------------------------------------------------------------------------
200instance Monad m => Applicative (StreamT m) where
201 pure a = StreamT $ scons a Nothing
202 (<*>) = ap
204------------------------------------------------------------------------------
205-- Functor
206------------------------------------------------------------------------------
208instance Monad m => Functor (StreamT m) where
209 fmap = liftM
211------------------------------------------------------------------------------
212-- Num
213------------------------------------------------------------------------------
215instance (Monad m, Num a) => Num (StreamT m a) where
216 fromInteger n = pure (fromInteger n)
218 negate = fmap negate
219 abs = fmap abs
220 signum = fmap signum
222 (+) = liftA2 (+)
223 (*) = liftA2 (*)
224 (-) = liftA2 (-)
226instance (Monad m, Fractional a) => Fractional (StreamT m a) where
227 fromRational n = pure (fromRational n)
229 recip = fmap recip
231 (/) = liftA2 (/)
233instance (Monad m, Floating a) => Floating (StreamT m a) where
234 pi = pure pi
236 exp = fmap exp
237 sqrt = fmap sqrt
238 log = fmap log
239 sin = fmap sin
240 tan = fmap tan
241 cos = fmap cos
242 asin = fmap asin
243 atan = fmap atan
244 acos = fmap acos
245 sinh = fmap sinh
246 tanh = fmap tanh
247 cosh = fmap cosh
248 asinh = fmap asinh
249 atanh = fmap atanh
250 acosh = fmap acosh
252 (**) = liftA2 (**)
253 logBase = liftA2 logBase
255------------------------------------------------------------------------------
256-- InterleavedT interleaves the iterations in the Monad and Applicative
257-- compositions.
258------------------------------------------------------------------------------
260-- | Note that 'InterleavedT' style composition cannot work well operationally
261-- on infinite streams. It will keep accumulating the elements of the stream
262-- resulting in continuous increase in space consumption.
263--
264newtype InterleavedT m a = InterleavedT {getInterleavedT :: Stream m a}
265 deriving (Semigroup, Monoid, MonadTrans, MonadIO, MonadThrow)
267deriving instance MonadAsync m => Alternative (InterleavedT m)
268deriving instance MonadAsync m => MonadPlus (InterleavedT m)
269deriving instance (MonadBase b m, Monad m) => MonadBase b (InterleavedT m)
270deriving instance MonadError e m => MonadError e (InterleavedT m)
271deriving instance MonadReader r m => MonadReader r (InterleavedT m)
272deriving instance MonadState s m => MonadState s (InterleavedT m)
274instance Streaming InterleavedT where
275 toStream = getInterleavedT
276 fromStream = InterleavedT
278-- | Execute a monadic action for each element in the stream, in a fairly
279-- interleaved manner i.e. iterations yield alternately.
280instance Monad m => Monad (InterleavedT m) where
281 return = pure
282 (InterleavedT (Stream m)) >>= f = InterleavedT $ Stream $ \_ stp yld ->
283 let run x = (runStream x) Nothing stp yld
284 yield a Nothing = run $ getInterleavedT (f a)
285 yield a (Just r) = run $ getInterleavedT (f a)
286 `interleave`
287 getInterleavedT (InterleavedT r >>= f)
288 in m Nothing stp yield
290------------------------------------------------------------------------------
291-- Applicative
292------------------------------------------------------------------------------
294instance Monad m => Applicative (InterleavedT m) where
295 pure a = InterleavedT $ scons a Nothing
296 (<*>) = ap
298------------------------------------------------------------------------------
299-- Functor
300------------------------------------------------------------------------------
302instance Monad m => Functor (InterleavedT m) where
303 fmap = liftM
305------------------------------------------------------------------------------
306-- Num
307------------------------------------------------------------------------------
309instance (Monad m, Num a) => Num (InterleavedT m a) where
310 fromInteger n = pure (fromInteger n)
312 negate = fmap negate
313 abs = fmap abs
314 signum = fmap signum
316 (+) = liftA2 (+)
317 (*) = liftA2 (*)
318 (-) = liftA2 (-)
320instance (Monad m, Fractional a) => Fractional (InterleavedT m a) where
321 fromRational n = pure (fromRational n)
323 recip = fmap recip
325 (/) = liftA2 (/)
327instance (Monad m, Floating a) => Floating (InterleavedT m a) where
328 pi = pure pi
330 exp = fmap exp
331 sqrt = fmap sqrt
332 log = fmap log
333 sin = fmap sin
334 tan = fmap tan
335 cos = fmap cos
336 asin = fmap asin
337 atan = fmap atan
338 acos = fmap acos
339 sinh = fmap sinh
340 tanh = fmap tanh
341 cosh = fmap cosh
342 asinh = fmap asinh
343 atanh = fmap atanh
344 acosh = fmap acosh
346 (**) = liftA2 (**)
347 logBase = liftA2 logBase
349------------------------------------------------------------------------------
350-- AsyncT runs the iterations asynchronously in the Monad and Applicative
351-- compositions. More iterations are started in parallel on demand. It can work
352-- with infinite streams.
353------------------------------------------------------------------------------
355-- | Just like 'StreamT', 'AsyncT' style composition works well operationally
356-- for infinite streams. However, if the second stream is infinite we will
357-- never be able to finish the first stream.
358--
359-- Note that 'fmap' on 'AsyncT' would map on multiple elements concurrently.
361newtype AsyncT m a = AsyncT {getAsyncT :: Stream m a}
362 deriving (Semigroup, Monoid, MonadTrans)
364deriving instance MonadAsync m => Alternative (AsyncT m)
365deriving instance MonadAsync m => MonadPlus (AsyncT m)
366deriving instance MonadAsync m => MonadIO (AsyncT m)
367deriving instance MonadAsync m => MonadThrow (AsyncT m)
368deriving instance (MonadBase b m, MonadAsync m) => MonadBase b (AsyncT m)
369deriving instance (MonadError e m, MonadAsync m) => MonadError e (AsyncT m)
370deriving instance (MonadReader r m, MonadAsync m) => MonadReader r (AsyncT m)
371deriving instance (MonadState s m, MonadAsync m) => MonadState s (AsyncT m)
373instance Streaming AsyncT where
374 toStream = getAsyncT
375 fromStream = AsyncT
377{-# INLINE parbind #-}
378parbind
379 :: (forall c. Stream m c -> Stream m c -> Stream m c)
380 -> Stream m a
381 -> (a -> Stream m b)
382 -> Stream m b
383parbind par m f = go m
384 where
385 go (Stream g) =
386 Stream $ \ctx stp yld ->
387 let run x = (runStream x) ctx stp yld
388 yield a Nothing = run $ f a
389 yield a (Just r) = run $ f a `par` (go r)
390 in g Nothing stp yield
392-- | Execute a monadic action for each element in the stream, running
393-- iterations in parallel, but giving preference to iterations started
394-- earlier.
395instance MonadAsync m => Monad (AsyncT m) where
396 return = pure
397 (AsyncT m) >>= f = AsyncT $ parbind par m g
398 where g x = getAsyncT (f x)
399 par = joinStreamVar2 (SVarStyle Conjunction LIFO)
401------------------------------------------------------------------------------
402-- Applicative
403------------------------------------------------------------------------------
405instance MonadAsync m => Applicative (AsyncT m) where
406 pure a = AsyncT $ scons a Nothing
407 (<*>) = ap
409------------------------------------------------------------------------------
410-- Functor
411------------------------------------------------------------------------------
413instance MonadAsync m => Functor (AsyncT m) where
414 fmap = liftM
416------------------------------------------------------------------------------
417-- Num
418------------------------------------------------------------------------------
420instance (MonadAsync m, Num a) => Num (AsyncT m a) where
421 fromInteger n = pure (fromInteger n)
423 negate = fmap negate
424 abs = fmap abs
425 signum = fmap signum
427 (+) = liftA2 (+)
428 (*) = liftA2 (*)
429 (-) = liftA2 (-)
431instance (MonadAsync m, Fractional a) => Fractional (AsyncT m a) where
432 fromRational n = pure (fromRational n)
434 recip = fmap recip
436 (/) = liftA2 (/)
438instance (MonadAsync m, Floating a) => Floating (AsyncT m a) where
439 pi = pure pi
441 exp = fmap exp
442 sqrt = fmap sqrt
443 log = fmap log
444 sin = fmap sin
445 tan = fmap tan
446 cos = fmap cos
447 asin = fmap asin
448 atan = fmap atan
449 acos = fmap acos
450 sinh = fmap sinh
451 tanh = fmap tanh
452 cosh = fmap cosh
453 asinh = fmap asinh
454 atanh = fmap atanh
455 acosh = fmap acosh
457 (**) = liftA2 (**)
458 logBase = liftA2 logBase
460------------------------------------------------------------------------------
461-- ParallelT runs all iterations in parallel in the Monad and Applicative
462-- compositions. Iterations are scheduled in a round-robin fashion.
463------------------------------------------------------------------------------
465-- | Note that, just like 'InterleavedT', 'ParallelT' style composition cannot
466-- work well operationally on infinite streams. It will keep accumulating the
467-- elements of the stream resulting in continuous increase in space
468-- consumption.
469--
470-- Note that 'fmap' on 'ParallelT' would map on both streams concurrently.
471--
472newtype ParallelT m a = ParallelT {getParallelT :: Stream m a}
473 deriving (Semigroup, Monoid, MonadTrans)
475deriving instance MonadAsync m => Alternative (ParallelT m)
476deriving instance MonadAsync m => MonadPlus (ParallelT m)
477deriving instance MonadAsync m => MonadIO (ParallelT m)
478deriving instance MonadAsync m => MonadThrow (ParallelT m)
479deriving instance (MonadBase b m, MonadAsync m) => MonadBase b (ParallelT m)
480deriving instance (MonadError e m, MonadAsync m) => MonadError e (ParallelT m)
481deriving instance (MonadReader r m, MonadAsync m) => MonadReader r (ParallelT m)
482deriving instance (MonadState s m, MonadAsync m) => MonadState s (ParallelT m)
484instance Streaming ParallelT where
485 toStream = getParallelT
486 fromStream = ParallelT
488-- | Execute a monadic action for each element in the stream, running
489-- iterations in a fairly parallel manner, i.e. all iterations are equally
490-- likely to run.
491instance MonadAsync m => Monad (ParallelT m) where
492 return = pure
493 (ParallelT m) >>= f = ParallelT $ parbind par m g
494 where g x = getParallelT (f x)
495 par = joinStreamVar2 (SVarStyle Conjunction FIFO)
497------------------------------------------------------------------------------
498-- Applicative
499------------------------------------------------------------------------------
501instance MonadAsync m => Applicative (ParallelT m) where
502 pure a = ParallelT $ scons a Nothing
503 (<*>) = ap
505------------------------------------------------------------------------------
506-- Functor
507------------------------------------------------------------------------------
509instance MonadAsync m => Functor (ParallelT m) where
510 fmap = liftM
512------------------------------------------------------------------------------
513-- Num
514------------------------------------------------------------------------------
516instance (MonadAsync m, Num a) => Num (ParallelT m a) where
517 fromInteger n = pure (fromInteger n)
519 negate = fmap negate
520 abs = fmap abs
521 signum = fmap signum
523 (+) = liftA2 (+)
524 (*) = liftA2 (*)
525 (-) = liftA2 (-)
527instance (MonadAsync m, Fractional a) => Fractional (ParallelT m a) where
528 fromRational n = pure (fromRational n)
530 recip = fmap recip
532 (/) = liftA2 (/)
534instance (MonadAsync m, Floating a) => Floating (ParallelT m a) where
535 pi = pure pi
537 exp = fmap exp
538 sqrt = fmap sqrt
539 log = fmap log
540 sin = fmap sin
541 tan = fmap tan
542 cos = fmap cos
543 asin = fmap asin
544 atan = fmap atan
545 acos = fmap acos
546 sinh = fmap sinh
547 tanh = fmap tanh
548 cosh = fmap cosh
549 asinh = fmap asinh
550 atanh = fmap atanh
551 acosh = fmap acosh
553 (**) = liftA2 (**)
554 logBase = liftA2 logBase
556------------------------------------------------------------------------------
557-- Serially Zipping Streams
558------------------------------------------------------------------------------
560-- | Zip two streams serially using a pure zipping function.
561zipWith :: Streaming t => (a -> b -> c) -> t m a -> t m b -> t m c
562zipWith f m1 m2 = fromStream $ go (toStream m1) (toStream m2)
563 where
564 go mx my = Stream $ \_ stp yld -> do
565 let merge a ra =
566 let yield2 b Nothing = yld (f a b) Nothing
567 yield2 b (Just rb) = yld (f a b) (Just (go ra rb))
568 in (runStream my) Nothing stp yield2
569 let yield1 a Nothing = merge a snil
570 yield1 a (Just ra) = merge a ra
571 (runStream mx) Nothing stp yield1
573-- | 'ZipStream' zips serially i.e. it produces one element from each stream in
574-- a serial manner and then zips the two elements.
575newtype ZipStream m a = ZipStream {getZipStream :: Stream m a}
576 deriving (Semigroup, Monoid)
578deriving instance MonadAsync m => Alternative (ZipStream m)
580instance Monad m => Functor (ZipStream m) where
581 fmap f (ZipStream (Stream m)) = ZipStream $ Stream $ \_ stp yld ->
582 let yield a Nothing = yld (f a) Nothing
583 yield a (Just r) = yld (f a)
584 (Just (getZipStream (fmap f (ZipStream r))))
585 in m Nothing stp yield
587instance Monad m => Applicative (ZipStream m) where
588 pure a = ZipStream $ scons a Nothing
589 (<*>) = zipWith id
591instance Streaming ZipStream where
592 toStream = getZipStream
593 fromStream = ZipStream
595instance (Monad m, Num a) => Num (ZipStream m a) where
596 fromInteger n = pure (fromInteger n)
598 negate = fmap negate
599 abs = fmap abs
600 signum = fmap signum
602 (+) = liftA2 (+)
603 (*) = liftA2 (*)
604 (-) = liftA2 (-)
606instance (Monad m, Fractional a) => Fractional (ZipStream m a) where
607 fromRational n = pure (fromRational n)
609 recip = fmap recip
611 (/) = liftA2 (/)
613instance (Monad m, Floating a) => Floating (ZipStream m a) where
614 pi = pure pi
616 exp = fmap exp
617 sqrt = fmap sqrt
618 log = fmap log
619 sin = fmap sin
620 tan = fmap tan
621 cos = fmap cos
622 asin = fmap asin
623 atan = fmap atan
624 acos = fmap acos
625 sinh = fmap sinh
626 tanh = fmap tanh
627 cosh = fmap cosh
628 asinh = fmap asinh
629 atanh = fmap atanh
630 acosh = fmap acosh
632 (**) = liftA2 (**)
633 logBase = liftA2 logBase
635------------------------------------------------------------------------------
636-- Parallely Zipping Streams
637------------------------------------------------------------------------------
639-- | Zip two streams asyncly (i.e. both the elements being zipped are generated
640-- concurrently) using a pure zipping function.
641zipAsyncWith :: (Streaming t, MonadAsync m)
642 => (a -> b -> c) -> t m a -> t m b -> t m c
643zipAsyncWith f m1 m2 = fromStream $ Stream $ \_ stp yld -> do
644 ma <- async m1
645 mb <- async m2
646 (runStream (toStream (zipWith f ma mb))) Nothing stp yld
648-- | 'ZipAsync' zips in parallel, it produces one element from each stream
649-- concurrently and then zips the two.
650newtype ZipAsync m a = ZipAsync {getZipAsync :: Stream m a}
651 deriving (Semigroup, Monoid)
653deriving instance MonadAsync m => Alternative (ZipAsync m)
655instance Monad m => Functor (ZipAsync m) where
656 fmap f (ZipAsync (Stream m)) = ZipAsync $ Stream $ \_ stp yld ->
657 let yield a Nothing = yld (f a) Nothing
658 yield a (Just r) = yld (f a)
659 (Just (getZipAsync (fmap f (ZipAsync r))))
660 in m Nothing stp yield
662instance MonadAsync m => Applicative (ZipAsync m) where
663 pure a = ZipAsync $ scons a Nothing
664 (<*>) = zipAsyncWith id
666instance Streaming ZipAsync where
667 toStream = getZipAsync
668 fromStream = ZipAsync
670instance (MonadAsync m, Num a) => Num (ZipAsync m a) where
671 fromInteger n = pure (fromInteger n)
673 negate = fmap negate
674 abs = fmap abs
675 signum = fmap signum
677 (+) = liftA2 (+)
678 (*) = liftA2 (*)
679 (-) = liftA2 (-)
681instance (MonadAsync m, Fractional a) => Fractional (ZipAsync m a) where
682 fromRational n = pure (fromRational n)
684 recip = fmap recip
686 (/) = liftA2 (/)
688instance (MonadAsync m, Floating a) => Floating (ZipAsync m a) where
689 pi = pure pi
691 exp = fmap exp
692 sqrt = fmap sqrt
693 log = fmap log
694 sin = fmap sin
695 tan = fmap tan
696 cos = fmap cos
697 asin = fmap asin
698 atan = fmap atan
699 acos = fmap acos
700 sinh = fmap sinh
701 tanh = fmap tanh
702 cosh = fmap cosh
703 asinh = fmap asinh
704 atanh = fmap atanh
705 acosh = fmap acosh
707 (**) = liftA2 (**)
708 logBase = liftA2 logBase
710-------------------------------------------------------------------------------
711-- Type adapting combinators
712-------------------------------------------------------------------------------
714-- | Adapt one streaming type to another.
715adapt :: (Streaming t1, Streaming t2) => t1 m a -> t2 m a
716adapt = fromStream . toStream
718-- | Interpret an ambiguously typed stream as 'StreamT'.
719serially :: StreamT m a -> StreamT m a
720serially x = x
722-- | Interpret an ambiguously typed stream as 'InterleavedT'.
723interleaving :: InterleavedT m a -> InterleavedT m a
724interleaving x = x
726-- | Interpret an ambiguously typed stream as 'AsyncT'.
727asyncly :: AsyncT m a -> AsyncT m a
728asyncly x = x
730-- | Interpret an ambiguously typed stream as 'ParallelT'.
731parallely :: ParallelT m a -> ParallelT m a
732parallely x = x
734-- | Interpret an ambiguously typed stream as 'ZipStream'.
735zipping :: ZipStream m a -> ZipStream m a
736zipping x = x
738-- | Interpret an ambiguously typed stream as 'ZipAsync'.
739zippingAsync :: ZipAsync m a -> ZipAsync m a
740zippingAsync x = x
742------------------------------------------------------------------------------
743-- Constructing a stream
744------------------------------------------------------------------------------
746cons :: (Streaming t) => a -> t m a -> t m a
747cons a r = fromStream $ scons a (Just (toStream r))
749nil :: Streaming t => t m a
750nil = fromStream $ snil
752-- | Build a stream from its church encoding. The function passed maps
753-- directly to the underlying representation of the stream type. The second
754-- parameter to the function is the "yield" function yielding a value and the
755-- remaining stream if any otherwise 'Nothing'. The third parameter is to
756-- represent an "empty" stream.
757streamBuild :: Streaming t
758 => (forall r. Maybe (SVar m a)
759 -> (a -> Maybe (t m a) -> m r)
760 -> m r
761 -> m r)
762 -> t m a
763streamBuild k = fromStream $ Stream $ \sv stp yld ->
764 let yield a Nothing = yld a Nothing
765 yield a (Just r) = yld a (Just (toStream r))
766 in k sv yield stp
768-- | Build a singleton stream from a callback function.
769fromCallback :: (Streaming t) => (forall r. (a -> m r) -> m r) -> t m a
770fromCallback k = fromStream $ Stream $ \_ _ yld -> k (\a -> yld a Nothing)
772-- | Read an SVar to get a stream.
773fromSVar :: (MonadAsync m, Streaming t) => SVar m a -> t m a
774fromSVar sv = fromStream $ fromStreamVar sv
776------------------------------------------------------------------------------
777-- Destroying a stream
778------------------------------------------------------------------------------
780-- | Fold a stream using its church encoding. The second argument is the "step"
781-- function consuming an element and the remaining stream, if any. The third
782-- argument is for consuming an "empty" stream that yields nothing.
783streamFold :: Streaming t
784 => Maybe (SVar m a) -> (a -> Maybe (t m a) -> m r) -> m r -> t m a -> m r
785streamFold sv step blank m =
786 let yield a Nothing = step a Nothing
787 yield a (Just x) = step a (Just (fromStream x))
788 in (runStream (toStream m)) sv blank yield
790-- | Run a streaming composition, discard the results.
791runStreaming :: (Monad m, Streaming t) => t m a -> m ()
792runStreaming m = go (toStream m)
793 where
794 go m1 =
795 let stop = return ()
796 yield _ Nothing = stop
797 yield _ (Just x) = go x
798 in (runStream m1) Nothing stop yield
800-- | Write a stream to an 'SVar' in a non-blocking manner. The stream can then
801-- be read back from the SVar using 'fromSVar'.
802toSVar :: (Streaming t, MonadAsync m) => SVar m a -> t m a -> m ()
803toSVar sv m = toStreamVar sv (toStream m)
805-------------------------------------------------------------------------------
806-- Running Streams, convenience functions specialized to types
807-------------------------------------------------------------------------------
809-- | Run a 'StreamT' computation. Same as @runStreaming . serially@.
810runStreamT :: Monad m => StreamT m a -> m ()
811runStreamT = runStreaming
813-- | Run an 'InterleavedT' computation. Same as @runStreaming . interleaving@.
814runInterleavedT :: Monad m => InterleavedT m a -> m ()
815runInterleavedT = runStreaming
817-- | Run an 'AsyncT' computation. Same as @runStreaming . asyncly@.
818runAsyncT :: Monad m => AsyncT m a -> m ()
819runAsyncT = runStreaming
821-- | Run a 'ParallelT' computation. Same as @runStreaming . parallely@.
822runParallelT :: Monad m => ParallelT m a -> m ()
823runParallelT = runStreaming
825-- | Run a 'ZipStream' computation. Same as @runStreaming . zipping@.
826runZipStream :: Monad m => ZipStream m a -> m ()
827runZipStream = runStreaming
829-- | Run a 'ZipAsync' computation. Same as @runStreaming . zippingAsync@.
830runZipAsync :: Monad m => ZipAsync m a -> m ()
831runZipAsync = runStreaming
833------------------------------------------------------------------------------
834-- Transformation
835------------------------------------------------------------------------------
837-- XXX Get rid of this?
838-- | Make a stream asynchronous, triggers the computation and returns a stream
839-- in the underlying monad representing the output generated by the original
840-- computation. The returned action is exhaustible and must be drained once. If
841-- not drained fully we may have a thread blocked forever and once exhausted it
842-- will always return 'empty'.
844async :: (Streaming t, MonadAsync m) => t m a -> m (t m a)
845async m = do
846 sv <- newStreamVar1 (SVarStyle Disjunction LIFO) (toStream m)
847 return $ fromSVar sv
849------------------------------------------------------------------------------
850-- Sum Style Composition
851------------------------------------------------------------------------------
853infixr 5 <=>
855-- | Sequential interleaved composition, in contrast to '<>' this operator
856-- fairly interleaves the two streams instead of appending them; yielding one
857-- element from each stream alternately. Unlike '<>' it cannot be used to fold
858-- an infinite container of streams.
859{-# INLINE (<=>) #-}
860(<=>) :: Streaming t => t m a -> t m a -> t m a
861m1 <=> m2 = fromStream $ interleave (toStream m1) (toStream m2)
863-- | Parallel interleaved composition, in contrast to '<|>' this operator
864-- "merges" streams in a left biased manner rather than fairly interleaving
865-- them. It keeps yielding from the stream on the left as long as it can. If
866-- the left stream blocks or cannot keep up with the pace of the consumer it
867-- can yield from the stream on the right in parallel. Unlike '<|>' it can be
868-- used to fold infinite containers of streams.
869{-# INLINE (<|) #-}
870(<|) :: (Streaming t, MonadAsync m) => t m a -> t m a -> t m a
871m1 <| m2 = fromStream $ parLeft (toStream m1) (toStream m2)
873------------------------------------------------------------------------------
874-- Fold Utilities
875------------------------------------------------------------------------------
877-- $foldutils
878-- These utilities are designed to pass the first argument as one of the sum
879-- style composition operators (i.e. '<>', '<=>', '<|', '<|>') to conveniently
880-- fold a container using any style of stream composition.
882-- | Like the 'Prelude' 'fold' but allows you to specify a binary sum style
883-- stream composition operator to fold a container of streams.
884--
885-- @foldWith (<>) $ map return [1..3]@
886{-# INLINABLE foldWith #-}
887foldWith :: (Streaming t, Foldable f)
888 => (t m a -> t m a -> t m a) -> f (t m a) -> t m a
889foldWith f = foldr f nil
891-- | Like 'foldMap' but allows you to specify a binary sum style composition
892-- operator to fold a container of streams. Maps a monadic streaming action on
893-- the container before folding it.
894--
895-- @foldMapWith (<>) return [1..3]@
896{-# INLINABLE foldMapWith #-}
897foldMapWith :: (Streaming t, Foldable f)
898 => (t m b -> t m b -> t m b) -> (a -> t m b) -> f a -> t m b
899foldMapWith f g = foldr (f . g) nil
901-- | Like 'foldMapWith' but with the last two arguments reversed i.e. the
902-- monadic streaming function is the last argument.
903{-# INLINABLE forEachWith #-}
904forEachWith :: (Streaming t, Foldable f)
905 => (t m b -> t m b -> t m b) -> f a -> (a -> t m b) -> t m b
906forEachWith f xs g = foldr (f . g) nil xs