1{-# LANGUAGE TypeFamilies #-}
2-- Must come after TypeFamilies, otherwise it is re-enabled.
3-- MonoLocalBinds enabled by TypeFamilies causes perf regressions in general.
4{-# LANGUAGE NoMonoLocalBinds #-}
5{-# LANGUAGE UndecidableInstances #-}
7{-# OPTIONS_GHC -Wno-deprecations #-}
8{-# OPTIONS_GHC -Wno-redundant-constraints #-}
11-- Module : Streamly.Internal.Data.Stream.Serial
12-- Copyright : (c) 2017 Composewell Technologies
15-- Maintainer : streamly@composewell.com
16-- Stability : experimental
19-- To run examples in this module:
21-- >>> import qualified Streamly.Prelude as Stream
23module Streamly.Internal.Data.Stream.Serial {-# DEPRECATED "Please use \"Streamly.Internal.Data.Stream\" from streamly-core package instead." #-}
25 -- * Serial appending stream
32 -- * Serial interleaving stream
56#if !(MIN_VERSION_base(4,18,0))
57import Control.Applicative (liftA2)
59import Control.DeepSeq (NFData(..), NFData1(..))
60#if !(MIN_VERSION_transformers(0,6,0))
61import Control.Monad.Base (MonadBase(..), liftBaseDefault)
63import Control.Monad.Catch (MonadThrow, throwM)
64import Control.Monad.IO.Class (MonadIO(..))
65import Control.Monad.Reader.Class (MonadReader(..))
66import Control.Monad.State.Class (MonadState(..))
67import Control.Monad.Trans.Class (MonadTrans(lift))
68import Data.Foldable (Foldable(foldl'), fold)
69import Data.Functor.Identity (Identity(..), runIdentity)
70import Data.Maybe (fromMaybe)
71import Data.Semigroup (Endo(..))
72import GHC.Exts (IsList(..), IsString(..), oneShot)
74 ( Lexeme(Ident), lexP, parens, prec, readPrec, readListPrec
75 , readListPrecDefault)
76import Streamly.Internal.BaseCompat ((#.))
77import Streamly.Internal.Data.Maybe.Strict (Maybe'(..), toMaybe)
78import Streamly.Internal.Data.StreamK (Stream)
80import qualified Streamly.Internal.Data.Stream.Common as P
81import qualified Streamly.Internal.Data.Stream as D
82import qualified Streamly.Internal.Data.StreamK as K
84import Prelude hiding (map, mapM, repeat, filter)
86#include "Instances.hs"
90-- >>> :set -fno-warn-deprecations
91-- >>> import qualified Streamly.Prelude as IsStream
93{-# INLINABLE withLocal #-}
94withLocal :: MonadReader r m => (r -> r) -> K.Stream m a -> K.Stream m a
96 K.mkStream $ \st yld sng stp ->
97 let single = local f . sng
98 yieldk a r = local f $ yld a (withLocal f r)
99 in K.foldStream st yieldk single (local f stp) m
101------------------------------------------------------------------------------
103------------------------------------------------------------------------------
105-- | For 'SerialT' streams:
108-- (<>) = 'Streamly.Prelude.serial' -- 'Semigroup'
109-- (>>=) = flip . 'Streamly.Prelude.concatMapWith' 'Streamly.Prelude.serial' -- 'Monad'
112-- A single 'Monad' bind behaves like a @for@ loop:
115-- IsStream.toList $ do
116-- x <- IsStream.fromList [1,2] -- foreach x in stream
121-- Nested monad binds behave like nested @for@ loops:
124-- IsStream.toList $ do
125-- x <- IsStream.fromList [1,2] -- foreach x in stream
126-- y <- IsStream.fromList [3,4] -- foreach y in stream
129-- [(1,3),(1,4),(2,3),(2,4)]
131-- /Since: 0.2.0 ("Streamly")/
134newtype SerialT m a = SerialT {getSerialT :: Stream m a}
135 -- XXX when deriving do we inherit an INLINE?
136 deriving (Semigroup, Monoid)
138-- | A serial IO stream of elements of type @a@. See 'SerialT' documentation
141-- /Since: 0.2.0 ("Streamly")/
144type Serial = SerialT IO
146toStreamK :: SerialT m a -> Stream m a
147toStreamK = getSerialT
149fromStreamK :: Stream m a -> SerialT m a
152------------------------------------------------------------------------------
154------------------------------------------------------------------------------
159cons :: a -> SerialT m a -> SerialT m a
160cons x (SerialT ms) = SerialT $ K.cons x ms
165{-# SPECIALIZE consM :: IO a -> SerialT IO a -> SerialT IO a #-}
166consM :: Monad m => m a -> SerialT m a -> SerialT m a
167consM m (SerialT ms) = SerialT $ K.consM m ms
170-- Generate an infinite stream by repeating a pure value.
172{-# INLINE_NORMAL repeat #-}
173repeat :: Monad m => a -> SerialT m a
174repeat = SerialT . D.toStreamK . D.repeat
176------------------------------------------------------------------------------
178------------------------------------------------------------------------------
181serial :: SerialT m a -> SerialT m a -> SerialT m a
184------------------------------------------------------------------------------
186------------------------------------------------------------------------------
188instance Monad m => Monad (SerialT m) where
191 -- Benchmarks better with StreamD bind and pure:
192 -- toList, filterAllout, *>, *<, >> (~2x)
194 -- pure = SerialT . D.fromStreamD . D.fromPure
195 -- m >>= f = D.fromStreamD $ D.concatMap (D.toStreamD . f) (D.toStreamD m)
197 -- Benchmarks better with CPS bind and pure:
199 -- n binds, breakAfterSome, filterAllIn, state transformer (~2x)
202 (>>=) (SerialT m) f = SerialT $ K.bindWith K.append m (getSerialT . f)
207instance MonadTrans SerialT where
209 lift = SerialT . K.fromEffect
211------------------------------------------------------------------------------
213------------------------------------------------------------------------------
216mapM :: Monad m => (a -> m b) -> SerialT m a -> SerialT m b
217mapM f (SerialT m) = SerialT $ D.toStreamK $ D.mapM f $ D.fromStreamK m
227-- > S.toList $ S.map (+1) $ S.fromList [1,2,3]
233map :: Monad m => (a -> b) -> SerialT m a -> SerialT m b
234map f = mapM (return . f)
236{-# INLINE apSerial #-}
237apSerial :: Monad m => SerialT m (a -> b) -> SerialT m a -> SerialT m b
238apSerial (SerialT m1) (SerialT m2) =
239 SerialT $ D.toStreamK $ D.fromStreamK m1 `D.crossApply` D.fromStreamK m2
241{-# INLINE apSequence #-}
242apSequence :: Monad m => SerialT m a -> SerialT m b -> SerialT m b
243apSequence (SerialT m1) (SerialT m2) =
244 SerialT $ D.toStreamK $ D.fromStreamK m1 `D.crossApplySnd` D.fromStreamK m2
246{-# INLINE apDiscardSnd #-}
247apDiscardSnd :: Monad m => SerialT m a -> SerialT m b -> SerialT m a
248apDiscardSnd (SerialT m1) (SerialT m2) =
249 SerialT $ D.toStreamK $ D.fromStreamK m1 `D.crossApplyFst` D.fromStreamK m2
251-- Note: we need to define all the typeclass operations because we want to
253instance Monad m => Applicative (SerialT m) where
255 pure = SerialT . K.fromPure
259 -- (<*>) = K.apSerial
261 {-# INLINE liftA2 #-}
262 liftA2 f x = (<*>) (fmap f x)
266 -- (*>) = K.apSerialDiscardFst
270 -- (<*) = K.apSerialDiscardSnd
272MONAD_COMMON_INSTANCES(SerialT,)
273LIST_INSTANCES(SerialT)
274NFDATA1_INSTANCE(SerialT)
275FOLDABLE_INSTANCE(SerialT)
276TRAVERSABLE_INSTANCE(SerialT)
278------------------------------------------------------------------------------
280------------------------------------------------------------------------------
282-- | For 'WSerialT' streams:
285-- (<>) = 'Streamly.Prelude.wSerial' -- 'Semigroup'
286-- (>>=) = flip . 'Streamly.Prelude.concatMapWith' 'Streamly.Prelude.wSerial' -- 'Monad'
289-- Note that '<>' is associative only if we disregard the ordering of elements
290-- in the resulting stream.
292-- A single 'Monad' bind behaves like a @for@ loop:
295-- IsStream.toList $ IsStream.fromWSerial $ do
296-- x <- IsStream.fromList [1,2] -- foreach x in stream
301-- Nested monad binds behave like interleaved nested @for@ loops:
304-- IsStream.toList $ IsStream.fromWSerial $ do
305-- x <- IsStream.fromList [1,2] -- foreach x in stream
306-- y <- IsStream.fromList [3,4] -- foreach y in stream
309-- [(1,3),(2,3),(1,4),(2,4)]
311-- It is a result of interleaving all the nested iterations corresponding to
312-- element @1@ in the first stream with all the nested iterations of element
315-- >>> import Streamly.Prelude (wSerial)
316-- >>> IsStream.toList $ IsStream.fromList [(1,3),(1,4)] `IsStream.wSerial` IsStream.fromList [(2,3),(2,4)]
317-- [(1,3),(2,3),(1,4),(2,4)]
319-- The @W@ in the name stands for @wide@ or breadth wise scheduling in
320-- contrast to the depth wise scheduling behavior of 'SerialT'.
322-- /Since: 0.2.0 ("Streamly")/
325newtype WSerialT m a = WSerialT {getWSerialT :: Stream m a}
327instance MonadTrans WSerialT where
329 lift = WSerialT . K.fromEffect
331-- | An interleaving serial IO stream of elements of type @a@. See 'WSerialT'
332-- documentation for more details.
334-- /Since: 0.2.0 ("Streamly")/
337type WSerial = WSerialT IO
339{-# INLINE consMWSerial #-}
340{-# SPECIALIZE consMWSerial :: IO a -> WSerialT IO a -> WSerialT IO a #-}
341consMWSerial :: Monad m => m a -> WSerialT m a -> WSerialT m a
342consMWSerial m (WSerialT ms) = WSerialT $ K.consM m ms
344------------------------------------------------------------------------------
346------------------------------------------------------------------------------
350-- | Interleaves two streams, yielding one element from each stream
351-- alternately. When one stream stops the rest of the other stream is used in
354-- This gives exponential priority to earlier streams than the ones joining
355-- later. Because of exponential weighting it can be used with 'concatMapWith'.
361-- Note that evaluation of @a \`wSerial` b \`wSerial` c@ does not interleave
362-- @a@, @b@ and @c@ with equal priority. This expression is equivalent to @a
363-- \`wSerial` (b \`wSerial` c)@, therefore, it fairly interleaves @a@ with the
364-- result of @b \`wSerial` c@. For example, @Stream.fromList [1,2] \`wSerial`
365-- Stream.fromList [3,4] \`wSerial` Stream.fromList [5,6]@ would result in
366-- [1,3,2,5,4,6]. In other words, the leftmost stream gets the same scheduling
367-- priority as the rest of the streams taken together. The same is true for
368-- each subexpression on the right.
370{-# INLINE wSerial #-}
371wSerial :: WSerialT m a -> WSerialT m a -> WSerialT m a
372wSerial (WSerialT m1) (WSerialT m2) = WSerialT $ K.interleave m1 m2
374{-# INLINE wSerialFst #-}
375wSerialFst :: WSerialT m a -> WSerialT m a -> WSerialT m a
376wSerialFst (WSerialT m1) (WSerialT m2) = WSerialT $ K.interleaveFst m1 m2
378{-# INLINE wSerialMin #-}
379wSerialMin :: WSerialT m a -> WSerialT m a -> WSerialT m a
380wSerialMin (WSerialT m1) (WSerialT m2) = WSerialT $ K.interleaveMin m1 m2
382instance Semigroup (WSerialT m a) where
385------------------------------------------------------------------------------
387------------------------------------------------------------------------------
389instance Monoid (WSerialT m a) where
390 mempty = WSerialT K.nil
393{-# INLINE apWSerial #-}
394apWSerial :: WSerialT m (a -> b) -> WSerialT m a -> WSerialT m b
395apWSerial (WSerialT m1) (WSerialT m2) =
396 let f x1 = K.concatMapWith K.interleave (K.fromPure . x1) m2
397 in WSerialT $ K.concatMapWith K.interleave f m1
399instance Monad m => Applicative (WSerialT m) where
401 pure = WSerialT . K.fromPure
405------------------------------------------------------------------------------
407------------------------------------------------------------------------------
409instance Monad m => Monad (WSerialT m) where
412 (>>=) (WSerialT m) f = WSerialT $ K.bindWith K.interleave m (getWSerialT . f)
414------------------------------------------------------------------------------
416------------------------------------------------------------------------------
418#if !(MIN_VERSION_transformers(0,6,0))
419instance (MonadBase b m, Monad m) => MonadBase b (SerialT m) where
420 liftBase = liftBaseDefault
423MONAD_COMMON_INSTANCES(WSerialT,)
424LIST_INSTANCES(WSerialT)
425NFDATA1_INSTANCE(WSerialT)
426FOLDABLE_INSTANCE(WSerialT)
427TRAVERSABLE_INSTANCE(WSerialT)
429------------------------------------------------------------------------------
431------------------------------------------------------------------------------
433-- | Build a stream by unfolding a /monadic/ step function starting from a
434-- seed. The step function returns the next element in the stream and the next
435-- seed value. When it is done it returns 'Nothing' and the stream ends. For
441-- then return Nothing
442-- else print b >> return (Just (b, b + 1))
443-- in drain $ unfoldrM f 0
454{-# INLINE unfoldrM #-}
455unfoldrM :: Monad m => (b -> m (Maybe (a, b))) -> b -> SerialT m a
456unfoldrM 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