1{-# LANGUAGE UndecidableInstances #-}
2{-# OPTIONS_GHC -Wno-orphans #-}
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.Data.Stream as Stream
16-- >>> import qualified Streamly.Prelude as IsStream
18module Streamly.Internal.Data.Stream.Serial {-# DEPRECATED "Please use \"Streamly.Internal.Data.Stream\" instead." #-}
20 -- * Serial appending stream
25 -- * Serial interleaving stream
49import Control.Applicative (liftA2)
50import Control.DeepSeq (NFData(..), NFData1(..))
51import Control.Monad.Base (MonadBase(..), liftBaseDefault)
52import Control.Monad.Catch (MonadThrow, throwM)
53import Control.Monad.IO.Class (MonadIO(..))
54import Control.Monad.Reader.Class (MonadReader(..))
55import Control.Monad.State.Class (MonadState(..))
56import Control.Monad.Trans.Class (MonadTrans(lift))
57import Data.Foldable (Foldable(foldl'), fold)
58import Data.Functor.Identity (Identity(..), runIdentity)
59import Data.Maybe (fromMaybe)
60import Data.Semigroup (Endo(..))
61import GHC.Exts (IsList(..), IsString(..), oneShot)
63 ( Lexeme(Ident), lexP, parens, prec, readPrec, readListPrec
64 , readListPrecDefault)
65import Streamly.Internal.BaseCompat ((#.))
66import Streamly.Internal.Data.Maybe.Strict (Maybe'(..), toMaybe)
67import Streamly.Data.Stream (Stream)
69import qualified Streamly.Data.Fold as Fold
70import qualified Streamly.Data.Stream as Stream
71import qualified Streamly.Internal.Data.Stream as Stream
72 (toStreamK, fromStreamK, crossApply, crossApplySnd, crossApplyFst)
73import qualified Streamly.Internal.Data.Stream.Common as P
74import qualified Streamly.Internal.Data.Stream.StreamD as D
75 (fromStreamK, toStreamK, mapM)
76import qualified Streamly.Internal.Data.Stream.StreamK.Type as K
77 (Stream, mkStream, foldStream, cons, consM, nil, concatMapWith, fromPure
78 , bindWith, interleave, interleaveFst, interleaveMin, serial, fromEffect)
80import Prelude hiding (map, mapM, repeat, filter)
82#include "Instances.hs"
86-- >>> :set -fno-warn-deprecations
87-- >>> import qualified Streamly.Data.Stream as Stream
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------------------------------------------------------------------------------
99-- Applicative - orphan instances
100------------------------------------------------------------------------------
102-- Note: we need to define all the typeclass operations because we want to
104instance Monad m => Applicative (Stream m) where
106 pure = Stream.fromStreamK . K.fromPure
109 (<*>) = Stream.crossApply
110 -- (<*>) = K.apSerial
112 {-# INLINE liftA2 #-}
113 liftA2 f x = (<*>) (fmap f x)
116 (*>) = Stream.crossApplySnd
117 -- (*>) = K.apSerialDiscardFst
120 (<*) = Stream.crossApplyFst
121 -- (<*) = K.apSerialDiscardSnd
123------------------------------------------------------------------------------
124-- Monad - orphan instances
125------------------------------------------------------------------------------
127instance Monad m => Monad (Stream m) where
130 -- Benchmarks better with StreamD bind and pure:
131 -- toList, filterAllout, *>, *<, >> (~2x)
133 -- pure = Stream . D.fromStreamD . D.fromPure
134 -- m >>= f = D.fromStreamD $ D.concatMap (D.toStreamD . f) (D.toStreamD m)
136 -- Benchmarks better with CPS bind and pure:
138 -- n binds, breakAfterSome, filterAllIn, state transformer (~2x)
143 $ K.bindWith K.serial (Stream.toStreamK m) (Stream.toStreamK . f)
148------------------------------------------------------------------------------
149-- Transformers - orphan instances
150------------------------------------------------------------------------------
152instance (MonadIO m) => MonadIO (Stream m) where
153 liftIO = lift . liftIO
155instance (MonadThrow m) => MonadThrow (Stream m) where
156 throwM = lift . throwM
158instance MonadTrans Stream where
160 lift = Stream.fromEffect
162instance (MonadReader r m) => MonadReader r (Stream m) where
165 local f m = Stream.fromStreamK $ withLocal f (Stream.toStreamK m)
167instance (MonadState s m) => MonadState s (Stream m) where
175 state k = lift (state k)
177------------------------------------------------------------------------------
178-- NFData - orphan instances
179------------------------------------------------------------------------------
181instance NFData a => NFData (Stream Identity a) where
183 rnf xs = runIdentity $ Stream.fold (Fold.foldl' (\_ x -> rnf x) ()) xs
185instance NFData1 (Stream Identity) where
186 {-# INLINE liftRnf #-}
187 liftRnf f xs = runIdentity $ Stream.fold (Fold.foldl' (\_ x -> f x) ()) xs
189------------------------------------------------------------------------------
191------------------------------------------------------------------------------
195-- | A serial IO stream of elements of type @a@. See 'SerialT' documentation
198-- /Since: 0.2.0 ("Streamly")/
201type Serial = SerialT IO
203------------------------------------------------------------------------------
205------------------------------------------------------------------------------
208serial :: SerialT m a -> SerialT m a -> SerialT m a
219-- > S.toList $ S.map (+1) $ S.fromList [1,2,3]
225map :: Monad m => (a -> b) -> SerialT m a -> SerialT m b
226map f = Stream.mapM (return . f)
228------------------------------------------------------------------------------
230------------------------------------------------------------------------------
232-- | For 'WSerialT' streams:
235-- (<>) = 'Streamly.Prelude.wSerial' -- 'Semigroup'
236-- (>>=) = flip . 'Streamly.Prelude.concatMapWith' 'Streamly.Prelude.wSerial' -- 'Monad'
239-- Note that '<>' is associative only if we disregard the ordering of elements
240-- in the resulting stream.
242-- A single 'Monad' bind behaves like a @for@ loop:
245-- IsStream.toList $ IsStream.fromWSerial $ do
246-- x <- IsStream.fromList [1,2] -- foreach x in stream
251-- Nested monad binds behave like interleaved nested @for@ loops:
254-- IsStream.toList $ IsStream.fromWSerial $ do
255-- x <- IsStream.fromList [1,2] -- foreach x in stream
256-- y <- IsStream.fromList [3,4] -- foreach y in stream
259-- [(1,3),(2,3),(1,4),(2,4)]
261-- It is a result of interleaving all the nested iterations corresponding to
262-- element @1@ in the first stream with all the nested iterations of element
265-- >>> import Streamly.Prelude (wSerial)
266-- >>> IsStream.toList $ IsStream.fromList [(1,3),(1,4)] `IsStream.wSerial` IsStream.fromList [(2,3),(2,4)]
267-- [(1,3),(2,3),(1,4),(2,4)]
269-- The @W@ in the name stands for @wide@ or breadth wise scheduling in
270-- contrast to the depth wise scheduling behavior of 'Stream'.
272-- /Since: 0.2.0 ("Streamly")/
275newtype WSerialT m a = WSerialT {getWSerialT :: K.Stream m a}
277instance MonadTrans WSerialT where
279 lift = WSerialT . K.fromEffect
281-- | An interleaving serial IO stream of elements of type @a@. See 'WSerialT'
282-- documentation for more details.
284-- /Since: 0.2.0 ("Streamly")/
287type WSerial = WSerialT IO
289{-# INLINE consMWSerial #-}
290{-# SPECIALIZE consMWSerial :: IO a -> WSerialT IO a -> WSerialT IO a #-}
291consMWSerial :: Monad m => m a -> WSerialT m a -> WSerialT m a
292consMWSerial m (WSerialT ms) = WSerialT $ K.consM m ms
294------------------------------------------------------------------------------
296------------------------------------------------------------------------------
300-- | Interleaves two streams, yielding one element from each stream
301-- alternately. When one stream stops the rest of the other stream is used in
304-- This gives exponential priority to earlier streams than the ones joining
305-- later. Because of exponential weighting it can be used with 'concatMapWith'.
311-- Note that evaluation of @a \`wSerial` b \`wSerial` c@ does not interleave
312-- @a@, @b@ and @c@ with equal priority. This expression is equivalent to @a
313-- \`wSerial` (b \`wSerial` c)@, therefore, it fairly interleaves @a@ with the
314-- result of @b \`wSerial` c@. For example, @Stream.fromList [1,2] \`wSerial`
315-- Stream.fromList [3,4] \`wSerial` Stream.fromList [5,6]@ would result in
316-- [1,3,2,5,4,6]. In other words, the leftmost stream gets the same scheduling
317-- priority as the rest of the streams taken together. The same is true for
318-- each subexpression on the right.
320{-# INLINE wSerial #-}
321wSerial :: WSerialT m a -> WSerialT m a -> WSerialT m a
322wSerial (WSerialT m1) (WSerialT m2) = WSerialT $ K.interleave m1 m2
324{-# INLINE wSerialFst #-}
325wSerialFst :: WSerialT m a -> WSerialT m a -> WSerialT m a
326wSerialFst (WSerialT m1) (WSerialT m2) = WSerialT $ K.interleaveFst m1 m2
328{-# INLINE wSerialMin #-}
329wSerialMin :: WSerialT m a -> WSerialT m a -> WSerialT m a
330wSerialMin (WSerialT m1) (WSerialT m2) = WSerialT $ K.interleaveMin m1 m2
332instance Semigroup (WSerialT m a) where
335------------------------------------------------------------------------------
337------------------------------------------------------------------------------
339instance Monoid (WSerialT m a) where
340 mempty = WSerialT K.nil
343{-# INLINE apWSerial #-}
344apWSerial :: WSerialT m (a -> b) -> WSerialT m a -> WSerialT m b
345apWSerial (WSerialT m1) (WSerialT m2) =
346 let f x1 = K.concatMapWith K.interleave (K.fromPure . x1) m2
347 in WSerialT $ K.concatMapWith K.interleave f m1
349instance Monad m => Applicative (WSerialT m) where
351 pure = WSerialT . K.fromPure
355------------------------------------------------------------------------------
357------------------------------------------------------------------------------
359instance Monad m => Monad (WSerialT m) where
362 (>>=) (WSerialT m) f = WSerialT $ K.bindWith K.interleave m (getWSerialT . f)
364------------------------------------------------------------------------------
366------------------------------------------------------------------------------
368MONAD_COMMON_INSTANCES(WSerialT,)
369LIST_INSTANCES(WSerialT)
370NFDATA1_INSTANCE(WSerialT)
371FOLDABLE_INSTANCE(WSerialT)
372TRAVERSABLE_INSTANCE(WSerialT)
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