1{-# LANGUAGE UndecidableInstances #-}
2{-# OPTIONS_GHC -Wno-deprecations #-}
5-- Module : Streamly.Internal.Data.Stream.Serial
6-- Copyright : (c) 2017 Composewell Technologies
9-- Maintainer : streamly@composewell.com
10-- Stability : experimental
13-- To run examples in this module:
15-- >>> import qualified Streamly.Prelude as Stream
17module Streamly.Internal.Data.Stream.Serial {-# DEPRECATED "Please use \"Streamly.Internal.Data.Stream\" from streamly-core package instead." #-}
19 -- * Serial appending stream
26 -- * Serial interleaving stream
50import Control.Applicative (liftA2)
51import Control.DeepSeq (NFData(..), NFData1(..))
52import Control.Monad.Base (MonadBase(..), liftBaseDefault)
53import Control.Monad.Catch (MonadThrow, throwM)
54import Control.Monad.IO.Class (MonadIO(..))
55import Control.Monad.Reader.Class (MonadReader(..))
56import Control.Monad.State.Class (MonadState(..))
57import Control.Monad.Trans.Class (MonadTrans(lift))
58import Data.Foldable (Foldable(foldl'), fold)
59import Data.Functor.Identity (Identity(..), runIdentity)
60import Data.Maybe (fromMaybe)
61import Data.Semigroup (Endo(..))
62import GHC.Exts (IsList(..), IsString(..), oneShot)
64 ( Lexeme(Ident), lexP, parens, prec, readPrec, readListPrec
65 , readListPrecDefault)
66import Streamly.Internal.BaseCompat ((#.))
67import Streamly.Internal.Data.Maybe.Strict (Maybe'(..), toMaybe)
68import Streamly.Internal.Data.Stream.StreamK.Type (Stream)
70import qualified Streamly.Internal.Data.Stream.Common as P
71import qualified Streamly.Internal.Data.Stream.StreamD.Generate as D
72import qualified Streamly.Internal.Data.Stream.StreamD.Transform as D
73import qualified Streamly.Internal.Data.Stream.StreamD.Type as D
74import qualified Streamly.Internal.Data.Stream.StreamK.Type as K
76import Prelude hiding (map, mapM, repeat, filter)
78#include "Instances.hs"
82-- >>> :set -fno-warn-deprecations
83-- >>> import qualified Streamly.Prelude as IsStream
85{-# INLINABLE withLocal #-}
86withLocal :: MonadReader r m => (r -> r) -> K.Stream m a -> K.Stream m a
88 K.mkStream $ \st yld sng stp ->
89 let single = local f . sng
90 yieldk a r = local f $ yld a (withLocal f r)
91 in K.foldStream st yieldk single (local f stp) m
93------------------------------------------------------------------------------
95------------------------------------------------------------------------------
97-- | For 'SerialT' streams:
100-- (<>) = 'Streamly.Prelude.serial' -- 'Semigroup'
101-- (>>=) = flip . 'Streamly.Prelude.concatMapWith' 'Streamly.Prelude.serial' -- 'Monad'
104-- A single 'Monad' bind behaves like a @for@ loop:
107-- IsStream.toList $ do
108-- x <- IsStream.fromList [1,2] -- foreach x in stream
113-- Nested monad binds behave like nested @for@ loops:
116-- IsStream.toList $ do
117-- x <- IsStream.fromList [1,2] -- foreach x in stream
118-- y <- IsStream.fromList [3,4] -- foreach y in stream
121-- [(1,3),(1,4),(2,3),(2,4)]
123-- /Since: 0.2.0 ("Streamly")/
126newtype SerialT m a = SerialT {getSerialT :: Stream m a}
127 -- XXX when deriving do we inherit an INLINE?
128 deriving (Semigroup, Monoid)
130-- | A serial IO stream of elements of type @a@. See 'SerialT' documentation
133-- /Since: 0.2.0 ("Streamly")/
136type Serial = SerialT IO
138toStreamK :: SerialT m a -> Stream m a
139toStreamK = getSerialT
141fromStreamK :: Stream m a -> SerialT m a
144------------------------------------------------------------------------------
146------------------------------------------------------------------------------
151cons :: a -> SerialT m a -> SerialT m a
152cons x (SerialT ms) = SerialT $ K.cons x ms
157{-# SPECIALIZE consM :: IO a -> SerialT IO a -> SerialT IO a #-}
158consM :: Monad m => m a -> SerialT m a -> SerialT m a
159consM m (SerialT ms) = SerialT $ K.consM m ms
162-- Generate an infinite stream by repeating a pure value.
164{-# INLINE_NORMAL repeat #-}
165repeat :: Monad m => a -> SerialT m a
166repeat = SerialT . D.toStreamK . D.repeat
168------------------------------------------------------------------------------
170------------------------------------------------------------------------------
173serial :: SerialT m a -> SerialT m a -> SerialT m a
176------------------------------------------------------------------------------
178------------------------------------------------------------------------------
180instance Monad m => Monad (SerialT m) where
183 -- Benchmarks better with StreamD bind and pure:
184 -- toList, filterAllout, *>, *<, >> (~2x)
186 -- pure = SerialT . D.fromStreamD . D.fromPure
187 -- m >>= f = D.fromStreamD $ D.concatMap (D.toStreamD . f) (D.toStreamD m)
189 -- Benchmarks better with CPS bind and pure:
191 -- n binds, breakAfterSome, filterAllIn, state transformer (~2x)
194 (>>=) (SerialT m) f = SerialT $ K.bindWith K.append m (getSerialT . f)
199instance MonadTrans SerialT where
201 lift = SerialT . K.fromEffect
203------------------------------------------------------------------------------
205------------------------------------------------------------------------------
208mapM :: Monad m => (a -> m b) -> SerialT m a -> SerialT m b
209mapM f (SerialT m) = SerialT $ D.toStreamK $ D.mapM f $ D.fromStreamK m
219-- > S.toList $ S.map (+1) $ S.fromList [1,2,3]
225map :: Monad m => (a -> b) -> SerialT m a -> SerialT m b
226map f = mapM (return . f)
228{-# INLINE apSerial #-}
229apSerial :: Monad m => SerialT m (a -> b) -> SerialT m a -> SerialT m b
230apSerial (SerialT m1) (SerialT m2) =
231 SerialT $ D.toStreamK $ D.fromStreamK m1 `D.crossApply` D.fromStreamK m2
233{-# INLINE apSequence #-}
234apSequence :: Monad m => SerialT m a -> SerialT m b -> SerialT m b
235apSequence (SerialT m1) (SerialT m2) =
236 SerialT $ D.toStreamK $ D.fromStreamK m1 `D.crossApplySnd` D.fromStreamK m2
238{-# INLINE apDiscardSnd #-}
239apDiscardSnd :: Monad m => SerialT m a -> SerialT m b -> SerialT m a
240apDiscardSnd (SerialT m1) (SerialT m2) =
241 SerialT $ D.toStreamK $ D.fromStreamK m1 `D.crossApplyFst` D.fromStreamK m2
243-- Note: we need to define all the typeclass operations because we want to
245instance Monad m => Applicative (SerialT m) where
247 pure = SerialT . K.fromPure
251 -- (<*>) = K.apSerial
253 {-# INLINE liftA2 #-}
254 liftA2 f x = (<*>) (fmap f x)
258 -- (*>) = K.apSerialDiscardFst
262 -- (<*) = K.apSerialDiscardSnd
264MONAD_COMMON_INSTANCES(SerialT,)
265LIST_INSTANCES(SerialT)
266NFDATA1_INSTANCE(SerialT)
267FOLDABLE_INSTANCE(SerialT)
268TRAVERSABLE_INSTANCE(SerialT)
270------------------------------------------------------------------------------
272------------------------------------------------------------------------------
274-- | For 'WSerialT' streams:
277-- (<>) = 'Streamly.Prelude.wSerial' -- 'Semigroup'
278-- (>>=) = flip . 'Streamly.Prelude.concatMapWith' 'Streamly.Prelude.wSerial' -- 'Monad'
281-- Note that '<>' is associative only if we disregard the ordering of elements
282-- in the resulting stream.
284-- A single 'Monad' bind behaves like a @for@ loop:
287-- IsStream.toList $ IsStream.fromWSerial $ do
288-- x <- IsStream.fromList [1,2] -- foreach x in stream
293-- Nested monad binds behave like interleaved nested @for@ loops:
296-- IsStream.toList $ IsStream.fromWSerial $ do
297-- x <- IsStream.fromList [1,2] -- foreach x in stream
298-- y <- IsStream.fromList [3,4] -- foreach y in stream
301-- [(1,3),(2,3),(1,4),(2,4)]
303-- It is a result of interleaving all the nested iterations corresponding to
304-- element @1@ in the first stream with all the nested iterations of element
307-- >>> import Streamly.Prelude (wSerial)
308-- >>> IsStream.toList $ IsStream.fromList [(1,3),(1,4)] `IsStream.wSerial` IsStream.fromList [(2,3),(2,4)]
309-- [(1,3),(2,3),(1,4),(2,4)]
311-- The @W@ in the name stands for @wide@ or breadth wise scheduling in
312-- contrast to the depth wise scheduling behavior of 'SerialT'.
314-- /Since: 0.2.0 ("Streamly")/
317newtype WSerialT m a = WSerialT {getWSerialT :: Stream m a}
319instance MonadTrans WSerialT where
321 lift = WSerialT . K.fromEffect
323-- | An interleaving serial IO stream of elements of type @a@. See 'WSerialT'
324-- documentation for more details.
326-- /Since: 0.2.0 ("Streamly")/
329type WSerial = WSerialT IO
331{-# INLINE consMWSerial #-}
332{-# SPECIALIZE consMWSerial :: IO a -> WSerialT IO a -> WSerialT IO a #-}
333consMWSerial :: Monad m => m a -> WSerialT m a -> WSerialT m a
334consMWSerial m (WSerialT ms) = WSerialT $ K.consM m ms
336------------------------------------------------------------------------------
338------------------------------------------------------------------------------
342-- | Interleaves two streams, yielding one element from each stream
343-- alternately. When one stream stops the rest of the other stream is used in
346-- This gives exponential priority to earlier streams than the ones joining
347-- later. Because of exponential weighting it can be used with 'concatMapWith'.
353-- Note that evaluation of @a \`wSerial` b \`wSerial` c@ does not interleave
354-- @a@, @b@ and @c@ with equal priority. This expression is equivalent to @a
355-- \`wSerial` (b \`wSerial` c)@, therefore, it fairly interleaves @a@ with the
356-- result of @b \`wSerial` c@. For example, @Stream.fromList [1,2] \`wSerial`
357-- Stream.fromList [3,4] \`wSerial` Stream.fromList [5,6]@ would result in
358-- [1,3,2,5,4,6]. In other words, the leftmost stream gets the same scheduling
359-- priority as the rest of the streams taken together. The same is true for
360-- each subexpression on the right.
362{-# INLINE wSerial #-}
363wSerial :: WSerialT m a -> WSerialT m a -> WSerialT m a
364wSerial (WSerialT m1) (WSerialT m2) = WSerialT $ K.interleave m1 m2
366{-# INLINE wSerialFst #-}
367wSerialFst :: WSerialT m a -> WSerialT m a -> WSerialT m a
368wSerialFst (WSerialT m1) (WSerialT m2) = WSerialT $ K.interleaveFst m1 m2
370{-# INLINE wSerialMin #-}
371wSerialMin :: WSerialT m a -> WSerialT m a -> WSerialT m a
372wSerialMin (WSerialT m1) (WSerialT m2) = WSerialT $ K.interleaveMin m1 m2
374instance Semigroup (WSerialT m a) where
377------------------------------------------------------------------------------
379------------------------------------------------------------------------------
381instance Monoid (WSerialT m a) where
382 mempty = WSerialT K.nil
385{-# INLINE apWSerial #-}
386apWSerial :: WSerialT m (a -> b) -> WSerialT m a -> WSerialT m b
387apWSerial (WSerialT m1) (WSerialT m2) =
388 let f x1 = K.concatMapWith K.interleave (K.fromPure . x1) m2
389 in WSerialT $ K.concatMapWith K.interleave f m1
391instance Monad m => Applicative (WSerialT m) where
393 pure = WSerialT . K.fromPure
397------------------------------------------------------------------------------
399------------------------------------------------------------------------------
401instance Monad m => Monad (WSerialT m) where
404 (>>=) (WSerialT m) f = WSerialT $ K.bindWith K.interleave m (getWSerialT . f)
406------------------------------------------------------------------------------
408------------------------------------------------------------------------------
410MONAD_COMMON_INSTANCES(WSerialT,)
411LIST_INSTANCES(WSerialT)
412NFDATA1_INSTANCE(WSerialT)
413FOLDABLE_INSTANCE(WSerialT)
414TRAVERSABLE_INSTANCE(WSerialT)
416------------------------------------------------------------------------------
418------------------------------------------------------------------------------
420-- | Build a stream by unfolding a /monadic/ step function starting from a
421-- seed. The step function returns the next element in the stream and the next
422-- seed value. When it is done it returns 'Nothing' and the stream ends. For
428-- then return Nothing
429-- else print b >> return (Just (b, b + 1))
430-- in drain $ unfoldrM f 0
441{-# INLINE unfoldrM #-}
442unfoldrM :: Monad m => (b -> m (Maybe (a, b))) -> b -> SerialT m a
443unfoldrM 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