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.Stream.StreamK.Type (Stream)
75import qualified Streamly.Internal.Data.Stream.Common as P
76import qualified Streamly.Internal.Data.Stream.StreamD.Generate as D
77import qualified Streamly.Internal.Data.Stream.StreamD.Transform as D
78import qualified Streamly.Internal.Data.Stream.StreamD.Type as D
79import qualified Streamly.Internal.Data.Stream.StreamK.Type as K
81import Prelude hiding (map, mapM, repeat, filter)
83#include "Instances.hs"
87-- >>> :set -fno-warn-deprecations
88-- >>> import qualified Streamly.Prelude as IsStream
90{-# INLINABLE withLocal #-}
91withLocal :: MonadReader r m => (r -> r) -> K.Stream m a -> K.Stream m a
93 K.mkStream $ \st yld sng stp ->
94 let single = local f . sng
95 yieldk a r = local f $ yld a (withLocal f r)
96 in K.foldStream st yieldk single (local f stp) m
98------------------------------------------------------------------------------
100------------------------------------------------------------------------------
102-- | For 'SerialT' streams:
105-- (<>) = 'Streamly.Prelude.serial' -- 'Semigroup'
106-- (>>=) = flip . 'Streamly.Prelude.concatMapWith' 'Streamly.Prelude.serial' -- 'Monad'
109-- A single 'Monad' bind behaves like a @for@ loop:
112-- IsStream.toList $ do
113-- x <- IsStream.fromList [1,2] -- foreach x in stream
118-- Nested monad binds behave like nested @for@ loops:
121-- IsStream.toList $ do
122-- x <- IsStream.fromList [1,2] -- foreach x in stream
123-- y <- IsStream.fromList [3,4] -- foreach y in stream
126-- [(1,3),(1,4),(2,3),(2,4)]
128-- /Since: 0.2.0 ("Streamly")/
131newtype SerialT m a = SerialT {getSerialT :: Stream m a}
132 -- XXX when deriving do we inherit an INLINE?
133 deriving (Semigroup, Monoid)
135-- | A serial IO stream of elements of type @a@. See 'SerialT' documentation
138-- /Since: 0.2.0 ("Streamly")/
141type Serial = SerialT IO
143toStreamK :: SerialT m a -> Stream m a
144toStreamK = getSerialT
146fromStreamK :: Stream m a -> SerialT m a
149------------------------------------------------------------------------------
151------------------------------------------------------------------------------
156cons :: a -> SerialT m a -> SerialT m a
157cons x (SerialT ms) = SerialT $ K.cons x ms
162{-# SPECIALIZE consM :: IO a -> SerialT IO a -> SerialT IO a #-}
163consM :: Monad m => m a -> SerialT m a -> SerialT m a
164consM m (SerialT ms) = SerialT $ K.consM m ms
167-- Generate an infinite stream by repeating a pure value.
169{-# INLINE_NORMAL repeat #-}
170repeat :: Monad m => a -> SerialT m a
171repeat = SerialT . D.toStreamK . D.repeat
173------------------------------------------------------------------------------
175------------------------------------------------------------------------------
178serial :: SerialT m a -> SerialT m a -> SerialT m a
181------------------------------------------------------------------------------
183------------------------------------------------------------------------------
185instance Monad m => Monad (SerialT m) where
188 -- Benchmarks better with StreamD bind and pure:
189 -- toList, filterAllout, *>, *<, >> (~2x)
191 -- pure = SerialT . D.fromStreamD . D.fromPure
192 -- m >>= f = D.fromStreamD $ D.concatMap (D.toStreamD . f) (D.toStreamD m)
194 -- Benchmarks better with CPS bind and pure:
196 -- n binds, breakAfterSome, filterAllIn, state transformer (~2x)
199 (>>=) (SerialT m) f = SerialT $ K.bindWith K.append m (getSerialT . f)
204instance MonadTrans SerialT where
206 lift = SerialT . K.fromEffect
208------------------------------------------------------------------------------
210------------------------------------------------------------------------------
213mapM :: Monad m => (a -> m b) -> SerialT m a -> SerialT m b
214mapM f (SerialT m) = SerialT $ D.toStreamK $ D.mapM f $ D.fromStreamK m
224-- > S.toList $ S.map (+1) $ S.fromList [1,2,3]
230map :: Monad m => (a -> b) -> SerialT m a -> SerialT m b
231map f = mapM (return . f)
233{-# INLINE apSerial #-}
234apSerial :: Monad m => SerialT m (a -> b) -> SerialT m a -> SerialT m b
235apSerial (SerialT m1) (SerialT m2) =
236 SerialT $ D.toStreamK $ D.fromStreamK m1 `D.crossApply` D.fromStreamK m2
238{-# INLINE apSequence #-}
239apSequence :: Monad m => SerialT m a -> SerialT m b -> SerialT m b
240apSequence (SerialT m1) (SerialT m2) =
241 SerialT $ D.toStreamK $ D.fromStreamK m1 `D.crossApplySnd` D.fromStreamK m2
243{-# INLINE apDiscardSnd #-}
244apDiscardSnd :: Monad m => SerialT m a -> SerialT m b -> SerialT m a
245apDiscardSnd (SerialT m1) (SerialT m2) =
246 SerialT $ D.toStreamK $ D.fromStreamK m1 `D.crossApplyFst` D.fromStreamK m2
248-- Note: we need to define all the typeclass operations because we want to
250instance Monad m => Applicative (SerialT m) where
252 pure = SerialT . K.fromPure
256 -- (<*>) = K.apSerial
258 {-# INLINE liftA2 #-}
259 liftA2 f x = (<*>) (fmap f x)
263 -- (*>) = K.apSerialDiscardFst
267 -- (<*) = K.apSerialDiscardSnd
269MONAD_COMMON_INSTANCES(SerialT,)
270LIST_INSTANCES(SerialT)
271NFDATA1_INSTANCE(SerialT)
272FOLDABLE_INSTANCE(SerialT)
273TRAVERSABLE_INSTANCE(SerialT)
275------------------------------------------------------------------------------
277------------------------------------------------------------------------------
279-- | For 'WSerialT' streams:
282-- (<>) = 'Streamly.Prelude.wSerial' -- 'Semigroup'
283-- (>>=) = flip . 'Streamly.Prelude.concatMapWith' 'Streamly.Prelude.wSerial' -- 'Monad'
286-- Note that '<>' is associative only if we disregard the ordering of elements
287-- in the resulting stream.
289-- A single 'Monad' bind behaves like a @for@ loop:
292-- IsStream.toList $ IsStream.fromWSerial $ do
293-- x <- IsStream.fromList [1,2] -- foreach x in stream
298-- Nested monad binds behave like interleaved nested @for@ loops:
301-- IsStream.toList $ IsStream.fromWSerial $ do
302-- x <- IsStream.fromList [1,2] -- foreach x in stream
303-- y <- IsStream.fromList [3,4] -- foreach y in stream
306-- [(1,3),(2,3),(1,4),(2,4)]
308-- It is a result of interleaving all the nested iterations corresponding to
309-- element @1@ in the first stream with all the nested iterations of element
312-- >>> import Streamly.Prelude (wSerial)
313-- >>> IsStream.toList $ IsStream.fromList [(1,3),(1,4)] `IsStream.wSerial` IsStream.fromList [(2,3),(2,4)]
314-- [(1,3),(2,3),(1,4),(2,4)]
316-- The @W@ in the name stands for @wide@ or breadth wise scheduling in
317-- contrast to the depth wise scheduling behavior of 'SerialT'.
319-- /Since: 0.2.0 ("Streamly")/
322newtype WSerialT m a = WSerialT {getWSerialT :: Stream m a}
324instance MonadTrans WSerialT where
326 lift = WSerialT . K.fromEffect
328-- | An interleaving serial IO stream of elements of type @a@. See 'WSerialT'
329-- documentation for more details.
331-- /Since: 0.2.0 ("Streamly")/
334type WSerial = WSerialT IO
336{-# INLINE consMWSerial #-}
337{-# SPECIALIZE consMWSerial :: IO a -> WSerialT IO a -> WSerialT IO a #-}
338consMWSerial :: Monad m => m a -> WSerialT m a -> WSerialT m a
339consMWSerial m (WSerialT ms) = WSerialT $ K.consM m ms
341------------------------------------------------------------------------------
343------------------------------------------------------------------------------
347-- | Interleaves two streams, yielding one element from each stream
348-- alternately. When one stream stops the rest of the other stream is used in
351-- This gives exponential priority to earlier streams than the ones joining
352-- later. Because of exponential weighting it can be used with 'concatMapWith'.
358-- Note that evaluation of @a \`wSerial` b \`wSerial` c@ does not interleave
359-- @a@, @b@ and @c@ with equal priority. This expression is equivalent to @a
360-- \`wSerial` (b \`wSerial` c)@, therefore, it fairly interleaves @a@ with the
361-- result of @b \`wSerial` c@. For example, @Stream.fromList [1,2] \`wSerial`
362-- Stream.fromList [3,4] \`wSerial` Stream.fromList [5,6]@ would result in
363-- [1,3,2,5,4,6]. In other words, the leftmost stream gets the same scheduling
364-- priority as the rest of the streams taken together. The same is true for
365-- each subexpression on the right.
367{-# INLINE wSerial #-}
368wSerial :: WSerialT m a -> WSerialT m a -> WSerialT m a
369wSerial (WSerialT m1) (WSerialT m2) = WSerialT $ K.interleave m1 m2
371{-# INLINE wSerialFst #-}
372wSerialFst :: WSerialT m a -> WSerialT m a -> WSerialT m a
373wSerialFst (WSerialT m1) (WSerialT m2) = WSerialT $ K.interleaveFst m1 m2
375{-# INLINE wSerialMin #-}
376wSerialMin :: WSerialT m a -> WSerialT m a -> WSerialT m a
377wSerialMin (WSerialT m1) (WSerialT m2) = WSerialT $ K.interleaveMin m1 m2
379instance Semigroup (WSerialT m a) where
382------------------------------------------------------------------------------
384------------------------------------------------------------------------------
386instance Monoid (WSerialT m a) where
387 mempty = WSerialT K.nil
390{-# INLINE apWSerial #-}
391apWSerial :: WSerialT m (a -> b) -> WSerialT m a -> WSerialT m b
392apWSerial (WSerialT m1) (WSerialT m2) =
393 let f x1 = K.concatMapWith K.interleave (K.fromPure . x1) m2
394 in WSerialT $ K.concatMapWith K.interleave f m1
396instance Monad m => Applicative (WSerialT m) where
398 pure = WSerialT . K.fromPure
402------------------------------------------------------------------------------
404------------------------------------------------------------------------------
406instance Monad m => Monad (WSerialT m) where
409 (>>=) (WSerialT m) f = WSerialT $ K.bindWith K.interleave m (getWSerialT . f)
411------------------------------------------------------------------------------
413------------------------------------------------------------------------------
415#if !(MIN_VERSION_transformers(0,6,0))
416instance (MonadBase b m, Monad m) => MonadBase b (SerialT m) where
417 liftBase = liftBaseDefault
420MONAD_COMMON_INSTANCES(WSerialT,)
421LIST_INSTANCES(WSerialT)
422NFDATA1_INSTANCE(WSerialT)
423FOLDABLE_INSTANCE(WSerialT)
424TRAVERSABLE_INSTANCE(WSerialT)
426------------------------------------------------------------------------------
428------------------------------------------------------------------------------
430-- | Build a stream by unfolding a /monadic/ step function starting from a
431-- seed. The step function returns the next element in the stream and the next
432-- seed value. When it is done it returns 'Nothing' and the stream ends. For
438-- then return Nothing
439-- else print b >> return (Just (b, b + 1))
440-- in drain $ unfoldrM f 0
451{-# INLINE unfoldrM #-}
452unfoldrM :: Monad m => (b -> m (Maybe (a, b))) -> b -> SerialT m a
453unfoldrM 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