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)
62import Data.Semigroup (Semigroup(..))
63import GHC.Exts (IsList(..), IsString(..))
64import Text.Read (Lexeme(Ident), lexP, parens, prec, readPrec, readListPrec,
66import Prelude hiding (map, mapM)
68import Streamly.Streams.StreamK (IsStream(..), adapt, Stream, mkStream,
70import qualified Streamly.Streams.Prelude as P
71import qualified Streamly.Streams.StreamK as K
72import qualified Streamly.Streams.StreamD as D
74#include "Instances.hs"
77------------------------------------------------------------------------------
79------------------------------------------------------------------------------
81-- | Deep serial composition or serial composition with depth first traversal.
82-- The 'Semigroup' instance of 'SerialT' appends two streams serially in a
83-- depth first manner, yielding all elements from the first stream, and then
84-- all elements from the second stream.
88-- import qualified "Streamly.Prelude" as S
90-- main = ('toList' . 'serially' $ (fromFoldable [1,2]) \<\> (fromFoldable [3,4])) >>= print
96-- The 'Monad' instance runs the /monadic continuation/ for each
97-- element of the stream, serially.
100-- main = 'drain' . 'serially' $ do
101-- x <- return 1 \<\> return 2
109-- 'SerialT' nests streams serially in a depth first manner.
112-- main = 'drain' . 'serially' $ do
113-- x <- return 1 \<\> return 2
114-- y <- return 3 \<\> return 4
115-- S.yieldM $ print (x, y)
124-- This behavior of 'SerialT' is exactly like a list transformer. We call the
125-- monadic code being run for each element of the stream a monadic
126-- continuation. In imperative paradigm we can think of this composition as
127-- nested @for@ loops and the monadic continuation is the body of the loop. The
128-- loop iterates for all elements of the stream.
130-- The 'serially' combinator can be omitted as the default stream type is
132-- Note that serial composition with depth first traversal can be used to
133-- combine an infinite number of streams as it explores only one stream at a
137newtype SerialT m a = SerialT {getSerialT :: Stream m a}
138 deriving (Semigroup, Monoid, MonadTrans)
140-- | A serial IO stream of elements of type @a@. See 'SerialT' documentation
144type Serial = SerialT IO
148{-# DEPRECATED StreamT "Please use 'SerialT' instead." #-}
149type StreamT = SerialT
151-- | Fix the type of a polymorphic stream as 'SerialT'.
154serially :: IsStream t => SerialT m a -> t m a
157{-# INLINE consMSerial #-}
158{-# SPECIALIZE consMSerial :: IO a -> SerialT IO a -> SerialT IO a #-}
159consMSerial :: Monad m => m a -> SerialT m a -> SerialT m a
160consMSerial m ms = fromStream $ K.consMStream m (toStream ms)
162instance IsStream SerialT where
163 toStream = getSerialT
168------------------------------------------------------------------------------
170------------------------------------------------------------------------------
172instance Monad m => Monad (SerialT m) where
175 (>>=) = K.bindWith K.serial
177 -- StreamD based implementation
178 -- return = SerialT . D.fromStreamD . D.yield
179 -- m >>= f = D.fromStreamD $ D.concatMap (\a -> D.toStreamD (f a)) (D.toStreamD m)
181------------------------------------------------------------------------------
183------------------------------------------------------------------------------
185{-# INLINE_EARLY mapM #-}
186mapM :: (IsStream t, Monad m) => (a -> m b) -> t m a -> t m b
187mapM f m = fromStream $ D.toStreamK $ D.mapM f $ D.fromStreamK (toStream m)
197-- > S.toList $ S.map (+1) $ S.fromList [1,2,3]
203map :: (IsStream t, Monad m) => (a -> b) -> t m a -> t m b
204map f = mapM (return . f)
206MONAD_APPLICATIVE_INSTANCE(SerialT,)
207MONAD_COMMON_INSTANCES(SerialT,)
208LIST_INSTANCES(SerialT)
209NFDATA1_INSTANCE(SerialT)
210FOLDABLE_INSTANCE(SerialT)
211TRAVERSABLE_INSTANCE(SerialT)
213------------------------------------------------------------------------------
215------------------------------------------------------------------------------
217-- | Wide serial composition or serial composition with a breadth first
218-- traversal. The 'Semigroup' instance of 'WSerialT' traverses
219-- the two streams in a breadth first manner. In other words, it interleaves
220-- two streams, yielding one element from each stream alternately.
224-- import qualified "Streamly.Prelude" as S
226-- main = ('toList' . 'wSerially' $ (fromFoldable [1,2]) \<\> (fromFoldable [3,4])) >>= print
232-- Similarly, the 'Monad' instance interleaves the iterations of the
233-- inner and the outer loop, nesting loops in a breadth first manner.
237-- main = 'drain' . 'wSerially' $ do
238-- x <- return 1 \<\> return 2
239-- y <- return 3 \<\> return 4
240-- S.yieldM $ print (x, y)
249-- Note that a serial composition with breadth first traversal can only combine
250-- a finite number of streams as it needs to retain state for each unfinished
254newtype WSerialT m a = WSerialT {getWSerialT :: Stream m a}
255 deriving (MonadTrans)
257-- | An interleaving serial IO stream of elements of type @a@. See 'WSerialT'
258-- documentation for more details.
261type WSerial = WSerialT IO
265{-# DEPRECATED InterleavedT "Please use 'WSerialT' instead." #-}
266type InterleavedT = WSerialT
268-- | Fix the type of a polymorphic stream as 'WSerialT'.
271wSerially :: IsStream t => WSerialT m a -> t m a
274-- | Same as 'wSerially'.
277{-# DEPRECATED interleaving "Please use wSerially instead." #-}
278interleaving :: IsStream t => WSerialT m a -> t m a
279interleaving = wSerially
281consMWSerial :: Monad m => m a -> WSerialT m a -> WSerialT m a
282consMWSerial m ms = fromStream $ K.consMStream m (toStream ms)
284instance IsStream WSerialT where
285 toStream = getWSerialT
286 fromStream = WSerialT
289 {-# SPECIALIZE consM :: IO a -> WSerialT IO a -> WSerialT IO a #-}
290 consM :: Monad m => m a -> WSerialT m a -> WSerialT m a
294 {-# SPECIALIZE (|:) :: IO a -> WSerialT IO a -> WSerialT IO a #-}
295 (|:) :: Monad m => m a -> WSerialT m a -> WSerialT m a
298------------------------------------------------------------------------------
300------------------------------------------------------------------------------
302-- | Polymorphic version of the 'Semigroup' operation '<>' of 'WSerialT'.
303-- Interleaves two streams, yielding one element from each stream alternately.
304-- When one stream stops the rest of the other stream is used in the output
308{-# INLINE wSerial #-}
309wSerial :: IsStream t => t m a -> t m a -> t m a
310wSerial m1 m2 = mkStream $ \st yld sng stp -> do
311 let stop = foldStream st yld sng stp m2
313 yieldk a r = yld a (wSerial m2 r)
314 foldStream st yieldk single stop m1
316-- | Like `wSerial` but stops interleaving as soon as the first stream stops.
319{-# INLINE wSerialEndByFirst #-}
320wSerialEndByFirst :: IsStream t => t m a -> t m a -> t m a
321wSerialEndByFirst m1 m2 = mkStream $ \st yld sng stp -> do
322 let yieldFirst a r = yld a (yieldSecond r m2)
323 in foldStream st yieldFirst sng stp m1
327 yieldSecond s1 s2 = mkStream $ \st yld sng stp -> do
328 let stop = foldStream st yld sng stp s1
330 yieldk a r = yld a (wSerial s1 r)
331 in foldStream st yieldk single stop s2
333-- | Like `wSerial` but stops interleaving as soon as any of the two streams
337{-# INLINE wSerialEndByAny #-}
338wSerialEndByAny :: IsStream t => t m a -> t m a -> t m a
339wSerialEndByAny m1 m2 = mkStream $ \st yld sng stp -> do
342 yieldk a r = yld a (wSerial m2 r)
343 foldStream st yieldk single stop m1
345instance Semigroup (WSerialT m a) where
350-- | Same as 'wSerial'.
353{-# DEPRECATED (<=>) "Please use 'wSerial' instead." #-}
355(<=>) :: IsStream t => t m a -> t m a -> t m a
358------------------------------------------------------------------------------
360------------------------------------------------------------------------------
362instance Monoid (WSerialT m a) where
366------------------------------------------------------------------------------
368------------------------------------------------------------------------------
370instance Monad m => Monad (WSerialT m) where
373 (>>=) = K.bindWith wSerial
375------------------------------------------------------------------------------
377------------------------------------------------------------------------------
379MONAD_APPLICATIVE_INSTANCE(WSerialT,)
380MONAD_COMMON_INSTANCES(WSerialT,)
381LIST_INSTANCES(WSerialT)
382NFDATA1_INSTANCE(WSerialT)
383FOLDABLE_INSTANCE(WSerialT)
384TRAVERSABLE_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