on cf1388b help sign in
streamly/src/Streamly/Streams.hs
1010 lines 32 kB history raw
1{-# LANGUAGE CPP #-}
2{-# LANGUAGE ConstraintKinds #-}
3{-# LANGUAGE FlexibleContexts #-}
4{-# LANGUAGE FlexibleInstances #-}
5{-# LANGUAGE GeneralizedNewtypeDeriving#-}
6{-# LANGUAGE MultiParamTypeClasses #-}
7{-# LANGUAGE RankNTypes #-}
8{-# LANGUAGE StandaloneDeriving #-}
9{-# LANGUAGE UndecidableInstances #-} -- XXX
11-- |
12-- Module : Streamly.Streams
13-- Copyright : (c) 2017 Harendra Kumar
14--
15-- License : BSD3
16-- Maintainer : harendra.kumar@gmail.com
17-- Stability : experimental
18-- Portability : GHC
19--
20--
21module Streamly.Streams
22 (
23 IsStream (..)
24 , Streaming -- deprecated
25 , MonadParallel
26 , S.MonadAsync -- deprecated
28 -- * SVars
29 , SVarSched (..)
30 , SVarTag (..)
31 , SVarStyle (..)
32 , SVar
33 , S.newEmptySVar
35 -- * Construction
36 , nil
37 , cons
38 , (.:)
39 , consM
40 , (|:)
41 , streamBuild
42 , fromCallback
43 , fromSVar
45 -- * Elimination
46 , streamFold
47 , runStream
48 , runStreaming -- deprecated
49 , toSVar
51 -- * Transformation
52 , async
54 -- * Merging Streams
55 , splice
56 , cosplice
57 , coparallel
58 , parallel
59 , (<=>) --deprecated
60 , (<|) --deprecated
62 -- * IO Streams
63 , Stream
64 , Costream
65 , Coparallel
66 , Parallel
67 , ZipStream
68 , ZipParallel
70 -- * Stream Transformers
71 , StreamT
72 , CostreamT
73 , InterleavedT -- deprecated
74 , CoparallelT
75 , AsyncT -- deprecated
76 , ParallelT
77 , ZipStreamM
78 , ZipParallelM
79 , ZipAsync -- deprecated
81 -- * Type Adapters
82 , streamly
83 , serially -- deprecated
84 , costreamly
85 , interleaving -- deprecated
86 , coparallely
87 , asyncly -- deprecated
88 , parallely
89 , zipStreamly
90 , zipping -- deprecated
91 , zipParallely
92 , zippingAsync -- deprecated
93 , adapt
95 -- * Running Streams
96 , runStreamT -- deprecated
97 , runInterleavedT -- deprecated
98 , runAsyncT -- deprecated
99 , runParallelT -- deprecated
100 , runZipStream -- deprecated
101 , runZipAsync -- deprecated
103 -- * Fold Utilities
104 , foldWith
105 , foldMapWith
106 , forEachWith
107 )
108where
110import Control.Monad (ap)
111import Control.Monad.Base (MonadBase (..), liftBaseDefault)
112import Control.Monad.Catch (MonadThrow, throwM)
113-- import Control.Monad.Error.Class (MonadError(..))
114import Control.Monad.IO.Class (MonadIO(..))
115import Control.Monad.Reader.Class (MonadReader(..))
116import Control.Monad.State.Class (MonadState(..))
117import Control.Monad.Trans.Class (MonadTrans (lift))
118import Data.Semigroup (Semigroup(..))
119import Streamly.Core ( MonadParallel
120 , SVar, SVarStyle(..)
121 , SVarTag(..), SVarSched(..))
122import qualified Streamly.Core as S
124------------------------------------------------------------------------------
125-- Types that can behave as a Stream
126------------------------------------------------------------------------------
128-- | Class of types that can represent a stream of elements of some type 'a' in
129-- some monad 'm'.
130--
131-- @since 0.2.0
132class IsStream t where
133 toStream :: t m a -> S.Stream m a
134 fromStream :: S.Stream m a -> t m a
136-- | Same as 'IsStream'.
137--
138-- @since 0.1.0
139{-# DEPRECATED Streaming "Please use IsStream instead." #-}
140type Streaming = IsStream
142------------------------------------------------------------------------------
143-- Constructing a stream
144------------------------------------------------------------------------------
146-- | An empty stream.
147--
148-- @
149-- > toList nil
150-- []
151-- @
152--
153-- @since 0.1.0
154nil :: IsStream t => t m a
155nil = fromStream S.nil
157infixr 5 `consM`
159-- | Constructs a stream by adding a monadic action at the head of an existing
160-- stream. For example:
161--
162-- @
163-- > toList $ getLine \`consM` getLine \`consM` nil
164-- hello
165-- world
166-- ["hello","world"]
167-- @
168--
169-- @since 0.2.0
170consM :: (IsStream t, Monad m) => m a -> t m a -> t m a
171consM m r = fromStream $ S.consM m (toStream r)
173infixr 5 |:
175-- | Operator equivalent of 'consM'.
176--
177-- @
178-- > toList $ getLine |: getLine |: nil
179-- hello
180-- world
181-- ["hello","world"]
182-- @
183--
184-- @since 0.2.0
185(|:) :: (IsStream t, Monad m) => m a -> t m a -> t m a
186(|:) = consM
188infixr 5 `cons`
190-- | Construct a stream by adding a pure value at the head of an existing
191-- stream. Same as @consM . return@. For example:
192--
193-- @
194-- > toList $ 1 \`cons` 2 \`cons` 3 \`cons` nil
195-- [1,2,3]
196-- @
197--
198-- @since 0.1.0
199cons :: IsStream t => a -> t m a -> t m a
200cons a r = fromStream $ S.cons a (toStream r)
202infixr 5 .:
204-- | Operator equivalent of 'cons'.
205--
206-- @
207-- > toList $ 1 .: 2 .: 3 .: nil
208-- [1,2,3]
209-- @
210--
211-- @since 0.1.1
212(.:) :: IsStream t => a -> t m a -> t m a
213(.:) = cons
215-- | Build a stream from its church encoding. The function passed maps
216-- directly to the underlying representation of the stream type. The second
217-- parameter to the function is the "yield" function yielding a value and the
218-- remaining stream if any otherwise 'Nothing'. The third parameter is to
219-- represent an "empty" stream.
220streamBuild :: IsStream t
221 => (forall r. Maybe (SVar m a)
222 -> (a -> t m a -> m r)
223 -> (a -> m r)
224 -> m r
225 -> m r)
226 -> t m a
227streamBuild k = fromStream $ S.Stream $ \svr stp sng yld ->
228 let yield a r = yld a (toStream r)
229 in k svr yield sng stp
231-- | Build a singleton stream from a callback function.
232fromCallback :: IsStream t => (forall r. (a -> m r) -> m r) -> t m a
233fromCallback k = fromStream $ S.Stream $ \_ _ sng _ -> k sng
235-- | Read an SVar to get a stream.
236fromSVar :: (MonadParallel m, IsStream t) => SVar m a -> t m a
237fromSVar sv = fromStream $ S.fromStreamVar sv
239------------------------------------------------------------------------------
240-- Destroying a stream
241------------------------------------------------------------------------------
243-- | Fold a stream using its church encoding. The second argument is the "step"
244-- function consuming an element and the remaining stream, if any. The third
245-- argument is for consuming an "empty" stream that yields nothing.
246streamFold
247 :: IsStream t
248 => Maybe (SVar m a)
249 -> (a -> t m a -> m r)
250 -> (a -> m r)
251 -> m r
252 -> t m a
253 -> m r
254streamFold svr step single blank m =
255 let yield a x = step a (fromStream x)
256 in (S.runStream (toStream m)) svr blank single yield
258-- | Run a streaming composition, discard the results. By default it interprets
259-- the stream as 'StreamT', to run other types of streams use the type adapting
260-- combinators for example @runStream . 'parallely'@.
261--
262-- @since 0.2.0
263runStream :: Monad m => StreamT m a -> m ()
264runStream m = go (toStream m)
265 where
266 go m1 =
267 let stop = return ()
268 single _ = return ()
269 yield _ r = go r
270 in (S.runStream m1) Nothing stop single yield
272-- | Same as 'runStream'
273--
274-- @since 0.1.0
275{-# DEPRECATED runStreaming "Please use runStream instead." #-}
276runStreaming :: (Monad m, IsStream t) => t m a -> m ()
277runStreaming = runStream . adapt
279-- | Write a stream to an 'SVar' in a non-blocking manner. The stream can then
280-- be read back from the SVar using 'fromSVar'.
281toSVar :: (IsStream t, MonadParallel m) => SVar m a -> t m a -> m ()
282toSVar sv m = S.toStreamVar sv (toStream m)
284------------------------------------------------------------------------------
285-- Transformation
286------------------------------------------------------------------------------
288-- XXX Get rid of this?
289-- | Make a stream asynchronous, triggers the computation and returns a stream
290-- in the underlying monad representing the output generated by the original
291-- computation. The returned action is exhaustible and must be drained once. If
292-- not drained fully we may have a thread blocked forever and once exhausted it
293-- will always return 'empty'.
294--
295-- @since 0.1.0
296async :: (IsStream t, MonadParallel m) => t m a -> m (t m a)
297async m = do
298 sv <- S.newStreamVar1 (SVarStyle Disjunction LIFO) (toStream m)
299 return $ fromSVar sv
301------------------------------------------------------------------------------
302-- CPP macros for common instances
303------------------------------------------------------------------------------
305-- XXX use template haskell instead and include Monoid and IsStream instances
306-- as well.
308#define MONADPARALLEL , MonadParallel m
310#define MONAD_APPLICATIVE_INSTANCE(STREAM,CONSTRAINT) \
311instance (Monad m CONSTRAINT) => Applicative (STREAM m) where { \
312 pure = STREAM . S.singleton; \
313 (<*>) = ap }
315#define MONAD_COMMON_INSTANCES(STREAM,CONSTRAINT) \
316instance (MonadBase b m, Monad m CONSTRAINT) => MonadBase b (STREAM m) where {\
317 liftBase = liftBaseDefault }; \
318 \
319instance (MonadIO m CONSTRAINT) => MonadIO (STREAM m) where { \
320 liftIO = lift . liftIO }; \
321 \
322instance (MonadThrow m CONSTRAINT) => MonadThrow (STREAM m) where { \
323 throwM = lift . throwM }; \
324 \
325{- \
326instance (MonadError e m CONSTRAINT) => MonadError e (STREAM m) where { \
327 throwError = lift . throwError; \
328 catchError m h = \
329 fromStream $ S.withCatchError (toStream m) (\e -> toStream $ h e) }; \
330-} \
331 \
332instance (MonadReader r m CONSTRAINT) => MonadReader r (STREAM m) where { \
333 ask = lift ask; \
334 local f m = fromStream $ S.withLocal f (toStream m) }; \
335 \
336instance (MonadState s m CONSTRAINT) => MonadState s (STREAM m) where { \
337 get = lift get; \
338 put x = lift (put x); \
339 state k = lift (state k) }
341------------------------------------------------------------------------------
342-- StreamT
343------------------------------------------------------------------------------
345-- | The 'Semigroup' instance of 'StreamT' appends two streams sequentially,
346-- yielding all elements from the first stream, and then all elements from the
347-- second stream.
348--
349-- @
350-- main = ('toList' . 'streamly' $ (fromFoldable [1,2]) \<\> (fromFoldable [3,4])) >>= print
351-- @
352-- @
353-- [1,2,3,4]
354-- @
355--
356-- The 'Monad' instance runs the /monadic continuation/ for each
357-- element of the stream, streamly.
358--
359-- @
360-- main = 'runStream' . 'streamly' $ do
361-- x <- return 1 \<\> return 2
362-- liftIO $ print x
363-- @
364-- @
365-- 1
366-- 2
367-- @
368--
369-- 'StreamT' nests streams streamly in a depth first manner.
370--
371-- @
372-- main = 'runStream' . 'streamly' $ do
373-- x <- return 1 \<\> return 2
374-- y <- return 3 \<\> return 4
375-- liftIO $ print (x, y)
376-- @
377-- @
378-- (1,3)
379-- (1,4)
380-- (2,3)
381-- (2,4)
382-- @
383--
384-- This behavior of 'StreamT' is exactly like a list transformer. We call the
385-- monadic code being run for each element of the stream a monadic
386-- continuation. In imperative paradigm we can think of this composition as
387-- nested @for@ loops and the monadic continuation is the body of the loop. The
388-- loop iterates for all elements of the stream.
389--
390-- The 'streamly' combinator can be omitted as the default stream type is
391-- 'StreamT'.
392-- Note that serial composition can be used to combine an infinite number of
393-- streams as it explores only one stream at a time.
394--
395-- @since 0.1.0
396newtype StreamT m a = StreamT {getStreamT :: S.Stream m a}
397 deriving (Semigroup, Monoid, Functor, MonadTrans)
399instance IsStream StreamT where
400 toStream = getStreamT
401 fromStream = StreamT
403------------------------------------------------------------------------------
404-- Semigroup
405------------------------------------------------------------------------------
407-- | Polymorphic version of the 'Semigroup' operation '<>' of 'StreamT'.
408-- Appends two streams sequentially, yielding all elements from the first
409-- stream, and then all elements from the second stream.
410--
411-- @since 0.2.0
412{-# INLINE splice #-}
413splice :: IsStream t => t m a -> t m a -> t m a
414splice m1 m2 = fromStream $ S.splice (toStream m1) (toStream m2)
416------------------------------------------------------------------------------
417-- Monad
418------------------------------------------------------------------------------
420instance Monad m => Monad (StreamT m) where
421 return = pure
422 (StreamT (S.Stream m)) >>= f = StreamT $ S.Stream $ \_ stp sng yld ->
423 let run x = (S.runStream x) Nothing stp sng yld
424 single a = run $ toStream (f a)
425 yield a r = run $ toStream $ f a <> (fromStream r >>= f)
426 in m Nothing stp single yield
428------------------------------------------------------------------------------
429-- Other instances
430------------------------------------------------------------------------------
432MONAD_APPLICATIVE_INSTANCE(StreamT,)
433MONAD_COMMON_INSTANCES(StreamT,)
435------------------------------------------------------------------------------
436-- CostreamT
437------------------------------------------------------------------------------
439-- | The 'Semigroup' instance of 'CostreamT' interleaves two streams,
440-- yielding one element from each stream alternately.
441--
442-- @
443-- main = ('toList' . 'costreamly' $ (fromFoldable [1,2]) \<\> (fromFoldable [3,4])) >>= print
444-- @
445-- @
446-- [1,3,2,4]
447-- @
448--
449-- Similarly, the 'Monad' instance fairly interleaves the iterations of the
450-- inner and the outer loop, nesting loops in a breadth first manner.
451--
452--
453-- @
454-- main = 'runStream' . 'costreamly' $ do
455-- x <- return 1 \<\> return 2
456-- y <- return 3 \<\> return 4
457-- liftIO $ print (x, y)
458-- @
459-- @
460-- (1,3)
461-- (2,3)
462-- (1,4)
463-- (2,4)
464-- @
465--
466-- Note that costreamly composition can only combine a finite number of
467-- streams as it needs to retain state for each unfinished stream.
468--
469-- @since 0.2.0
470newtype CostreamT m a = CostreamT {getCostreamT :: S.Stream m a}
471 deriving (Functor, MonadTrans)
473-- |
474-- @since 0.1.0
475{-# DEPRECATED InterleavedT "Please use 'CostreamT' instead." #-}
476type InterleavedT = CostreamT
478instance IsStream CostreamT where
479 toStream = getCostreamT
480 fromStream = CostreamT
482------------------------------------------------------------------------------
483-- Semigroup
484------------------------------------------------------------------------------
486-- | Polymorphic version of the 'Semigroup' operation '<>' of 'CostreamT'.
487-- Interleaves two streams, yielding one element from each stream alternately.
488--
489-- @since 0.2.0
490{-# INLINE cosplice #-}
491cosplice :: IsStream t => t m a -> t m a -> t m a
492cosplice m1 m2 = fromStream $ S.cosplice (toStream m1) (toStream m2)
494instance Semigroup (CostreamT m a) where
495 (<>) = cosplice
497infixr 5 <=>
499-- | Same as 'cosplice'.
500--
501-- @since 0.1.0
502{-# DEPRECATED (<=>) "Please use 'cosplice' instead." #-}
503{-# INLINE (<=>) #-}
504(<=>) :: IsStream t => t m a -> t m a -> t m a
505(<=>) = cosplice
507------------------------------------------------------------------------------
508-- Monoid
509------------------------------------------------------------------------------
511instance Monoid (CostreamT m a) where
512 mempty = nil
513 mappend = (<>)
515------------------------------------------------------------------------------
516-- Monad
517------------------------------------------------------------------------------
519instance Monad m => Monad (CostreamT m) where
520 return = pure
521 (CostreamT (S.Stream m)) >>= f = CostreamT $ S.Stream $ \_ stp sng yld ->
522 let run x = (S.runStream x) Nothing stp sng yld
523 single a = run $ toStream (f a)
524 yield a r = run $ toStream $ f a <> (fromStream r >>= f)
525 in m Nothing stp single yield
527------------------------------------------------------------------------------
528-- Other instances
529------------------------------------------------------------------------------
531MONAD_APPLICATIVE_INSTANCE(CostreamT,)
532MONAD_COMMON_INSTANCES(CostreamT,)
534------------------------------------------------------------------------------
535-- CoparallelT
536------------------------------------------------------------------------------
538-- | Adaptive parallel, in a left to right 'Semigroup' composition it tries to
539-- yield elements from the left stream as long as it can, but it can run the
540-- right stream in parallel if it needs to based on demand. The right stream
541-- can be run if the left stream blocks on IO or cannot produce elements fast
542-- enough for the consumer.
543--
544-- @
545-- main = ('toList' . 'coparallely' $ (fromFoldable [1,2]) \<> (fromFoldable [3,4])) >>= print
546-- @
547-- @
548-- [1,2,3,4]
549-- @
550--
551-- Similarly, the monad instance of 'ParallelT' /may/ run each iteration
552-- concurrently based on demand. More concurrent iterations are started only
553-- if the previous iterations are not able to produce enough output for the
554-- consumer.
555--
556-- @
557-- import "Streamly"
558-- import Control.Concurrent
559--
560-- main = 'runStream' . 'coparallely' $ do
561-- n <- return 3 \<\> return 2 \<\> return 1
562-- liftIO $ do
563-- threadDelay (n * 1000000)
564-- myThreadId >>= \\tid -> putStrLn (show tid ++ ": Delay " ++ show n)
565-- @
566-- @
567-- ThreadId 40: Delay 1
568-- ThreadId 39: Delay 2
569-- ThreadId 38: Delay 3
570-- @
571--
572-- All iterations may run in the same thread if they do not block.
573--
574-- Note that this composition can be used to combine infinite number of streams
575-- as it explores only a bounded number of streams at a time.
576--
577-- @since 0.2.0
578newtype CoparallelT m a = CoparallelT {getCoparallelT :: S.Stream m a}
579 deriving (Functor, MonadTrans)
581-- |
582-- @since 0.1.0
583{-# DEPRECATED AsyncT "Please use 'CoparallelT' instead." #-}
584type AsyncT = CoparallelT
586instance IsStream CoparallelT where
587 toStream = getCoparallelT
588 fromStream = CoparallelT
590------------------------------------------------------------------------------
591-- Semigroup
592------------------------------------------------------------------------------
594-- | Polymorphic version of the 'Semigroup' operation '<>' of 'CoparallelT'.
595-- Merges two streams possibly concurrently, preferring the
596-- elements from the left one when available.
597--
598-- @since 0.2.0
599{-# INLINE coparallel #-}
600coparallel :: (IsStream t, MonadParallel m) => t m a -> t m a -> t m a
601coparallel m1 m2 = fromStream $ S.coparallel (toStream m1) (toStream m2)
603instance MonadParallel m => Semigroup (CoparallelT m a) where
604 (<>) = coparallel
606-- | Same as 'coparallel'.
607--
608-- @since 0.1.0
609{-# DEPRECATED (<|) "Please use 'coparallel' instead." #-}
610{-# INLINE (<|) #-}
611(<|) :: (IsStream t, MonadParallel m) => t m a -> t m a -> t m a
612(<|) = coparallel
614------------------------------------------------------------------------------
615-- Monoid
616------------------------------------------------------------------------------
618instance MonadParallel m => Monoid (CoparallelT m a) where
619 mempty = nil
620 mappend = (<>)
622------------------------------------------------------------------------------
623-- Monad
624------------------------------------------------------------------------------
626{-# INLINE parbind #-}
627parbind
628 :: (forall c. S.Stream m c -> S.Stream m c -> S.Stream m c)
629 -> S.Stream m a
630 -> (a -> S.Stream m b)
631 -> S.Stream m b
632parbind par m f = go m
633 where
634 go (S.Stream g) =
635 S.Stream $ \ctx stp sng yld ->
636 let run x = (S.runStream x) ctx stp sng yld
637 single a = run $ f a
638 yield a r = run $ f a `par` go r
639 in g Nothing stp single yield
641instance MonadParallel m => Monad (CoparallelT m) where
642 return = pure
643 (CoparallelT m) >>= f = CoparallelT $ parbind par m (getCoparallelT . f)
644 where par = S.joinStreamVar2 (SVarStyle Conjunction LIFO)
646------------------------------------------------------------------------------
647-- Other instances
648------------------------------------------------------------------------------
650MONAD_APPLICATIVE_INSTANCE(CoparallelT,MONADPARALLEL)
651MONAD_COMMON_INSTANCES(CoparallelT, MONADPARALLEL)
653------------------------------------------------------------------------------
654-- ParallelT
655------------------------------------------------------------------------------
657-- | Round robin concurrent composition.
658--
659-- The Semigroup instance of 'ParallelT' concurrently /merges/ streams in a
660-- round robin fashion, yielding elements from both streams alternately.
661--
662-- @
663-- main = ('toList' . 'parallely' $ (fromFoldable [1,2]) \<> (fromFoldable [3,4])) >>= print
664-- @
665-- @
666-- [1,3,2,4]
667-- @
668--
669-- Similarly, the 'Monad' instance of 'ParallelT' runs /all/ iterations fairly
670-- concurrently using a round robin scheduling.
671--
672-- @
673-- import "Streamly"
674-- import Control.Concurrent
675--
676-- main = 'runStream' . 'parallely' $ do
677-- n <- return 3 \<\> return 2 \<\> return 1
678-- liftIO $ do
679-- threadDelay (n * 1000000)
680-- myThreadId >>= \\tid -> putStrLn (show tid ++ ": Delay " ++ show n)
681-- @
682-- @
683-- ThreadId 40: Delay 1
684-- ThreadId 39: Delay 2
685-- ThreadId 38: Delay 3
686-- @
687--
688-- Unlike 'CoparallelT' all iterations are guaranteed to run fairly
689-- concurrently, unconditionally.
690--
691-- Note that round robin composition can only combine a finite number of
692-- streams as it needs to retain state for each unfinished stream.
693--
694-- @since 0.1.0
695newtype ParallelT m a = ParallelT {getParallelT :: S.Stream m a}
696 deriving (Functor, MonadTrans)
698instance IsStream ParallelT where
699 toStream = getParallelT
700 fromStream = ParallelT
702------------------------------------------------------------------------------
703-- Semigroup
704------------------------------------------------------------------------------
706-- | Polymorphic version of the 'Semigroup' operation '<>' of 'ParallelT'.
707-- Merges two streams concurrently choosing elements from both fairly.
708--
709-- @since 0.2.0
710{-# INLINE parallel #-}
711parallel :: (IsStream t, MonadParallel m) => t m a -> t m a -> t m a
712parallel m1 m2 = fromStream $ S.parallel (toStream m1) (toStream m2)
714instance MonadParallel m => Semigroup (ParallelT m a) where
715 (<>) = parallel
717------------------------------------------------------------------------------
718-- Monoid
719------------------------------------------------------------------------------
721instance MonadParallel m => Monoid (ParallelT m a) where
722 mempty = nil
723 mappend = (<>)
725------------------------------------------------------------------------------
726-- Monad
727------------------------------------------------------------------------------
729instance MonadParallel m => Monad (ParallelT m) where
730 return = pure
731 (ParallelT m) >>= f = ParallelT $ parbind par m (getParallelT . f)
732 where par = S.joinStreamVar2 (SVarStyle Conjunction FIFO)
734------------------------------------------------------------------------------
735-- Other instances
736------------------------------------------------------------------------------
738MONAD_APPLICATIVE_INSTANCE(ParallelT,MONADPARALLEL)
739MONAD_COMMON_INSTANCES(ParallelT, MONADPARALLEL)
741------------------------------------------------------------------------------
742-- Serially Zipping Streams
743------------------------------------------------------------------------------
745-- | The applicative instance of 'ZipStreamM' zips a number of streams serially
746-- i.e. it produces one element from each stream serially and then zips all
747-- those elements.
748--
749-- @
750-- main = (toList . 'zipStreamly' $ (,,) \<$\> s1 \<*\> s2 \<*\> s3) >>= print
751-- where s1 = fromFoldable [1, 2]
752-- s2 = fromFoldable [3, 4]
753-- s3 = fromFoldable [5, 6]
754-- @
755-- @
756-- [(1,3,5),(2,4,6)]
757-- @
758--
759-- The 'Semigroup' instance of this type works the same way as that of
760-- 'StreamT'.
761--
762-- @since 0.2.0
763newtype ZipStreamM m a = ZipStreamM {getZipStreamM :: S.Stream m a}
764 deriving (Functor, Semigroup, Monoid)
766instance IsStream ZipStreamM where
767 toStream = getZipStreamM
768 fromStream = ZipStreamM
770instance Monad m => Applicative (ZipStreamM m) where
771 pure = ZipStreamM . S.repeat
772 m1 <*> m2 = fromStream $ S.zipWith id (toStream m1) (toStream m2)
774------------------------------------------------------------------------------
775-- Parallely Zipping Streams
776------------------------------------------------------------------------------
778-- | Like 'ZipStreamM' but zips in parallel, it generates all the elements to
779-- be zipped concurrently.
780--
781-- @
782-- main = (toList . 'zipParallely' $ (,,) \<$\> s1 \<*\> s2 \<*\> s3) >>= print
783-- where s1 = fromFoldable [1, 2]
784-- s2 = fromFoldable [3, 4]
785-- s3 = fromFoldable [5, 6]
786-- @
787-- @
788-- [(1,3,5),(2,4,6)]
789-- @
790--
791-- The 'Semigroup' instance of this type works the same way as that of
792-- 'StreamT'.
793--
794-- @since 0.2.0
795newtype ZipParallelM m a = ZipParallelM {getZipParallelM :: S.Stream m a}
796 deriving (Functor, Semigroup, Monoid)
798-- |
799-- @since 0.1.0
800{-# DEPRECATED ZipAsync "Please use ZipParallelM instead." #-}
801type ZipAsync = ZipParallelM
803instance IsStream ZipParallelM where
804 toStream = getZipParallelM
805 fromStream = ZipParallelM
807instance MonadParallel m => Applicative (ZipParallelM m) where
808 pure = ZipParallelM . S.repeat
809 m1 <*> m2 = fromStream $ S.zipParallelWith id (toStream m1) (toStream m2)
811-------------------------------------------------------------------------------
812-- Type adapting combinators
813-------------------------------------------------------------------------------
815-- | Adapt any specific stream type to any other specific stream type.
816--
817-- @since 0.1.0
818adapt :: (IsStream t1, IsStream t2) => t1 m a -> t2 m a
819adapt = fromStream . toStream
821-- | Fix the type of a polymorphic stream as 'StreamT'.
822--
823-- @since 0.2.0
824streamly :: IsStream t => StreamT m a -> t m a
825streamly = adapt
827-- | Same as 'streamly'.
828--
829-- @since 0.1.0
830{-# DEPRECATED serially "Please use streamly instead." #-}
831serially :: IsStream t => StreamT m a -> t m a
832serially = streamly
834-- | Fix the type of a polymorphic stream as 'CostreamT'.
835--
836-- @since 0.2.0
837costreamly :: IsStream t => CostreamT m a -> t m a
838costreamly = adapt
840-- | Same as 'costreamly'.
841--
842-- @since 0.1.0
843{-# DEPRECATED interleaving "Please use costreamly instead." #-}
844interleaving :: IsStream t => CostreamT m a -> t m a
845interleaving = costreamly
847-- | Fix the type of a polymorphic stream as 'CoparallelT'.
848--
849-- @since 0.2.0
850coparallely :: IsStream t => CoparallelT m a -> t m a
851coparallely = adapt
853-- | Same as 'coparallely'.
854--
855-- @since 0.1.0
856{-# DEPRECATED asyncly "Please use coparallely instead." #-}
857asyncly :: IsStream t => CoparallelT m a -> t m a
858asyncly = coparallely
860-- | Fix the type of a polymorphic stream as 'ParallelT'.
861--
862-- @since 0.1.0
863parallely :: IsStream t => ParallelT m a -> t m a
864parallely = adapt
866-- | Fix the type of a polymorphic stream as 'ZipStreamM'.
867--
868-- @since 0.2.0
869zipStreamly :: IsStream t => ZipStreamM m a -> t m a
870zipStreamly = adapt
872-- | Same as 'zipStreamly'.
873--
874-- @since 0.1.0
875{-# DEPRECATED zipping "Please use zipStreamly instead." #-}
876zipping :: IsStream t => ZipStreamM m a -> t m a
877zipping = zipStreamly
879-- | Fix the type of a polymorphic stream as 'ZipParallelM'.
880--
881-- @since 0.2.0
882zipParallely :: IsStream t => ZipParallelM m a -> t m a
883zipParallely = adapt
885-- | Same as 'zipParallely'.
886--
887-- @since 0.1.0
888{-# DEPRECATED zippingAsync "Please use zipParallely instead." #-}
889zippingAsync :: IsStream t => ZipParallelM m a -> t m a
890zippingAsync = zipParallely
892-------------------------------------------------------------------------------
893-- Running Streams, convenience functions specialized to types
894-------------------------------------------------------------------------------
896-- | Same as @runStream@.
897--
898-- @since 0.1.0
899{-# DEPRECATED runStreamT "Please use runStream instead." #-}
900runStreamT :: Monad m => StreamT m a -> m ()
901runStreamT = runStream
903-- | Same as @runStream . costreamly@.
904--
905-- @since 0.1.0
906{-# DEPRECATED runInterleavedT "Please use 'runStream . interleaving' instead." #-}
907runInterleavedT :: Monad m => InterleavedT m a -> m ()
908runInterleavedT = runStream . costreamly
910-- | Same as @runStream . coparallely@.
911--
912-- @since 0.1.0
913{-# DEPRECATED runAsyncT "Please use 'runStream . coparallely' instead." #-}
914runAsyncT :: Monad m => CoparallelT m a -> m ()
915runAsyncT = runStream . coparallely
917-- | Same as @runStream . parallely@.
918--
919-- @since 0.1.0
920{-# DEPRECATED runParallelT "Please use 'runStream . parallely' instead." #-}
921runParallelT :: Monad m => ParallelT m a -> m ()
922runParallelT = runStream . parallely
924-- | Same as @runStream . zipping@.
925--
926-- @since 0.1.0
927{-# DEPRECATED runZipStream "Please use 'runStream . zipStreamly instead." #-}
928runZipStream :: Monad m => ZipStreamM m a -> m ()
929runZipStream = runStream . zipStreamly
931-- | Same as @runStream . zippingAsync@.
932--
933-- @since 0.1.0
934{-# DEPRECATED runZipAsync "Please use 'runStream . zipParallely instead." #-}
935runZipAsync :: Monad m => ZipParallelM m a -> m ()
936runZipAsync = runStream . zipParallely
938------------------------------------------------------------------------------
939-- IO Streams
940------------------------------------------------------------------------------
942-- | A serial IO stream of elements of type @a@. See 'StreamT' documentation
943-- for more details.
944--
945-- @since 0.2.0
946type Stream a = StreamT IO a
948-- | An interleaving serial IO stream of elements of type @a@. See 'CostreamT'
949-- documentation for more details.
950--
951-- @since 0.2.0
952type Costream a = CostreamT IO a
954-- | A demand driven left biased parallelly composing IO stream of elements of
955-- type @a@. See 'CoparallelT' documentation for more details.
956--
957-- @since 0.2.0
958type Coparallel a = CoparallelT IO a
960-- | A round robin parallelly composing IO stream of elements of type @a@.
961-- See 'ParallelT' documentation for more details.
962--
963-- @since 0.2.0
964type Parallel a = ParallelT IO a
966-- | An IO stream whose applicative instance zips streams serially.
967--
968-- @since 0.2.0
969type ZipStream a = ZipStreamM IO a
971-- | An IO stream whose applicative instance zips streams parallely.
972--
973-- @since 0.2.0
974type ZipParallel a = ZipParallelM IO a
976------------------------------------------------------------------------------
977-- Fold Utilities
978------------------------------------------------------------------------------
980-- | A variant of 'Data.Foldable.fold' that allows you to fold a 'Foldable'
981-- container of streams using the specified stream sum operation.
982--
983-- @foldWith 'parallel' $ map return [1..3]@
984--
985-- @since 0.1.0
986{-# INLINABLE foldWith #-}
987foldWith :: (IsStream t, Foldable f)
988 => (t m a -> t m a -> t m a) -> f (t m a) -> t m a
989foldWith f = foldr f nil
991-- | A variant of 'foldMap' that allows you to map a monadic streaming action
992-- on a 'Foldable' container and then fold it using the specified stream sum
993-- operation.
994--
995-- @foldMapWith 'parallel' return [1..3]@
996--
997-- @since 0.1.0
998{-# INLINABLE foldMapWith #-}
999foldMapWith :: (IsStream t, Foldable f)
1000 => (t m b -> t m b -> t m b) -> (a -> t m b) -> f a -> t m b
1001foldMapWith f g = foldr (f . g) nil
1003-- | Like 'foldMapWith' but with the last two arguments reversed i.e. the
1004-- monadic streaming function is the last argument.
1006-- @since 0.1.0
1007{-# INLINABLE forEachWith #-}
1008forEachWith :: (IsStream t, Foldable f)
1009 => (t m b -> t m b -> t m b) -> f a -> (a -> t m b) -> t m b
1010forEachWith f xs g = foldr (f . g) nil xs