2{-# LANGUAGE ConstraintKinds #-}
3{-# LANGUAGE FlexibleContexts #-}
4{-# LANGUAGE FlexibleInstances #-}
5{-# LANGUAGE GeneralizedNewtypeDeriving#-}
6{-# LANGUAGE InstanceSigs #-}
7{-# LANGUAGE MultiParamTypeClasses #-}
8{-# LANGUAGE TypeFamilies #-}
9{-# LANGUAGE UndecidableInstances #-} -- XXX
12-- Module : Streamly.Streams.Serial
13-- Copyright : (c) 2017 Harendra Kumar
16-- Maintainer : harendra.kumar@gmail.com
17-- Stability : experimental
21module Streamly.Streams.Serial
23 -- * Serial appending stream
25 , StreamT -- deprecated
30 -- * Serial interleaving stream
32 , InterleavedT -- deprecated
39 , interleaving -- deprecated
47import Control.Applicative (liftA2)
48import Control.DeepSeq (NFData(..))
49#if MIN_VERSION_deepseq(1,4,3)
50import Control.DeepSeq (NFData1(..))
52import Control.Monad (ap)
53import Control.Monad.Base (MonadBase(..), liftBaseDefault)
54import Control.Monad.Catch (MonadThrow, throwM)
55-- import Control.Monad.Error.Class (MonadError(..))
56import Control.Monad.IO.Class (MonadIO(..))
57import Control.Monad.Reader.Class (MonadReader(..))
58import Control.Monad.State.Class (MonadState(..))
59import Control.Monad.Trans.Class (MonadTrans(lift))
60import Data.Functor.Identity (Identity(..), runIdentity)
61import Data.Foldable (fold)
62#if __GLASGOW_HASKELL__ < 808
63import Data.Semigroup (Semigroup(..))
65import GHC.Exts (IsList(..), IsString(..))
66import Text.Read (Lexeme(Ident), lexP, parens, prec, readPrec, readListPrec,
68import Prelude hiding (map, mapM)
70import Streamly.Streams.StreamK (IsStream(..), adapt, Stream, mkStream,
72import qualified Streamly.Streams.Prelude as P
73import qualified Streamly.Streams.StreamK as K
74import qualified Streamly.Streams.StreamD as D
76#include "Instances.hs"
79------------------------------------------------------------------------------
81------------------------------------------------------------------------------
83-- | The 'Semigroup' operation for 'SerialT' behaves like a regular append
84-- operation. Therefore, when @a <> b@ is evaluated, stream @a@ is evaluated
85-- first until it exhausts and then stream @b@ is evaluated. In other words,
86-- the elements of stream @b@ are appended to the elements of stream @a@. This
87-- operation can be used to fold an infinite lazy container of streams.
91-- import qualified "Streamly.Prelude" as S
93-- main = (S.toList . 'serially' $ (S.fromList [1,2]) \<\> (S.fromList [3,4])) >>= print
99-- The 'Monad' instance runs the /monadic continuation/ for each
100-- element of the stream, serially.
103-- main = S.drain . 'serially' $ do
104-- x <- return 1 \<\> return 2
112-- 'SerialT' nests streams serially in a depth first manner.
115-- main = S.drain . 'serially' $ do
116-- x <- return 1 \<\> return 2
117-- y <- return 3 \<\> return 4
118-- S.yieldM $ print (x, y)
127-- We call the monadic code being run for each element of the stream a monadic
128-- continuation. In imperative paradigm we can think of this composition as
129-- nested @for@ loops and the monadic continuation is the body of the loop. The
130-- loop iterates for all elements of the stream.
132-- Note that the behavior and semantics of 'SerialT', including 'Semigroup'
133-- and 'Monad' instances are exactly like Haskell lists except that 'SerialT'
134-- can contain effectful actions while lists are pure.
136-- In the code above, the 'serially' combinator can be omitted as the default
137-- stream type is 'SerialT'.
140newtype SerialT m a = SerialT {getSerialT :: Stream m a}
141 deriving (Semigroup, Monoid, MonadTrans)
143-- | A serial IO stream of elements of type @a@. See 'SerialT' documentation
147type Serial = SerialT IO
151{-# DEPRECATED StreamT "Please use 'SerialT' instead." #-}
152type StreamT = SerialT
154-- | Fix the type of a polymorphic stream as 'SerialT'.
157serially :: IsStream t => SerialT m a -> t m a
160{-# INLINE consMSerial #-}
161{-# SPECIALIZE consMSerial :: IO a -> SerialT IO a -> SerialT IO a #-}
162consMSerial :: Monad m => m a -> SerialT m a -> SerialT m a
163consMSerial m ms = fromStream $ K.consMStream m (toStream ms)
165instance IsStream SerialT where
166 toStream = getSerialT
171------------------------------------------------------------------------------
173------------------------------------------------------------------------------
175instance Monad m => Monad (SerialT m) where
178 (>>=) = K.bindWith K.serial
180 -- StreamD based implementation
181 -- return = SerialT . D.fromStreamD . D.yield
182 -- m >>= f = D.fromStreamD $ D.concatMap (\a -> D.toStreamD (f a)) (D.toStreamD m)
184------------------------------------------------------------------------------
186------------------------------------------------------------------------------
188{-# INLINE_EARLY mapM #-}
189mapM :: (IsStream t, Monad m) => (a -> m b) -> t m a -> t m b
190mapM f m = fromStream $ D.toStreamK $ D.mapM f $ D.fromStreamK (toStream m)
200-- > S.toList $ S.map (+1) $ S.fromList [1,2,3]
206map :: (IsStream t, Monad m) => (a -> b) -> t m a -> t m b
207map f = mapM (return . f)
209MONAD_APPLICATIVE_INSTANCE(SerialT,)
210MONAD_COMMON_INSTANCES(SerialT,)
211LIST_INSTANCES(SerialT)
212NFDATA1_INSTANCE(SerialT)
213FOLDABLE_INSTANCE(SerialT)
214TRAVERSABLE_INSTANCE(SerialT)
216------------------------------------------------------------------------------
218------------------------------------------------------------------------------
220-- | The 'Semigroup' operation for 'WSerialT' interleaves the elements from the
221-- two streams. Therefore, when @a <> b@ is evaluated, stream @a@ is evaluated
222-- first to produce the first element of the combined stream and then stream
223-- @b@ is evaluated to produce the next element of the combined stream, and
224-- then we go back to evaluating stream @a@ and so on. In other words, the
225-- elements of stream @a@ are interleaved with the elements of stream @b@.
227-- Note that when multiple actions are combined like @a <> b <> c ... <> z@ we
228-- interleave them in a binary fashion i.e. @a@ and @b@ are interleaved with
229-- each other and the result is interleaved with @c@ and so on. This will not
230-- act as a true round-robin scheduling across all the streams. Note that this
231-- operation cannot be used to fold a container of infinite streams as the
232-- state that it needs to maintain is proportional to the number of streams.
236-- import qualified "Streamly.Prelude" as S
238-- main = (S.toList . 'wSerially' $ (S.fromList [1,2]) \<\> (S.fromList [3,4])) >>= print
244-- Similarly, the 'Monad' instance interleaves the iterations of the
245-- inner and the outer loop, nesting loops in a breadth first manner.
249-- main = S.drain . 'wSerially' $ do
250-- x <- return 1 \<\> return 2
251-- y <- return 3 \<\> return 4
252-- S.yieldM $ print (x, y)
262newtype WSerialT m a = WSerialT {getWSerialT :: Stream m a}
263 deriving (MonadTrans)
265-- | An interleaving serial IO stream of elements of type @a@. See 'WSerialT'
266-- documentation for more details.
269type WSerial = WSerialT IO
273{-# DEPRECATED InterleavedT "Please use 'WSerialT' instead." #-}
274type InterleavedT = WSerialT
276-- | Fix the type of a polymorphic stream as 'WSerialT'.
279wSerially :: IsStream t => WSerialT m a -> t m a
282-- | Same as 'wSerially'.
285{-# DEPRECATED interleaving "Please use wSerially instead." #-}
286interleaving :: IsStream t => WSerialT m a -> t m a
287interleaving = wSerially
289consMWSerial :: Monad m => m a -> WSerialT m a -> WSerialT m a
290consMWSerial m ms = fromStream $ K.consMStream m (toStream ms)
292instance IsStream WSerialT where
293 toStream = getWSerialT
294 fromStream = WSerialT
297 {-# SPECIALIZE consM :: IO a -> WSerialT IO a -> WSerialT IO a #-}
298 consM :: Monad m => m a -> WSerialT m a -> WSerialT m a
302 {-# SPECIALIZE (|:) :: IO a -> WSerialT IO a -> WSerialT IO a #-}
303 (|:) :: Monad m => m a -> WSerialT m a -> WSerialT m a
306------------------------------------------------------------------------------
308------------------------------------------------------------------------------
310-- Additionally we can have m elements yield from the first stream and n
311-- elements yeilding from the second stream. We can also have time slicing
312-- variants of positional interleaving, e.g. run first stream for m seconds and
313-- run the second stream for n seconds.
315-- Similar combinators can be implemented using WAhead style.
317-- | Polymorphic version of the 'Semigroup' operation '<>' of 'WSerialT'.
318-- Interleaves two streams, yielding one element from each stream alternately.
319-- When one stream stops the rest of the other stream is used in the output
323{-# INLINE wSerial #-}
324wSerial :: IsStream t => t m a -> t m a -> t m a
325wSerial m1 m2 = mkStream $ \st yld sng stp -> do
326 let stop = foldStream st yld sng stp m2
328 yieldk a r = yld a (wSerial m2 r)
329 foldStream st yieldk single stop m1
331-- | Like `wSerial` but stops interleaving as soon as the first stream stops.
334{-# INLINE wSerialFst #-}
335wSerialFst :: IsStream t => t m a -> t m a -> t m a
336wSerialFst m1 m2 = mkStream $ \st yld sng stp -> do
337 let yieldFirst a r = yld a (yieldSecond r m2)
338 in foldStream st yieldFirst sng stp m1
342 yieldSecond s1 s2 = mkStream $ \st yld sng stp -> do
343 let stop = foldStream st yld sng stp s1
345 yieldk a r = yld a (wSerial s1 r)
346 in foldStream st yieldk single stop s2
348-- | Like `wSerial` but stops interleaving as soon as any of the two streams
352{-# INLINE wSerialMin #-}
353wSerialMin :: IsStream t => t m a -> t m a -> t m a
354wSerialMin m1 m2 = mkStream $ \st yld sng stp -> do
357 yieldk a r = yld a (wSerial m2 r)
358 foldStream st yieldk single stop m1
360instance Semigroup (WSerialT m a) where
365-- | Same as 'wSerial'.
368{-# DEPRECATED (<=>) "Please use 'wSerial' instead." #-}
370(<=>) :: IsStream t => t m a -> t m a -> t m a
373------------------------------------------------------------------------------
375------------------------------------------------------------------------------
377instance Monoid (WSerialT m a) where
381------------------------------------------------------------------------------
383------------------------------------------------------------------------------
385instance Monad m => Monad (WSerialT m) where
388 (>>=) = K.bindWith wSerial
390------------------------------------------------------------------------------
392------------------------------------------------------------------------------
394MONAD_APPLICATIVE_INSTANCE(WSerialT,)
395MONAD_COMMON_INSTANCES(WSerialT,)
396LIST_INSTANCES(WSerialT)
397NFDATA1_INSTANCE(WSerialT)
398FOLDABLE_INSTANCE(WSerialT)
399TRAVERSABLE_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