1{-# LANGUAGE UndecidableInstances #-}
4-- Module : Streamly.Internal.Data.Stream.Serial
5-- Copyright : (c) 2017 Composewell Technologies
8-- Maintainer : streamly@composewell.com
9-- Stability : experimental
12-- To run examples in this module:
14-- >>> import qualified Streamly.Prelude as Stream
16module Streamly.Internal.Data.Stream.Serial
18 -- * Serial appending stream
23 -- * Serial interleaving stream
52import Control.Applicative (liftA2)
53import Control.DeepSeq (NFData(..))
54#if MIN_VERSION_deepseq(1,4,3)
55import Control.DeepSeq (NFData1(..))
57import Control.Monad.Base (MonadBase(..), liftBaseDefault)
58import Control.Monad.Catch (MonadThrow, throwM)
59import Control.Monad.IO.Class (MonadIO(..))
60import Control.Monad.Reader.Class (MonadReader(..))
61import Control.Monad.State.Class (MonadState(..))
62import Control.Monad.Trans.Class (MonadTrans(lift))
63import Data.Foldable (Foldable(foldl'), fold)
64import Data.Functor.Identity (Identity(..), runIdentity)
65import Data.Maybe (fromMaybe)
66import Data.Semigroup (Endo(..))
67#if __GLASGOW_HASKELL__ < 808
68import Data.Semigroup (Semigroup(..))
70import GHC.Exts (IsList(..), IsString(..))
72 ( Lexeme(Ident), lexP, parens, prec, readPrec, readListPrec
73 , readListPrecDefault)
74import Streamly.Internal.BaseCompat ((#.), errorWithoutStackTrace, oneShot)
75import Streamly.Internal.Data.Maybe.Strict (Maybe'(..), toMaybe)
76import Streamly.Internal.Data.Stream.StreamK.Type
77 (Stream, mkStream, foldStream)
79import qualified Streamly.Internal.Data.Stream.Prelude as P
80import qualified Streamly.Internal.Data.Stream.StreamD.Generate as D
81import qualified Streamly.Internal.Data.Stream.StreamD.Type as D
82import qualified Streamly.Internal.Data.Stream.StreamK.Type as K
84import Prelude hiding (map, mapM, errorWithoutStackTrace, repeat)
86#include "Instances.hs"
90-- >>> import qualified Streamly.Prelude as Stream
92------------------------------------------------------------------------------
94------------------------------------------------------------------------------
96-- | For 'SerialT' streams:
99-- (<>) = 'Streamly.Prelude.serial' -- 'Semigroup'
100-- (>>=) = flip . 'Streamly.Prelude.concatMapWith' 'Streamly.Prelude.serial' -- 'Monad'
103-- A single 'Monad' bind behaves like a @for@ loop:
107-- x <- Stream.fromList [1,2] -- foreach x in stream
112-- Nested monad binds behave like nested @for@ loops:
116-- x <- Stream.fromList [1,2] -- foreach x in stream
117-- y <- Stream.fromList [3,4] -- foreach y in stream
120-- [(1,3),(1,4),(2,3),(2,4)]
122-- /Since: 0.2.0 ("Streamly")/
125newtype SerialT m a = SerialT {getSerialT :: Stream m a}
126 -- XXX when deriving do we inherit an INLINE?
127 deriving (Semigroup, Monoid, MonadTrans)
129-- | A serial IO stream of elements of type @a@. See 'SerialT' documentation
132-- /Since: 0.2.0 ("Streamly")/
135type Serial = SerialT IO
139{-# DEPRECATED StreamT "Please use 'SerialT' instead." #-}
140type StreamT = SerialT
142------------------------------------------------------------------------------
144------------------------------------------------------------------------------
147cons :: a -> SerialT m a -> SerialT m a
148cons x (SerialT ms) = SerialT $ K.cons x ms
151{-# SPECIALIZE consM :: IO a -> SerialT IO a -> SerialT IO a #-}
152consM :: Monad m => m a -> SerialT m a -> SerialT m a
153consM m (SerialT ms) = SerialT $ K.consM m ms
156-- Generate an infinite stream by repeating a pure value.
158{-# INLINE_NORMAL repeat #-}
159repeat :: Monad m => a -> SerialT m a
160repeat = SerialT . D.toStreamK . D.repeat
162------------------------------------------------------------------------------
164------------------------------------------------------------------------------
167serial :: SerialT m a -> SerialT m a -> SerialT m a
170------------------------------------------------------------------------------
172------------------------------------------------------------------------------
174instance Monad m => Monad (SerialT m) where
177 -- Benchmarks better with StreamD bind and pure:
178 -- toList, filterAllout, *>, *<, >> (~2x)
180 -- pure = SerialT . D.fromStreamD . D.fromPure
181 -- m >>= f = D.fromStreamD $ D.concatMap (D.toStreamD . f) (D.toStreamD m)
183 -- Benchmarks better with CPS bind and pure:
185 -- n binds, breakAfterSome, filterAllIn, state transformer (~2x)
188 (>>=) (SerialT m) f = SerialT $ K.bindWith K.serial m (getSerialT . f)
193------------------------------------------------------------------------------
195------------------------------------------------------------------------------
198mapM :: Monad m => (a -> m b) -> SerialT m a -> SerialT m b
199mapM f (SerialT m) = SerialT $ D.toStreamK $ D.mapM f $ D.fromStreamK m
209-- > S.toList $ S.map (+1) $ S.fromList [1,2,3]
215map :: Monad m => (a -> b) -> SerialT m a -> SerialT m b
216map f = mapM (return . f)
218{-# INLINE apSerial #-}
219apSerial :: Monad m => SerialT m (a -> b) -> SerialT m a -> SerialT m b
220apSerial (SerialT m1) (SerialT m2) =
221 SerialT $ D.toStreamK $ D.fromStreamK m1 <*> D.fromStreamK m2
223{-# INLINE apSequence #-}
224apSequence :: Monad m => SerialT m a -> SerialT m b -> SerialT m b
225apSequence (SerialT m1) (SerialT m2) =
226 SerialT $ D.toStreamK $ D.fromStreamK m1 *> D.fromStreamK m2
228{-# INLINE apDiscardSnd #-}
229apDiscardSnd :: Monad m => SerialT m a -> SerialT m b -> SerialT m a
230apDiscardSnd (SerialT m1) (SerialT m2) =
231 SerialT $ D.toStreamK $ D.fromStreamK m1 <* D.fromStreamK m2
233-- Note: we need to define all the typeclass operations because we want to
235instance Monad m => Applicative (SerialT m) where
237 pure = SerialT . K.fromPure
241 -- (<*>) = K.apSerial
243#if MIN_VERSION_base(4,10,0)
244 {-# INLINE liftA2 #-}
245 liftA2 f x = (<*>) (fmap f x)
250 -- (*>) = K.apSerialDiscardFst
254 -- (<*) = K.apSerialDiscardSnd
256MONAD_COMMON_INSTANCES(SerialT,)
257LIST_INSTANCES(SerialT)
258NFDATA1_INSTANCE(SerialT)
259FOLDABLE_INSTANCE(SerialT)
260TRAVERSABLE_INSTANCE(SerialT)
262------------------------------------------------------------------------------
264------------------------------------------------------------------------------
266-- | For 'WSerialT' streams:
269-- (<>) = 'Streamly.Prelude.wSerial' -- 'Semigroup'
270-- (>>=) = flip . 'Streamly.Prelude.concatMapWith' 'Streamly.Prelude.wSerial' -- 'Monad'
273-- Note that '<>' is associative only if we disregard the ordering of elements
274-- in the resulting stream.
276-- A single 'Monad' bind behaves like a @for@ loop:
279-- Stream.toList $ Stream.fromWSerial $ do
280-- x <- Stream.fromList [1,2] -- foreach x in stream
285-- Nested monad binds behave like interleaved nested @for@ loops:
288-- Stream.toList $ Stream.fromWSerial $ do
289-- x <- Stream.fromList [1,2] -- foreach x in stream
290-- y <- Stream.fromList [3,4] -- foreach y in stream
293-- [(1,3),(2,3),(1,4),(2,4)]
295-- It is a result of interleaving all the nested iterations corresponding to
296-- element @1@ in the first stream with all the nested iterations of element
299-- >>> import Streamly.Prelude (wSerial)
300-- >>> Stream.toList $ Stream.fromList [(1,3),(1,4)] `Stream.wSerial` Stream.fromList [(2,3),(2,4)]
301-- [(1,3),(2,3),(1,4),(2,4)]
303-- The @W@ in the name stands for @wide@ or breadth wise scheduling in
304-- contrast to the depth wise scheduling behavior of 'SerialT'.
306-- /Since: 0.2.0 ("Streamly")/
309newtype WSerialT m a = WSerialT {getWSerialT :: Stream m a}
310 deriving (MonadTrans)
312-- | An interleaving serial IO stream of elements of type @a@. See 'WSerialT'
313-- documentation for more details.
315-- /Since: 0.2.0 ("Streamly")/
318type WSerial = WSerialT IO
322{-# DEPRECATED InterleavedT "Please use 'WSerialT' instead." #-}
323type InterleavedT = WSerialT
325{-# INLINE consMWSerial #-}
326{-# SPECIALIZE consMWSerial :: IO a -> WSerialT IO a -> WSerialT IO a #-}
327consMWSerial :: Monad m => m a -> WSerialT m a -> WSerialT m a
328consMWSerial m (WSerialT ms) = WSerialT $ K.consM m ms
330------------------------------------------------------------------------------
332------------------------------------------------------------------------------
336-- Additionally we can have m elements yield from the first stream and n
337-- elements yielding from the second stream. We can also have time slicing
338-- variants of positional interleaving, e.g. run first stream for m seconds and
339-- run the second stream for n seconds.
341-- Similar combinators can be implemented using WAhead style.
343{-# INLINE wSerialK #-}
344wSerialK :: Stream m a -> Stream m a -> Stream m a
345wSerialK m1 m2 = mkStream $ \st yld sng stp -> do
346 let stop = foldStream st yld sng stp m2
348 yieldk a r = yld a (wSerialK m2 r)
349 foldStream st yieldk single stop m1
351-- | Interleaves two streams, yielding one element from each stream
352-- alternately. When one stream stops the rest of the other stream is used in
357-- Note that evaluation of @a \`wSerial` b \`wSerial` c@ does not interleave
358-- @a@, @b@ and @c@ with equal priority. This expression is equivalent to @a
359-- \`wSerial` (b \`wSerial` c)@, therefore, it fairly interleaves @a@ with the
360-- result of @b \`wSerial` c@. For example, @Stream.fromList [1,2] \`wSerial`
361-- Stream.fromList [3,4] \`wSerial` Stream.fromList [5,6]@ would result in
362-- [1,3,2,5,4,6]. In other words, the leftmost stream gets the same scheduling
363-- priority as the rest of the streams taken together. The same is true for
364-- each subexpression on the right.
366{-# INLINE wSerial #-}
367wSerial :: WSerialT m a -> WSerialT m a -> WSerialT m a
368wSerial (WSerialT m1) (WSerialT m2) = WSerialT $ wSerialK m1 m2
370-- | Like `wSerial` but stops interleaving as soon as the first stream stops.
373{-# INLINE wSerialFstK #-}
374wSerialFstK :: Stream m a -> Stream m a -> Stream m a
375wSerialFstK m1 m2 = mkStream $ \st yld sng stp -> do
376 let yieldFirst a r = yld a (yieldSecond r m2)
377 in foldStream st yieldFirst sng stp m1
381 yieldSecond s1 s2 = mkStream $ \st yld sng stp -> do
382 let stop = foldStream st yld sng stp s1
384 yieldk a r = yld a (wSerialK s1 r)
385 in foldStream st yieldk single stop s2
387{-# INLINE wSerialFst #-}
388wSerialFst :: WSerialT m a -> WSerialT m a -> WSerialT m a
389wSerialFst (WSerialT m1) (WSerialT m2) = WSerialT $ wSerialFstK m1 m2
391-- | Like `wSerial` but stops interleaving as soon as any of the two streams
395{-# INLINE wSerialMinK #-}
396wSerialMinK :: Stream m a -> Stream m a -> Stream m a
397wSerialMinK m1 m2 = mkStream $ \st yld _ stp -> do
399 -- "single a" is defined as "yld a (wSerialMin m2 K.nil)" instead of
400 -- "sng a" to keep the behaviour consistent with the yield continuation.
401 single a = yld a (wSerialMinK m2 K.nil)
402 yieldk a r = yld a (wSerialMinK m2 r)
403 foldStream st yieldk single stop m1
405{-# INLINE wSerialMin #-}
406wSerialMin :: WSerialT m a -> WSerialT m a -> WSerialT m a
407wSerialMin (WSerialT m1) (WSerialT m2) = WSerialT $ wSerialMinK m1 m2
409instance Semigroup (WSerialT m a) where
412------------------------------------------------------------------------------
414------------------------------------------------------------------------------
416instance Monoid (WSerialT m a) where
417 mempty = WSerialT K.nil
420{-# INLINE apWSerial #-}
421apWSerial :: Monad m => WSerialT m (a -> b) -> WSerialT m a -> WSerialT m b
422apWSerial (WSerialT m1) (WSerialT m2) =
423 let f x1 = K.concatMapWith wSerialK (pure . x1) m2
424 in WSerialT $ K.concatMapWith wSerialK f m1
426instance Monad m => Applicative (WSerialT m) where
428 pure = WSerialT . K.fromPure
432------------------------------------------------------------------------------
434------------------------------------------------------------------------------
436instance Monad m => Monad (WSerialT m) where
439 (>>=) (WSerialT m) f = WSerialT $ K.bindWith wSerialK m (getWSerialT . f)
441------------------------------------------------------------------------------
443------------------------------------------------------------------------------
445MONAD_COMMON_INSTANCES(WSerialT,)
446LIST_INSTANCES(WSerialT)
447NFDATA1_INSTANCE(WSerialT)
448FOLDABLE_INSTANCE(WSerialT)
449TRAVERSABLE_INSTANCE(WSerialT)
451------------------------------------------------------------------------------
453------------------------------------------------------------------------------
455-- | Build a stream by unfolding a /monadic/ step function starting from a
456-- seed. The step function returns the next element in the stream and the next
457-- seed value. When it is done it returns 'Nothing' and the stream ends. For
463-- then return Nothing
464-- else print b >> return (Just (b, b + 1))
465-- in drain $ unfoldrM f 0
476{-# INLINE unfoldrM #-}
477unfoldrM :: Monad m => (b -> m (Maybe (a, b))) -> b -> SerialT m a
478unfoldrM step seed = SerialT $ D.toStreamK (D.unfoldrM step seed)
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list