1{-# LANGUAGE UndecidableInstances #-}
2{-# OPTIONS_GHC -Wno-deprecations #-}
3{-# OPTIONS_GHC -Wno-redundant-constraints #-}
6-- Module : Streamly.Internal.Data.Stream.Serial
7-- Copyright : (c) 2017 Composewell Technologies
10-- Maintainer : streamly@composewell.com
11-- Stability : experimental
14-- To run examples in this module:
16-- >>> import qualified Streamly.Prelude as Stream
18module Streamly.Internal.Data.Stream.Serial {-# DEPRECATED "Please use \"Streamly.Internal.Data.Stream\" from streamly-core package instead." #-}
20 -- * Serial appending stream
27 -- * Serial interleaving stream
51import Control.Applicative (liftA2)
52import Control.DeepSeq (NFData(..), NFData1(..))
53import Control.Monad.Base (MonadBase(..), liftBaseDefault)
54import Control.Monad.Catch (MonadThrow, throwM)
55import Control.Monad.IO.Class (MonadIO(..))
56import Control.Monad.Reader.Class (MonadReader(..))
57import Control.Monad.State.Class (MonadState(..))
58import Control.Monad.Trans.Class (MonadTrans(lift))
59import Data.Foldable (Foldable(foldl'), fold)
60import Data.Functor.Identity (Identity(..), runIdentity)
61import Data.Maybe (fromMaybe)
62import Data.Semigroup (Endo(..))
63import GHC.Exts (IsList(..), IsString(..), oneShot)
65 ( Lexeme(Ident), lexP, parens, prec, readPrec, readListPrec
66 , readListPrecDefault)
67import Streamly.Internal.BaseCompat ((#.))
68import Streamly.Internal.Data.Maybe.Strict (Maybe'(..), toMaybe)
69import Streamly.Internal.Data.Stream.StreamK.Type (Stream)
71import qualified Streamly.Internal.Data.Stream.Common as P
72import qualified Streamly.Internal.Data.Stream.StreamD.Generate as D
73import qualified Streamly.Internal.Data.Stream.StreamD.Transform as D
74import qualified Streamly.Internal.Data.Stream.StreamD.Type as D
75import qualified Streamly.Internal.Data.Stream.StreamK.Type as K
77import Prelude hiding (map, mapM, repeat, filter)
79#include "Instances.hs"
83-- >>> :set -fno-warn-deprecations
84-- >>> import qualified Streamly.Prelude as IsStream
86{-# INLINABLE withLocal #-}
87withLocal :: MonadReader r m => (r -> r) -> K.Stream m a -> K.Stream m a
89 K.mkStream $ \st yld sng stp ->
90 let single = local f . sng
91 yieldk a r = local f $ yld a (withLocal f r)
92 in K.foldStream st yieldk single (local f stp) m
94------------------------------------------------------------------------------
96------------------------------------------------------------------------------
98-- | For 'SerialT' streams:
101-- (<>) = 'Streamly.Prelude.serial' -- 'Semigroup'
102-- (>>=) = flip . 'Streamly.Prelude.concatMapWith' 'Streamly.Prelude.serial' -- 'Monad'
105-- A single 'Monad' bind behaves like a @for@ loop:
108-- IsStream.toList $ do
109-- x <- IsStream.fromList [1,2] -- foreach x in stream
114-- Nested monad binds behave like nested @for@ loops:
117-- IsStream.toList $ do
118-- x <- IsStream.fromList [1,2] -- foreach x in stream
119-- y <- IsStream.fromList [3,4] -- foreach y in stream
122-- [(1,3),(1,4),(2,3),(2,4)]
124-- /Since: 0.2.0 ("Streamly")/
127newtype SerialT m a = SerialT {getSerialT :: Stream m a}
128 -- XXX when deriving do we inherit an INLINE?
129 deriving (Semigroup, Monoid)
131-- | A serial IO stream of elements of type @a@. See 'SerialT' documentation
134-- /Since: 0.2.0 ("Streamly")/
137type Serial = SerialT IO
139toStreamK :: SerialT m a -> Stream m a
140toStreamK = getSerialT
142fromStreamK :: Stream m a -> SerialT m a
145------------------------------------------------------------------------------
147------------------------------------------------------------------------------
152cons :: a -> SerialT m a -> SerialT m a
153cons x (SerialT ms) = SerialT $ K.cons x ms
158{-# SPECIALIZE consM :: IO a -> SerialT IO a -> SerialT IO a #-}
159consM :: Monad m => m a -> SerialT m a -> SerialT m a
160consM m (SerialT ms) = SerialT $ K.consM m ms
163-- Generate an infinite stream by repeating a pure value.
165{-# INLINE_NORMAL repeat #-}
166repeat :: Monad m => a -> SerialT m a
167repeat = SerialT . D.toStreamK . D.repeat
169------------------------------------------------------------------------------
171------------------------------------------------------------------------------
174serial :: SerialT m a -> SerialT m a -> SerialT m a
177------------------------------------------------------------------------------
179------------------------------------------------------------------------------
181instance Monad m => Monad (SerialT m) where
184 -- Benchmarks better with StreamD bind and pure:
185 -- toList, filterAllout, *>, *<, >> (~2x)
187 -- pure = SerialT . D.fromStreamD . D.fromPure
188 -- m >>= f = D.fromStreamD $ D.concatMap (D.toStreamD . f) (D.toStreamD m)
190 -- Benchmarks better with CPS bind and pure:
192 -- n binds, breakAfterSome, filterAllIn, state transformer (~2x)
195 (>>=) (SerialT m) f = SerialT $ K.bindWith K.append m (getSerialT . f)
200instance MonadTrans SerialT where
202 lift = SerialT . K.fromEffect
204------------------------------------------------------------------------------
206------------------------------------------------------------------------------
209mapM :: Monad m => (a -> m b) -> SerialT m a -> SerialT m b
210mapM f (SerialT m) = SerialT $ D.toStreamK $ D.mapM f $ D.fromStreamK m
220-- > S.toList $ S.map (+1) $ S.fromList [1,2,3]
226map :: Monad m => (a -> b) -> SerialT m a -> SerialT m b
227map f = mapM (return . f)
229{-# INLINE apSerial #-}
230apSerial :: Monad m => SerialT m (a -> b) -> SerialT m a -> SerialT m b
231apSerial (SerialT m1) (SerialT m2) =
232 SerialT $ D.toStreamK $ D.fromStreamK m1 `D.crossApply` D.fromStreamK m2
234{-# INLINE apSequence #-}
235apSequence :: Monad m => SerialT m a -> SerialT m b -> SerialT m b
236apSequence (SerialT m1) (SerialT m2) =
237 SerialT $ D.toStreamK $ D.fromStreamK m1 `D.crossApplySnd` D.fromStreamK m2
239{-# INLINE apDiscardSnd #-}
240apDiscardSnd :: Monad m => SerialT m a -> SerialT m b -> SerialT m a
241apDiscardSnd (SerialT m1) (SerialT m2) =
242 SerialT $ D.toStreamK $ D.fromStreamK m1 `D.crossApplyFst` D.fromStreamK m2
244-- Note: we need to define all the typeclass operations because we want to
246instance Monad m => Applicative (SerialT m) where
248 pure = SerialT . K.fromPure
252 -- (<*>) = K.apSerial
254 {-# INLINE liftA2 #-}
255 liftA2 f x = (<*>) (fmap f x)
259 -- (*>) = K.apSerialDiscardFst
263 -- (<*) = K.apSerialDiscardSnd
265MONAD_COMMON_INSTANCES(SerialT,)
266LIST_INSTANCES(SerialT)
267NFDATA1_INSTANCE(SerialT)
268FOLDABLE_INSTANCE(SerialT)
269TRAVERSABLE_INSTANCE(SerialT)
271------------------------------------------------------------------------------
273------------------------------------------------------------------------------
275-- | For 'WSerialT' streams:
278-- (<>) = 'Streamly.Prelude.wSerial' -- 'Semigroup'
279-- (>>=) = flip . 'Streamly.Prelude.concatMapWith' 'Streamly.Prelude.wSerial' -- 'Monad'
282-- Note that '<>' is associative only if we disregard the ordering of elements
283-- in the resulting stream.
285-- A single 'Monad' bind behaves like a @for@ loop:
288-- IsStream.toList $ IsStream.fromWSerial $ do
289-- x <- IsStream.fromList [1,2] -- foreach x in stream
294-- Nested monad binds behave like interleaved nested @for@ loops:
297-- IsStream.toList $ IsStream.fromWSerial $ do
298-- x <- IsStream.fromList [1,2] -- foreach x in stream
299-- y <- IsStream.fromList [3,4] -- foreach y in stream
302-- [(1,3),(2,3),(1,4),(2,4)]
304-- It is a result of interleaving all the nested iterations corresponding to
305-- element @1@ in the first stream with all the nested iterations of element
308-- >>> import Streamly.Prelude (wSerial)
309-- >>> IsStream.toList $ IsStream.fromList [(1,3),(1,4)] `IsStream.wSerial` IsStream.fromList [(2,3),(2,4)]
310-- [(1,3),(2,3),(1,4),(2,4)]
312-- The @W@ in the name stands for @wide@ or breadth wise scheduling in
313-- contrast to the depth wise scheduling behavior of 'SerialT'.
315-- /Since: 0.2.0 ("Streamly")/
318newtype WSerialT m a = WSerialT {getWSerialT :: Stream m a}
320instance MonadTrans WSerialT where
322 lift = WSerialT . K.fromEffect
324-- | An interleaving serial IO stream of elements of type @a@. See 'WSerialT'
325-- documentation for more details.
327-- /Since: 0.2.0 ("Streamly")/
330type WSerial = WSerialT IO
332{-# INLINE consMWSerial #-}
333{-# SPECIALIZE consMWSerial :: IO a -> WSerialT IO a -> WSerialT IO a #-}
334consMWSerial :: Monad m => m a -> WSerialT m a -> WSerialT m a
335consMWSerial m (WSerialT ms) = WSerialT $ K.consM m ms
337------------------------------------------------------------------------------
339------------------------------------------------------------------------------
343-- | Interleaves two streams, yielding one element from each stream
344-- alternately. When one stream stops the rest of the other stream is used in
347-- This gives exponential priority to earlier streams than the ones joining
348-- later. Because of exponential weighting it can be used with 'concatMapWith'.
354-- Note that evaluation of @a \`wSerial` b \`wSerial` c@ does not interleave
355-- @a@, @b@ and @c@ with equal priority. This expression is equivalent to @a
356-- \`wSerial` (b \`wSerial` c)@, therefore, it fairly interleaves @a@ with the
357-- result of @b \`wSerial` c@. For example, @Stream.fromList [1,2] \`wSerial`
358-- Stream.fromList [3,4] \`wSerial` Stream.fromList [5,6]@ would result in
359-- [1,3,2,5,4,6]. In other words, the leftmost stream gets the same scheduling
360-- priority as the rest of the streams taken together. The same is true for
361-- each subexpression on the right.
363{-# INLINE wSerial #-}
364wSerial :: WSerialT m a -> WSerialT m a -> WSerialT m a
365wSerial (WSerialT m1) (WSerialT m2) = WSerialT $ K.interleave m1 m2
367{-# INLINE wSerialFst #-}
368wSerialFst :: WSerialT m a -> WSerialT m a -> WSerialT m a
369wSerialFst (WSerialT m1) (WSerialT m2) = WSerialT $ K.interleaveFst m1 m2
371{-# INLINE wSerialMin #-}
372wSerialMin :: WSerialT m a -> WSerialT m a -> WSerialT m a
373wSerialMin (WSerialT m1) (WSerialT m2) = WSerialT $ K.interleaveMin m1 m2
375instance Semigroup (WSerialT m a) where
378------------------------------------------------------------------------------
380------------------------------------------------------------------------------
382instance Monoid (WSerialT m a) where
383 mempty = WSerialT K.nil
386{-# INLINE apWSerial #-}
387apWSerial :: WSerialT m (a -> b) -> WSerialT m a -> WSerialT m b
388apWSerial (WSerialT m1) (WSerialT m2) =
389 let f x1 = K.concatMapWith K.interleave (K.fromPure . x1) m2
390 in WSerialT $ K.concatMapWith K.interleave f m1
392instance Monad m => Applicative (WSerialT m) where
394 pure = WSerialT . K.fromPure
398------------------------------------------------------------------------------
400------------------------------------------------------------------------------
402instance Monad m => Monad (WSerialT m) where
405 (>>=) (WSerialT m) f = WSerialT $ K.bindWith K.interleave m (getWSerialT . f)
407------------------------------------------------------------------------------
409------------------------------------------------------------------------------
411MONAD_COMMON_INSTANCES(WSerialT,)
412LIST_INSTANCES(WSerialT)
413NFDATA1_INSTANCE(WSerialT)
414FOLDABLE_INSTANCE(WSerialT)
415TRAVERSABLE_INSTANCE(WSerialT)
417------------------------------------------------------------------------------
419------------------------------------------------------------------------------
421-- | Build a stream by unfolding a /monadic/ step function starting from a
422-- seed. The step function returns the next element in the stream and the next
423-- seed value. When it is done it returns 'Nothing' and the stream ends. For
429-- then return Nothing
430-- else print b >> return (Just (b, b + 1))
431-- in drain $ unfoldrM f 0
442{-# INLINE unfoldrM #-}
443unfoldrM :: Monad m => (b -> m (Maybe (a, b))) -> b -> SerialT m a
444unfoldrM 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