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
51#if !(MIN_VERSION_base(4,18,0))
52import Control.Applicative (liftA2)
54import Control.DeepSeq (NFData(..), NFData1(..))
55#if !(MIN_VERSION_transformers(0,6,0))
56import 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(..))
67import GHC.Exts (IsList(..), IsString(..), oneShot)
69 ( Lexeme(Ident), lexP, parens, prec, readPrec, readListPrec
70 , readListPrecDefault)
71import Streamly.Internal.BaseCompat ((#.))
72import Streamly.Internal.Data.Maybe.Strict (Maybe'(..), toMaybe)
73import Streamly.Internal.Data.StreamK (Stream)
75import qualified Streamly.Internal.Data.Stream.Common as P
76import qualified Streamly.Internal.Data.Stream as D
77import qualified Streamly.Internal.Data.StreamK as K
79import Prelude hiding (map, mapM, repeat, filter)
81#include "Instances.hs"
85-- >>> :set -fno-warn-deprecations
86-- >>> import qualified Streamly.Prelude as IsStream
88{-# INLINABLE withLocal #-}
89withLocal :: MonadReader r m => (r -> r) -> K.Stream m a -> K.Stream m a
91 K.mkStream $ \st yld sng stp ->
92 let single = local f . sng
93 yieldk a r = local f $ yld a (withLocal f r)
94 in K.foldStream st yieldk single (local f stp) m
96------------------------------------------------------------------------------
98------------------------------------------------------------------------------
100-- | For 'SerialT' streams:
103-- (<>) = 'Streamly.Prelude.serial' -- 'Semigroup'
104-- (>>=) = flip . 'Streamly.Prelude.concatMapWith' 'Streamly.Prelude.serial' -- 'Monad'
107-- A single 'Monad' bind behaves like a @for@ loop:
110-- IsStream.toList $ do
111-- x <- IsStream.fromList [1,2] -- foreach x in stream
116-- Nested monad binds behave like nested @for@ loops:
119-- IsStream.toList $ do
120-- x <- IsStream.fromList [1,2] -- foreach x in stream
121-- y <- IsStream.fromList [3,4] -- foreach y in stream
124-- [(1,3),(1,4),(2,3),(2,4)]
126-- /Since: 0.2.0 ("Streamly")/
129newtype SerialT m a = SerialT {getSerialT :: Stream m a}
130 -- XXX when deriving do we inherit an INLINE?
131 deriving (Semigroup, Monoid)
133-- | A serial IO stream of elements of type @a@. See 'SerialT' documentation
136-- /Since: 0.2.0 ("Streamly")/
139type Serial = SerialT IO
141toStreamK :: SerialT m a -> Stream m a
142toStreamK = getSerialT
144fromStreamK :: Stream m a -> SerialT m a
147------------------------------------------------------------------------------
149------------------------------------------------------------------------------
154cons :: a -> SerialT m a -> SerialT m a
155cons x (SerialT ms) = SerialT $ K.cons x ms
160{-# SPECIALIZE consM :: IO a -> SerialT IO a -> SerialT IO a #-}
161consM :: Monad m => m a -> SerialT m a -> SerialT m a
162consM m (SerialT ms) = SerialT $ K.consM m ms
165-- Generate an infinite stream by repeating a pure value.
167{-# INLINE_NORMAL repeat #-}
168repeat :: Monad m => a -> SerialT m a
169repeat = SerialT . D.toStreamK . D.repeat
171------------------------------------------------------------------------------
173------------------------------------------------------------------------------
176serial :: SerialT m a -> SerialT m a -> SerialT m a
179------------------------------------------------------------------------------
181------------------------------------------------------------------------------
183instance Monad m => Monad (SerialT m) where
186 -- Benchmarks better with StreamD bind and pure:
187 -- toList, filterAllout, *>, *<, >> (~2x)
189 -- pure = SerialT . D.fromStreamD . D.fromPure
190 -- m >>= f = D.fromStreamD $ D.concatMap (D.toStreamD . f) (D.toStreamD m)
192 -- Benchmarks better with CPS bind and pure:
194 -- n binds, breakAfterSome, filterAllIn, state transformer (~2x)
197 (>>=) (SerialT m) f = SerialT $ K.bindWith K.append m (getSerialT . f)
202instance MonadTrans SerialT where
204 lift = SerialT . K.fromEffect
206------------------------------------------------------------------------------
208------------------------------------------------------------------------------
211mapM :: Monad m => (a -> m b) -> SerialT m a -> SerialT m b
212mapM f (SerialT m) = SerialT $ D.toStreamK $ D.mapM f $ D.fromStreamK m
222-- > S.toList $ S.map (+1) $ S.fromList [1,2,3]
228map :: Monad m => (a -> b) -> SerialT m a -> SerialT m b
229map f = mapM (return . f)
231{-# INLINE apSerial #-}
232apSerial :: Monad m => SerialT m (a -> b) -> SerialT m a -> SerialT m b
233apSerial (SerialT m1) (SerialT m2) =
234 SerialT $ D.toStreamK $ D.fromStreamK m1 `D.crossApply` D.fromStreamK m2
236{-# INLINE apSequence #-}
237apSequence :: Monad m => SerialT m a -> SerialT m b -> SerialT m b
238apSequence (SerialT m1) (SerialT m2) =
239 SerialT $ D.toStreamK $ D.fromStreamK m1 `D.crossApplySnd` D.fromStreamK m2
241{-# INLINE apDiscardSnd #-}
242apDiscardSnd :: Monad m => SerialT m a -> SerialT m b -> SerialT m a
243apDiscardSnd (SerialT m1) (SerialT m2) =
244 SerialT $ D.toStreamK $ D.fromStreamK m1 `D.crossApplyFst` D.fromStreamK m2
246-- Note: we need to define all the typeclass operations because we want to
248instance Monad m => Applicative (SerialT m) where
250 pure = SerialT . K.fromPure
254 -- (<*>) = K.apSerial
256 {-# INLINE liftA2 #-}
257 liftA2 f x = (<*>) (fmap f x)
261 -- (*>) = K.apSerialDiscardFst
265 -- (<*) = K.apSerialDiscardSnd
267MONAD_COMMON_INSTANCES(SerialT,)
268LIST_INSTANCES(SerialT)
269NFDATA1_INSTANCE(SerialT)
270FOLDABLE_INSTANCE(SerialT)
271TRAVERSABLE_INSTANCE(SerialT)
273------------------------------------------------------------------------------
275------------------------------------------------------------------------------
277-- | For 'WSerialT' streams:
280-- (<>) = 'Streamly.Prelude.wSerial' -- 'Semigroup'
281-- (>>=) = flip . 'Streamly.Prelude.concatMapWith' 'Streamly.Prelude.wSerial' -- 'Monad'
284-- Note that '<>' is associative only if we disregard the ordering of elements
285-- in the resulting stream.
287-- A single 'Monad' bind behaves like a @for@ loop:
290-- IsStream.toList $ IsStream.fromWSerial $ do
291-- x <- IsStream.fromList [1,2] -- foreach x in stream
296-- Nested monad binds behave like interleaved nested @for@ loops:
299-- IsStream.toList $ IsStream.fromWSerial $ do
300-- x <- IsStream.fromList [1,2] -- foreach x in stream
301-- y <- IsStream.fromList [3,4] -- foreach y in stream
304-- [(1,3),(2,3),(1,4),(2,4)]
306-- It is a result of interleaving all the nested iterations corresponding to
307-- element @1@ in the first stream with all the nested iterations of element
310-- >>> import Streamly.Prelude (wSerial)
311-- >>> IsStream.toList $ IsStream.fromList [(1,3),(1,4)] `IsStream.wSerial` IsStream.fromList [(2,3),(2,4)]
312-- [(1,3),(2,3),(1,4),(2,4)]
314-- The @W@ in the name stands for @wide@ or breadth wise scheduling in
315-- contrast to the depth wise scheduling behavior of 'SerialT'.
317-- /Since: 0.2.0 ("Streamly")/
320newtype WSerialT m a = WSerialT {getWSerialT :: Stream m a}
322instance MonadTrans WSerialT where
324 lift = WSerialT . K.fromEffect
326-- | An interleaving serial IO stream of elements of type @a@. See 'WSerialT'
327-- documentation for more details.
329-- /Since: 0.2.0 ("Streamly")/
332type WSerial = WSerialT IO
334{-# INLINE consMWSerial #-}
335{-# SPECIALIZE consMWSerial :: IO a -> WSerialT IO a -> WSerialT IO a #-}
336consMWSerial :: Monad m => m a -> WSerialT m a -> WSerialT m a
337consMWSerial m (WSerialT ms) = WSerialT $ K.consM m ms
339------------------------------------------------------------------------------
341------------------------------------------------------------------------------
345-- | Interleaves two streams, yielding one element from each stream
346-- alternately. When one stream stops the rest of the other stream is used in
349-- This gives exponential priority to earlier streams than the ones joining
350-- later. Because of exponential weighting it can be used with 'concatMapWith'.
356-- Note that evaluation of @a \`wSerial` b \`wSerial` c@ does not interleave
357-- @a@, @b@ and @c@ with equal priority. This expression is equivalent to @a
358-- \`wSerial` (b \`wSerial` c)@, therefore, it fairly interleaves @a@ with the
359-- result of @b \`wSerial` c@. For example, @Stream.fromList [1,2] \`wSerial`
360-- Stream.fromList [3,4] \`wSerial` Stream.fromList [5,6]@ would result in
361-- [1,3,2,5,4,6]. In other words, the leftmost stream gets the same scheduling
362-- priority as the rest of the streams taken together. The same is true for
363-- each subexpression on the right.
365{-# INLINE wSerial #-}
366wSerial :: WSerialT m a -> WSerialT m a -> WSerialT m a
367wSerial (WSerialT m1) (WSerialT m2) = WSerialT $ K.interleave m1 m2
369{-# INLINE wSerialFst #-}
370wSerialFst :: WSerialT m a -> WSerialT m a -> WSerialT m a
371wSerialFst (WSerialT m1) (WSerialT m2) = WSerialT $ K.interleaveFst m1 m2
373{-# INLINE wSerialMin #-}
374wSerialMin :: WSerialT m a -> WSerialT m a -> WSerialT m a
375wSerialMin (WSerialT m1) (WSerialT m2) = WSerialT $ K.interleaveMin m1 m2
377instance Semigroup (WSerialT m a) where
380------------------------------------------------------------------------------
382------------------------------------------------------------------------------
384instance Monoid (WSerialT m a) where
385 mempty = WSerialT K.nil
388{-# INLINE apWSerial #-}
389apWSerial :: WSerialT m (a -> b) -> WSerialT m a -> WSerialT m b
390apWSerial (WSerialT m1) (WSerialT m2) =
391 let f x1 = K.concatMapWith K.interleave (K.fromPure . x1) m2
392 in WSerialT $ K.concatMapWith K.interleave f m1
394instance Monad m => Applicative (WSerialT m) where
396 pure = WSerialT . K.fromPure
400------------------------------------------------------------------------------
402------------------------------------------------------------------------------
404instance Monad m => Monad (WSerialT m) where
407 (>>=) (WSerialT m) f = WSerialT $ K.bindWith K.interleave m (getWSerialT . f)
409------------------------------------------------------------------------------
411------------------------------------------------------------------------------
413#if !(MIN_VERSION_transformers(0,6,0))
414instance (MonadBase b m, Monad m) => MonadBase b (SerialT m) where
415 liftBase = liftBaseDefault
418MONAD_COMMON_INSTANCES(WSerialT,)
419LIST_INSTANCES(WSerialT)
420NFDATA1_INSTANCE(WSerialT)
421FOLDABLE_INSTANCE(WSerialT)
422TRAVERSABLE_INSTANCE(WSerialT)
424------------------------------------------------------------------------------
426------------------------------------------------------------------------------
428-- | Build a stream by unfolding a /monadic/ step function starting from a
429-- seed. The step function returns the next element in the stream and the next
430-- seed value. When it is done it returns 'Nothing' and the stream ends. For
436-- then return Nothing
437-- else print b >> return (Just (b, b + 1))
438-- in drain $ unfoldrM f 0
449{-# INLINE unfoldrM #-}
450unfoldrM :: Monad m => (b -> m (Maybe (a, b))) -> b -> SerialT m a
451unfoldrM 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