on a74f291 help sign in
266 lines 8.4 kB history raw
1{-# LANGUAGE UndecidableInstances #-}
3-- |
4-- Module : Streamly.Internal.Data.Stream.Serial
5-- Copyright : (c) 2017 Composewell Technologies
6--
7-- License : BSD3
8-- Maintainer : streamly@composewell.com
9-- Stability : experimental
10-- Portability : GHC
11--
12-- To run examples in this module:
13--
14-- >>> import qualified Streamly.Data.Stream as Stream
15-- >>> import qualified Streamly.Prelude as IsStream
16--
17module Streamly.Internal.Data.Stream.Serial {-# DEPRECATED "Please use \"Streamly.Internal.Data.Stream\" instead." #-}
18 (
19 -- * Serial appending stream
20 SerialT
21 , Serial
22 , serial
24 -- * Serial interleaving stream
25 , WSerialT(..)
26 , WSerial
27 , wSerial
28 , wSerialFst
29 , wSerialMin
30 , consMWSerial
32 -- * Construction
33 , Stream.cons
34 , Stream.consM
35 , Stream.repeat
36 , Stream.unfoldrM
37 , fromList
39 -- * Elimination
40 , toList
42 -- * Transformation
43 , map
44 , Stream.mapM
45 )
46where
48import Control.Applicative (liftA2)
49import Control.DeepSeq (NFData(..), NFData1(..))
50import Control.Monad.Base (MonadBase(..), liftBaseDefault)
51import Control.Monad.Catch (MonadThrow, throwM)
52import Control.Monad.IO.Class (MonadIO(..))
53import Control.Monad.Reader.Class (MonadReader(..))
54import Control.Monad.State.Class (MonadState(..))
55import Control.Monad.Trans.Class (MonadTrans(lift))
56import Data.Foldable (Foldable(foldl'), fold)
57import Data.Functor.Identity (Identity(..), runIdentity)
58import Data.Maybe (fromMaybe)
59import Data.Semigroup (Endo(..))
60import GHC.Exts (IsList(..), IsString(..), oneShot)
61import Text.Read
62 ( Lexeme(Ident), lexP, parens, prec, readPrec, readListPrec
63 , readListPrecDefault)
64import Streamly.Internal.BaseCompat ((#.))
65import Streamly.Internal.Data.Maybe.Strict (Maybe'(..), toMaybe)
66import Streamly.Data.Stream (Stream)
68import qualified Streamly.Data.Stream as Stream
69import qualified Streamly.Internal.Data.Stream.Common as P
70import qualified Streamly.Internal.Data.Stream.StreamD as D
71 (fromStreamK, toStreamK, mapM)
72import qualified Streamly.Internal.Data.Stream.StreamK.Type as K
73 (Stream, cons, consM, nil, concatMapWith, fromPure, bindWith
74 , withLocal, interleave, interleaveFst, interleaveMin)
76import Prelude hiding (map, mapM, repeat, filter)
78#include "Instances.hs"
79#include "inline.hs"
81-- $setup
82-- >>> :set -fno-warn-deprecations
83-- >>> import qualified Streamly.Data.Stream as Stream
84-- >>> import qualified Streamly.Prelude as IsStream
86------------------------------------------------------------------------------
87-- SerialT
88------------------------------------------------------------------------------
90type SerialT = Stream
92-- | A serial IO stream of elements of type @a@. See 'SerialT' documentation
93-- for more details.
94--
95-- /Since: 0.2.0 ("Streamly")/
96--
97-- @since 0.8.0
98type Serial = SerialT IO
100------------------------------------------------------------------------------
101-- Combining
102------------------------------------------------------------------------------
104{-# INLINE serial #-}
105serial :: SerialT m a -> SerialT m a -> SerialT m a
106serial = (<>)
108-- |
109-- @
110-- map = fmap
111-- @
112--
113-- Same as 'fmap'.
114--
115-- @
116-- > S.toList $ S.map (+1) $ S.fromList [1,2,3]
117-- [2,3,4]
118-- @
119--
120-- @since 0.4.0
121{-# INLINE map #-}
122map :: Monad m => (a -> b) -> SerialT m a -> SerialT m b
123map f = Stream.mapM (return . f)
125------------------------------------------------------------------------------
126-- WSerialT
127------------------------------------------------------------------------------
129-- | For 'WSerialT' streams:
130--
131-- @
132-- (<>) = 'Streamly.Prelude.wSerial' -- 'Semigroup'
133-- (>>=) = flip . 'Streamly.Prelude.concatMapWith' 'Streamly.Prelude.wSerial' -- 'Monad'
134-- @
135--
136-- Note that '<>' is associative only if we disregard the ordering of elements
137-- in the resulting stream.
138--
139-- A single 'Monad' bind behaves like a @for@ loop:
140--
141-- >>> :{
142-- IsStream.toList $ IsStream.fromWSerial $ do
143-- x <- IsStream.fromList [1,2] -- foreach x in stream
144-- return x
145-- :}
146-- [1,2]
147--
148-- Nested monad binds behave like interleaved nested @for@ loops:
149--
150-- >>> :{
151-- IsStream.toList $ IsStream.fromWSerial $ do
152-- x <- IsStream.fromList [1,2] -- foreach x in stream
153-- y <- IsStream.fromList [3,4] -- foreach y in stream
154-- return (x, y)
155-- :}
156-- [(1,3),(2,3),(1,4),(2,4)]
157--
158-- It is a result of interleaving all the nested iterations corresponding to
159-- element @1@ in the first stream with all the nested iterations of element
160-- @2@:
161--
162-- >>> import Streamly.Prelude (wSerial)
163-- >>> IsStream.toList $ IsStream.fromList [(1,3),(1,4)] `IsStream.wSerial` IsStream.fromList [(2,3),(2,4)]
164-- [(1,3),(2,3),(1,4),(2,4)]
165--
166-- The @W@ in the name stands for @wide@ or breadth wise scheduling in
167-- contrast to the depth wise scheduling behavior of 'Stream'.
168--
169-- /Since: 0.2.0 ("Streamly")/
170--
171-- @since 0.8.0
172newtype WSerialT m a = WSerialT {getWSerialT :: K.Stream m a}
173 deriving (MonadTrans)
175-- | An interleaving serial IO stream of elements of type @a@. See 'WSerialT'
176-- documentation for more details.
177--
178-- /Since: 0.2.0 ("Streamly")/
179--
180-- @since 0.8.0
181type WSerial = WSerialT IO
183{-# INLINE consMWSerial #-}
184{-# SPECIALIZE consMWSerial :: IO a -> WSerialT IO a -> WSerialT IO a #-}
185consMWSerial :: Monad m => m a -> WSerialT m a -> WSerialT m a
186consMWSerial m (WSerialT ms) = WSerialT $ K.consM m ms
188------------------------------------------------------------------------------
189-- Semigroup
190------------------------------------------------------------------------------
192infixr 6 `wSerial`
194-- | Interleaves two streams, yielding one element from each stream
195-- alternately. When one stream stops the rest of the other stream is used in
196-- the output stream.
197--
198-- This gives exponential priority to earlier streams than the ones joining
199-- later. Because of exponential weighting it can be used with 'concatMapWith'.
200--
201-- /Not fused/
203-- NOTE:
204--
205-- Note that evaluation of @a \`wSerial` b \`wSerial` c@ does not interleave
206-- @a@, @b@ and @c@ with equal priority. This expression is equivalent to @a
207-- \`wSerial` (b \`wSerial` c)@, therefore, it fairly interleaves @a@ with the
208-- result of @b \`wSerial` c@. For example, @Stream.fromList [1,2] \`wSerial`
209-- Stream.fromList [3,4] \`wSerial` Stream.fromList [5,6]@ would result in
210-- [1,3,2,5,4,6]. In other words, the leftmost stream gets the same scheduling
211-- priority as the rest of the streams taken together. The same is true for
212-- each subexpression on the right.
213--
214{-# INLINE wSerial #-}
215wSerial :: WSerialT m a -> WSerialT m a -> WSerialT m a
216wSerial (WSerialT m1) (WSerialT m2) = WSerialT $ K.interleave m1 m2
218{-# INLINE wSerialFst #-}
219wSerialFst :: WSerialT m a -> WSerialT m a -> WSerialT m a
220wSerialFst (WSerialT m1) (WSerialT m2) = WSerialT $ K.interleaveFst m1 m2
222{-# INLINE wSerialMin #-}
223wSerialMin :: WSerialT m a -> WSerialT m a -> WSerialT m a
224wSerialMin (WSerialT m1) (WSerialT m2) = WSerialT $ K.interleaveMin m1 m2
226instance Semigroup (WSerialT m a) where
227 (<>) = wSerial
229------------------------------------------------------------------------------
230-- Monoid
231------------------------------------------------------------------------------
233instance Monoid (WSerialT m a) where
234 mempty = WSerialT K.nil
235 mappend = (<>)
237{-# INLINE apWSerial #-}
238apWSerial :: Monad m => WSerialT m (a -> b) -> WSerialT m a -> WSerialT m b
239apWSerial (WSerialT m1) (WSerialT m2) =
240 let f x1 = K.concatMapWith K.interleave (pure . x1) m2
241 in WSerialT $ K.concatMapWith K.interleave f m1
243instance Monad m => Applicative (WSerialT m) where
244 {-# INLINE pure #-}
245 pure = WSerialT . K.fromPure
246 {-# INLINE (<*>) #-}
247 (<*>) = apWSerial
249------------------------------------------------------------------------------
250-- Monad
251------------------------------------------------------------------------------
253instance Monad m => Monad (WSerialT m) where
254 return = pure
255 {-# INLINE (>>=) #-}
256 (>>=) (WSerialT m) f = WSerialT $ K.bindWith K.interleave m (getWSerialT . f)
258------------------------------------------------------------------------------
259-- Other instances
260------------------------------------------------------------------------------
262MONAD_COMMON_INSTANCES(WSerialT,)
263LIST_INSTANCES(WSerialT)
264NFDATA1_INSTANCE(WSerialT)
265FOLDABLE_INSTANCE(WSerialT)
266TRAVERSABLE_INSTANCE(WSerialT)