1{-# OPTIONS_GHC -Wno-orphans #-}
6-- Module : Streamly.Internal.Data.Stream.IsStream
7-- Copyright : (c) 2017 Harendra Kumar
10-- Maintainer : streamly@composewell.com
11-- Stability : experimental
14-- This is an Internal module consisting of released, unreleased and
15-- unimplemented APIs. For stable and released APIs please see
16-- "Streamly.Prelude" module. This module provides documentation only for the
17-- unreleased and unimplemented APIs. For documentation on released APIs please
18-- see "Streamly.Prelude" module.
20module Streamly.Internal.Data.Stream.IsStream
45 -- ** Time Enumeration
91 -- ** Composable Left Folds
97 -- ** Concurrent Folds
104 -- -- ** To Summary (Full Folds)
112 -- -- ** To Summary (Maybe) (Full Folds)
120 -- -- ** To Containers (Full Folds)
126 -- ** Composable Left Folds
128 , toStream -- XXX rename to write?
129 , toStreamRev -- XXX rename to writeRev?
133 -- -- ** To Elements (Partial Folds)
137 -- -- | Folds that extract selected elements of a stream or their properties.
147 -- -- ** To Boolean (Partial Folds)
156 -- ** Multi-Stream folds
161 -- finding subsequences
167 -- trimming sequences
205 -- ** Scan Using Fold
209 -- XXX Once we have pipes the contravariant transformations can be
210 -- represented by attaching pipes before a transformation.
222 -- ** Concurrent Transformation
234 -- ** Mapping Filters
238 -- ** Deleting Elements
241 -- , uniqBy -- by predicate e.g. to remove duplicate "/" in a path
242 -- , uniqOn -- to remove duplicate sequences
243 -- , pruneBy -- dropAround + uniqBy - like words
245 -- ** Inserting Elements
254 , intersperseSuffixBySpan
255 -- , intersperseBySpan
256 -- , intersperseByIndices -- using an index function/stream
258 -- time domain intersperse
259 -- , intersperseByTime
260 -- , intersperseByEvent
271 -- , timestampedR -- timer
308 -- -- *** Searching Elements
312 -- -- *** Searching Sequences
313 -- , seqIndices -- search a sequence in the stream
315 -- -- *** Searching Multiple Sequences
316 -- , seqIndicesAny -- search any of the given sequence in the stream
318 -- -- -- ** Searching Streams
319 -- -- | Finding a stream within another stream.
322 -- | Streams can be sliced into segments in space or in time. We use the
323 -- term @chunk@ to refer to a spatial length of the stream (spatial window)
324 -- and the term @session@ to refer to a length in time (time window).
326 -- -- *** Using Element Separators
334 , wordsBy -- stripAndCompactBy
336 -- -- *** Splitting By Sequences
339 -- , splitOnPrefixSeq
341 -- Keeping the delimiters
344 -- , splitByPrefixSeq
347 -- Splitting using multiple sequence separators
349 -- , splitOnAnySuffixSeq
350 -- , splitOnAnyPrefixSeq
352 -- -- *** Splitting By Streams
353 -- -- | Splitting a stream using another stream as separator.
360 -- In imperative terms, grouped folding can be considered as a nested loop
361 -- where we loop over the stream to group elements and then loop over
362 -- individual groups to fold them to a single value that is yielded in the
375 -- * Windowed Classification
377 -- | Split the stream into windows or chunks in space or time. Each window
378 -- can be associated with a key, all events associated with a particular
379 -- key in the window can be folded to a single result. The stream is split
380 -- into windows of specified size, the window can be terminated early if
381 -- the closing flag is specified in the input stream.
383 -- The term "chunk" is used for a space window and the term "session" is
384 -- used for a time window.
386 -- ** Tumbling Windows
387 -- | A new window starts after the previous window is finished.
389 -- , classifyChunksOf
393 -- ** Keep Alive Windows
394 -- | The window size is extended if an event arrives within the specified
395 -- window size. This can represent sessions with idle or inactive timeout.
397 -- , classifyKeepAliveChunks
398 , classifyKeepAliveSessions
401 -- ** Sliding Windows
402 -- | A new window starts after the specified slide from the previous
403 -- window. Therefore windows can overlap.
404 , classifySlidingChunks
405 , classifySlidingSessions
407 -- ** Sliding Window Buffers
408 -- , slidingChunkBuffer
409 -- , slidingSessionBuffer
411 -- * Combining Streams
446 -- ** Folding Containers of Streams
451 -- Flattening Nested Streams
452 -- ** Folding Streams of Streams
457 -- XXX add stateful concatMapWith?
461 -- ** Flattening Using Unfolds
463 , concatUnfoldInterleave
464 , concatUnfoldRoundrobin
467 , concatMapIterateWith
470 , concatMapTreeYieldLeavesWith
473 -- ** Inserting Streams in Streams
493 -- * Generalize Inner Monad
497 -- * Transform Inner Monad
523import Control.Concurrent (threadDelay)
524import Control.Exception (Exception, assert)
525import Control.Monad (void)
526import Control.Monad.Catch (MonadCatch, MonadThrow)
527import Control.Monad.IO.Class (MonadIO(..))
528import Control.Monad.Trans.Reader (ReaderT)
529import Control.Monad.Trans.State.Strict (StateT)
530import Control.Monad.Trans.Class (MonadTrans(..))
531import Control.Monad.Trans.Control (MonadBaseControl)
532import Data.Functor.Identity (Identity (..))
533import Data.Kind (Type)
534import Data.Heap (Entry(..))
535import Data.Maybe (isJust, fromJust, isNothing)
536import Data.Void (Void)
537import Foreign.Storable (Storable)
538import Streamly.Internal.Data.Stream.Enumeration
539 (Enumerable(..), enumerate, enumerateTo)
540import Streamly.Internal.Data.Fold.Types (Fold (..), Fold2 (..))
541import Streamly.Internal.Data.Parser (Parser (..))
542import Streamly.Internal.Data.Unfold.Types (Unfold)
543import Streamly.Internal.Memory.Array.Types (Array, writeNUnsafe)
544import Streamly.Internal.Data.SVar (MonadAsync, defState, Rate)
545import Streamly.Internal.Data.Stream.Combinators (inspectMode, maxYields)
546import Streamly.Internal.Data.Stream.Prelude
547 (fromStreamS, toStreamS, foldWith, foldMapWith, forEachWith)
548import Streamly.Internal.Data.Stream.StreamD (fromStreamD, toStreamD)
549import Streamly.Internal.Data.Stream.StreamK (IsStream((|:), consM))
550import Streamly.Internal.Data.Stream.Serial (SerialT, WSerialT)
551import Streamly.Internal.Data.Stream.Zip (ZipSerialM)
552import Streamly.Internal.Data.Pipe.Types (Pipe (..))
553import Streamly.Internal.Data.Time.Units
554 ( AbsTime, MilliSecond64(..), addToAbsTime, toRelTime
555 , toAbsTime, TimeUnit64, RelTime64, addToAbsTime64)
556import Streamly.Internal.Data.IORef.Prim (Prim, IORef)
557import Streamly.Internal.Data.Tuple.Strict (Tuple'(..))
559import qualified Streamly.Internal.Memory.Array as A
560import qualified Streamly.Data.Fold as FL
561import qualified Streamly.Internal.Data.Fold.Types as FL
562import qualified Streamly.Internal.Data.Stream.Prelude as P
563import qualified Streamly.Internal.Data.Stream.StreamK as K
564import qualified Streamly.Internal.Data.Stream.StreamD as D
565import qualified Streamly.Internal.Data.Stream.Serial as Serial
566import qualified Streamly.Internal.Data.Stream.Parallel as Par
567import qualified Streamly.Internal.Data.Stream.Zip as Z
568import qualified Streamly.Internal.Data.Parser.ParserK.Types as PRK
569import qualified Streamly.Internal.Data.Parser.ParserD as PRD
570import qualified Data.Heap as H
571import qualified Data.Map.Strict as Map
572import qualified Prelude
573import qualified System.IO as IO
574#ifdef USE_STREAMK_ONLY
575import qualified Streamly.Internal.Data.Stream.StreamK as S
577import qualified Streamly.Internal.Data.Stream.StreamD as S
581 ( filter, drop, dropWhile, take, takeWhile, zipWith, foldr
582 , foldl, map, mapM, mapM_, sequence, all, any, sum, product, elem
583 , notElem, maximum, minimum, head, last, tail, length, null
584 , reverse, iterate, init, and, or, lookup, foldr1, (!!)
585 , scanl, scanl1, replicate, concatMap, span, splitAt, break
586 , repeat, concat, mconcat)
588------------------------------------------------------------------------------
590------------------------------------------------------------------------------
592-- | Decompose a stream into its head and tail. If the stream is empty, returns
593-- 'Nothing'. If the stream is non-empty, returns @Just (a, ma)@, where @a@ is
594-- the head of the stream and @ma@ its tail.
596-- This is a brute force primitive. Avoid using it as long as possible, use it
597-- when no other combinator can do the job. This can be used to do pretty much
598-- anything in an imperative manner, as it just breaks down the stream into
599-- individual elements and we can loop over them as we deem fit. For example,
600-- this can be used to convert a streamly stream into other stream types.
604uncons :: (IsStream t, Monad m) => SerialT m a -> m (Maybe (a, t m a))
605uncons m = K.uncons (K.adapt m)
607------------------------------------------------------------------------------
608-- Generation by Unfolding
609------------------------------------------------------------------------------
616-- Just (a, b) -> a \`cons` unfoldr step b
619-- Build a stream by unfolding a /pure/ step function @step@ starting from a
620-- seed @s@. The step function returns the next element in the stream and the
621-- next seed value. When it is done it returns 'Nothing' and the stream ends.
628-- else Just (b, b + 1)
629-- in toList $ unfoldr f 0
636{-# INLINE_EARLY unfoldr #-}
637unfoldr :: (Monad m, IsStream t) => (b -> Maybe (a, b)) -> b -> t m a
638unfoldr step seed = fromStreamS (S.unfoldr step seed)
639{-# RULES "unfoldr fallback to StreamK" [1]
640 forall a b. S.toStreamK (S.unfoldr a b) = K.unfoldr a b #-}
642-- | Build a stream by unfolding a /monadic/ step function starting from a
643-- seed. The step function returns the next element in the stream and the next
644-- seed value. When it is done it returns 'Nothing' and the stream ends. For
650-- then return Nothing
651-- else print b >> return (Just (b, b + 1))
652-- in drain $ unfoldrM f 0
660-- When run concurrently, the next unfold step can run concurrently with the
661-- processing of the output of the previous step. Note that more than one step
662-- cannot run concurrently as the next step depends on the output of the
666-- (asyncly $ S.unfoldrM (\\n -> liftIO (threadDelay 1000000) >> return (Just (n, n + 1))) 0)
667-- & S.foldlM' (\\_ a -> threadDelay 1000000 >> print a) ()
673{-# INLINE_EARLY unfoldrM #-}
674unfoldrM :: (IsStream t, MonadAsync m) => (b -> m (Maybe (a, b))) -> b -> t m a
677{-# RULES "unfoldrM serial" unfoldrM = unfoldrMSerial #-}
678{-# INLINE_EARLY unfoldrMSerial #-}
679unfoldrMSerial :: MonadAsync m => (b -> m (Maybe (a, b))) -> b -> SerialT m a
680unfoldrMSerial = Serial.unfoldrM
682{-# RULES "unfoldrM wSerial" unfoldrM = unfoldrMWSerial #-}
683{-# INLINE_EARLY unfoldrMWSerial #-}
684unfoldrMWSerial :: MonadAsync m => (b -> m (Maybe (a, b))) -> b -> WSerialT m a
685unfoldrMWSerial = Serial.unfoldrM
687{-# RULES "unfoldrM zipSerial" unfoldrM = unfoldrMZipSerial #-}
688{-# INLINE_EARLY unfoldrMZipSerial #-}
689unfoldrMZipSerial :: MonadAsync m => (b -> m (Maybe (a, b))) -> b -> ZipSerialM m a
690unfoldrMZipSerial = Serial.unfoldrM
692-- | Convert an 'Unfold' into a stream by supplying it an input seed.
694-- >>> unfold (UF.replicateM 10) (putStrLn "hello")
698unfold :: (IsStream t, Monad m) => Unfold m a b -> a -> t m b
699unfold unf x = fromStreamD $ D.unfold unf x
701-- | Convert an 'Unfold' with a closed input end into a stream.
704{-# INLINE unfold0 #-}
705unfold0 :: (IsStream t, Monad m) => Unfold m Void b -> t m b
706unfold0 unf = unfold unf (error "unfold0: unexpected void evaluation")
708------------------------------------------------------------------------------
709-- Specialized Generation
710------------------------------------------------------------------------------
712-- Faster than yieldM because there is no bind.
716-- yield a = a \`cons` nil
719-- Create a singleton stream from a pure value.
721-- The following holds in monadic streams, but not in Zip streams:
725-- yield = yieldM . pure
728-- In Zip applicative streams 'yield' is not the same as 'pure' because in that
729-- case 'pure' is equivalent to 'repeat' instead. 'yield' and 'pure' are
730-- equally efficient, in other cases 'yield' may be slightly more efficient
731-- than the other equivalent definitions.
735yield :: IsStream t => a -> t m a
740-- yieldM m = m \`consM` nil
743-- Create a singleton stream from a monadic action.
746-- > toList $ yieldM getLine
753yieldM :: (Monad m, IsStream t) => m a -> t m a
758-- fromIndices f = let g i = f i \`cons` g (i + 1) in g 0
761-- Generate an infinite stream, whose values are the output of a function @f@
762-- applied on the corresponding index. Index starts at 0.
765-- > S.toList $ S.take 5 $ S.fromIndices id
770{-# INLINE fromIndices #-}
771fromIndices :: (IsStream t, Monad m) => (Int -> a) -> t m a
772fromIndices = fromStreamS . S.fromIndices
777-- fromIndicesM f = let g i = f i \`consM` g (i + 1) in g 0
780-- Generate an infinite stream, whose values are the output of a monadic
781-- function @f@ applied on the corresponding index. Index starts at 0.
786{-# INLINE_EARLY fromIndicesM #-}
787fromIndicesM :: (IsStream t, MonadAsync m) => (Int -> m a) -> t m a
788fromIndicesM = K.fromIndicesM
790{-# RULES "fromIndicesM serial" fromIndicesM = fromIndicesMSerial #-}
791{-# INLINE fromIndicesMSerial #-}
792fromIndicesMSerial :: MonadAsync m => (Int -> m a) -> SerialT m a
793fromIndicesMSerial = fromStreamS . S.fromIndicesM
797-- replicateM = take n . repeatM
800-- Generate a stream by performing a monadic action @n@ times. Same as:
803-- drain $ serially $ S.replicateM 10 $ (threadDelay 1000000 >> print 1)
804-- drain $ asyncly $ S.replicateM 10 $ (threadDelay 1000000 >> print 1)
810{-# INLINE_EARLY replicateM #-}
811replicateM :: (IsStream t, MonadAsync m) => Int -> m a -> t m a
812replicateM = K.replicateM
814{-# RULES "replicateM serial" replicateM = replicateMSerial #-}
815{-# INLINE replicateMSerial #-}
816replicateMSerial :: MonadAsync m => Int -> m a -> SerialT m a
817replicateMSerial n = fromStreamS . S.replicateM n
821-- replicate = take n . repeat
824-- Generate a stream of length @n@ by repeating a value @n@ times.
827{-# INLINE_NORMAL replicate #-}
828replicate :: (IsStream t, Monad m) => Int -> a -> t m a
829replicate n = fromStreamS . S.replicate n
832-- Generate an infinite stream by repeating a pure value.
835{-# INLINE_NORMAL repeat #-}
836repeat :: (IsStream t, Monad m) => a -> t m a
837repeat = fromStreamS . S.repeat
841-- repeatM = fix . consM
842-- repeatM = cycle1 . yieldM
845-- Generate a stream by repeatedly executing a monadic action forever.
848-- drain $ serially $ S.take 10 $ S.repeatM $ (threadDelay 1000000 >> print 1)
849-- drain $ asyncly $ S.take 10 $ S.repeatM $ (threadDelay 1000000 >> print 1)
852-- /Concurrent, infinite (do not use with 'parallely')/
855{-# INLINE_EARLY repeatM #-}
856repeatM :: (IsStream t, MonadAsync m) => m a -> t m a
859{-# RULES "repeatM serial" repeatM = repeatMSerial #-}
860{-# INLINE repeatMSerial #-}
861repeatMSerial :: MonadAsync m => m a -> SerialT m a
862repeatMSerial = fromStreamS . S.repeatM
866-- iterate f x = x \`cons` iterate f x
869-- Generate an infinite stream with @x@ as the first element and each
870-- successive element derived by applying the function @f@ on the previous
874-- > S.toList $ S.take 5 $ S.iterate (+1) 1
879{-# INLINE_NORMAL iterate #-}
880iterate :: (IsStream t, Monad m) => (a -> a) -> a -> t m a
881iterate step = fromStreamS . S.iterate step
885-- iterateM f m = m >>= \a -> return a \`consM` iterateM f (f a)
888-- Generate an infinite stream with the first element generated by the action
889-- @m@ and each successive element derived by applying the monadic function
890-- @f@ on the previous element.
892-- When run concurrently, the next iteration can run concurrently with the
893-- processing of the previous iteration. Note that more than one iteration
894-- cannot run concurrently as the next iteration depends on the output of the
895-- previous iteration.
898-- drain $ serially $ S.take 10 $ S.iterateM
899-- (\\x -> threadDelay 1000000 >> print x >> return (x + 1)) (return 0)
901-- drain $ asyncly $ S.take 10 $ S.iterateM
902-- (\\x -> threadDelay 1000000 >> print x >> return (x + 1)) (return 0)
907-- /Since: 0.7.0 (signature change)/
910{-# INLINE_EARLY iterateM #-}
911iterateM :: (IsStream t, MonadAsync m) => (a -> m a) -> m a -> t m a
914{-# RULES "iterateM serial" iterateM = iterateMSerial #-}
915{-# INLINE iterateMSerial #-}
916iterateMSerial :: MonadAsync m => (a -> m a) -> m a -> SerialT m a
917iterateMSerial step = fromStreamS . S.iterateM step
919------------------------------------------------------------------------------
921------------------------------------------------------------------------------
925-- fromListM = 'Prelude.foldr' 'K.consM' 'K.nil'
928-- Construct a stream from a list of monadic actions. This is more efficient
929-- than 'fromFoldableM' for serial streams.
932{-# INLINE_EARLY fromListM #-}
933fromListM :: (MonadAsync m, IsStream t) => [m a] -> t m a
934fromListM = fromStreamD . D.fromListM
935{-# RULES "fromListM fallback to StreamK" [1]
936 forall a. D.toStreamK (D.fromListM a) = fromFoldableM a #-}
940-- fromFoldableM = 'Prelude.foldr' 'consM' 'K.nil'
943-- Construct a stream from a 'Foldable' containing monadic actions.
946-- drain $ serially $ S.fromFoldableM $ replicateM 10 (threadDelay 1000000 >> print 1)
947-- drain $ asyncly $ S.fromFoldableM $ replicateM 10 (threadDelay 1000000 >> print 1)
950-- /Concurrent (do not use with 'parallely' on infinite containers)/
953{-# INLINE fromFoldableM #-}
954fromFoldableM :: (IsStream t, MonadAsync m, Foldable f) => f (m a) -> t m a
955fromFoldableM = Prelude.foldr consM K.nil
957-- | Same as 'fromFoldable'.
960{-# DEPRECATED each "Please use fromFoldable instead." #-}
962each :: (IsStream t, Foldable f) => f a -> t m a
965-- | Read lines from an IO Handle into a stream of Strings.
968{-# DEPRECATED fromHandle
969 "Please use Streamly.FileSystem.Handle module (see the changelog)" #-}
970fromHandle :: (IsStream t, MonadIO m) => IO.Handle -> t m String
973 go = K.mkStream $ \_ yld _ stp -> do
974 eof <- liftIO $ IO.hIsEOF h
978 str <- liftIO $ IO.hGetLine h
981-- | Construct a stream by reading a 'Prim' 'IORef' repeatedly.
985{-# INLINE fromPrimIORef #-}
986fromPrimIORef :: (IsStream t, MonadIO m, Prim a) => IORef a -> t m a
987fromPrimIORef = fromStreamD . D.fromPrimIORef
989-- | Takes a callback setter function and provides it with a callback. The
990-- callback when invoked adds a value at the tail of the stream. Returns a
991-- stream of values generated by the callback.
995{-# INLINE fromCallback #-}
996fromCallback :: MonadAsync m => ((a -> m ()) -> m ()) -> SerialT m a
997fromCallback setCallback = concatM $ do
998 (callback, stream) <- D.newCallbackStream
1002------------------------------------------------------------------------------
1004------------------------------------------------------------------------------
1006-- | @timesWith g@ returns a stream of time value tuples. The first component
1007-- of the tuple is an absolute time reference (epoch) denoting the start of the
1008-- stream and the second component is a time relative to the reference.
1010-- The argument @g@ specifies the granularity of the relative time in seconds.
1011-- A lower granularity clock gives higher precision but is more expensive in
1012-- terms of CPU usage. Any granularity lower than 1 ms is treated as 1 ms.
1015-- >>> S.mapM_ (\x -> print x >> threadDelay 1000000) $ S.timesWith 0.01
1016-- > (AbsTime (TimeSpec {sec = 2496295, nsec = 536223000}),RelTime64 (NanoSecond64 0))
1017-- > (AbsTime (TimeSpec {sec = 2496295, nsec = 536223000}),RelTime64 (NanoSecond64 1002028000))
1018-- > (AbsTime (TimeSpec {sec = 2496295, nsec = 536223000}),RelTime64 (NanoSecond64 1996656000))
1021-- Note: This API is not safe on 32-bit machines.
1025{-# INLINE timesWith #-}
1026timesWith :: (IsStream t, MonadAsync m) => Double -> t m (AbsTime, RelTime64)
1027timesWith g = fromStreamD $ D.times g
1029-- | @times@ returns a stream of time value tuples with clock of 10 ms
1030-- granularity. The first component of the tuple is an absolute time reference
1031-- (epoch) denoting the start of the stream and the second component is a time
1032-- relative to the reference.
1035-- >>> S.mapM_ (\x -> print x >> threadDelay 1000000) $ S.times
1036-- > (AbsTime (TimeSpec {sec = 2496295, nsec = 536223000}),RelTime64 (NanoSecond64 0))
1037-- > (AbsTime (TimeSpec {sec = 2496295, nsec = 536223000}),RelTime64 (NanoSecond64 1002028000))
1038-- > (AbsTime (TimeSpec {sec = 2496295, nsec = 536223000}),RelTime64 (NanoSecond64 1996656000))
1041-- Note: This API is not safe on 32-bit machines.
1046times :: (IsStream t, MonadAsync m) => t m (AbsTime, RelTime64)
1047times = timesWith 0.01
1049-- | @absTimesWith g@ returns a stream of absolute timestamps using a clock of
1050-- granularity @g@ specified in seconds. A low granularity clock is more
1051-- expensive in terms of CPU usage. Any granularity lower than 1 ms is treated
1055-- >>> S.mapM_ print $ S.delayPre 1 $ S.absTimesWith 0.01
1058-- Note: This API is not safe on 32-bit machines.
1062{-# INLINE absTimesWith #-}
1063absTimesWith :: (IsStream t, MonadAsync m, Functor (t m))
1064 => Double -> t m AbsTime
1065absTimesWith = fmap (uncurry addToAbsTime64) . timesWith
1067-- | @absTimes@ returns a stream of absolute timestamps using a clock of 10 ms
1071-- >>> S.mapM_ print $ S.delayPre 1 $ S.absTimes
1074-- Note: This API is not safe on 32-bit machines.
1078{-# INLINE absTimes #-}
1079absTimes :: (IsStream t, MonadAsync m, Functor (t m)) => t m AbsTime
1080absTimes = fmap (uncurry addToAbsTime64) times
1082{-# DEPRECATED currentTime "Please use absTimes instead" #-}
1083{-# INLINE currentTime #-}
1084currentTime :: (IsStream t, MonadAsync m, Functor (t m))
1085 => Double -> t m AbsTime
1086currentTime = absTimesWith
1088-- | @relTimesWith g@ returns a stream of relative time values starting from 0,
1089-- using a clock of granularity @g@ specified in seconds. A low granularity
1090-- clock is more expensive in terms of CPU usage. Any granularity lower than 1
1091-- ms is treated as 1 ms.
1094-- >>> S.mapM_ print $ S.delayPre 1 $ S.relTimesWith 0.01
1095-- > RelTime64 (NanoSecond64 0)
1096-- > RelTime64 (NanoSecond64 91139000)
1097-- > RelTime64 (NanoSecond64 204052000)
1100-- Note: This API is not safe on 32-bit machines.
1104{-# INLINE relTimesWith #-}
1105relTimesWith :: (IsStream t, MonadAsync m, Functor (t m))
1106 => Double -> t m RelTime64
1107relTimesWith = fmap snd . timesWith
1109-- | @relTimes@ returns a stream of relative time values starting from 0,
1110-- using a clock of granularity 10 ms.
1113-- >>> S.mapM_ print $ S.delayPre 1 $ S.relTimes
1116-- Note: This API is not safe on 32-bit machines.
1120{-# INLINE relTimes #-}
1121relTimes :: (IsStream t, MonadAsync m, Functor (t m)) => t m RelTime64
1122relTimes = fmap snd times
1124-- | @durations g@ returns a stream of relative time values measuring the time
1125-- elapsed since the immediate predecessor element of the stream was generated.
1126-- The first element of the stream is always 0. @durations@ uses a clock of
1127-- granularity @g@ specified in seconds. A low granularity clock is more
1128-- expensive in terms of CPU usage. The minimum granularity is 1 millisecond.
1129-- Durations lower than 1 ms will be 0.
1131-- Note: This API is not safe on 32-bit machines.
1135{-# INLINE durations #-}
1136durations :: -- (IsStream t, MonadAsync m) =>
1137 Double -> t m RelTime64
1138durations = undefined
1140-- | Generate ticks at the specified rate. The rate is adaptive, the tick
1141-- generation speed can be increased or decreased at different times to achieve
1142-- the specified rate. The specific behavior for different styles of 'Rate'
1143-- specifications is documented under 'Rate'. The effective maximum rate
1144-- achieved by a stream is governed by the processor speed.
1149ticks :: -- (IsStream t, MonadAsync m) =>
1153-- | Generate a singleton event at or after the specified absolute time. Note
1154-- that this is different from a threadDelay, a threadDelay starts from the
1155-- time when the action is evaluated, whereas if we use AbsTime based timeout
1156-- it will immediately expire if the action is evaluated too late.
1160{-# INLINE timeout #-}
1161timeout :: -- (IsStream t, MonadAsync m) =>
1165------------------------------------------------------------------------------
1166-- Elimination by Folding
1167------------------------------------------------------------------------------
1169-- | Right associative/lazy pull fold. @foldrM build final stream@ constructs
1170-- an output structure using the step function @build@. @build@ is invoked with
1171-- the next input element and the remaining (lazy) tail of the output
1172-- structure. It builds a lazy output expression using the two. When the "tail
1173-- structure" in the output expression is evaluated it calls @build@ again thus
1174-- lazily consuming the input @stream@ until either the output expression built
1175-- by @build@ is free of the "tail" or the input is exhausted in which case
1176-- @final@ is used as the terminating case for the output structure. For more
1177-- details see the description in the previous section.
1179-- Example, determine if any element is 'odd' in a stream:
1181-- >>> S.foldrM (\x xs -> if odd x then return True else xs) (return False) $ S.fromList (2:4:5:undefined)
1184-- /Since: 0.7.0 (signature changed)/
1186-- /Since: 0.2.0 (signature changed)/
1189{-# INLINE foldrM #-}
1190foldrM :: Monad m => (a -> m b -> m b) -> m b -> SerialT m a -> m b
1193-- | Right fold to a streaming monad.
1195-- > foldrS S.cons S.nil === id
1197-- 'foldrS' can be used to perform stateless stream to stream transformations
1198-- like map and filter in general. It can be coupled with a scan to perform
1199-- stateful transformations. However, note that the custom map and filter
1200-- routines can be much more efficient than this due to better stream fusion.
1202-- >>> S.toList $ S.foldrS S.cons S.nil $ S.fromList [1..5]
1205-- Find if any element in the stream is 'True':
1207-- >>> S.toList $ S.foldrS (\x xs -> if odd x then return True else xs) (return False) $ (S.fromList (2:4:5:undefined) :: SerialT IO Int)
1210-- Map (+2) on odd elements and filter out the even elements:
1212-- >>> S.toList $ S.foldrS (\x xs -> if odd x then (x + 2) `S.cons` xs else xs) S.nil $ (S.fromList [1..5] :: SerialT IO Int)
1215-- 'foldrM' can also be represented in terms of 'foldrS', however, the former
1216-- is much more efficient:
1218-- > foldrM f z s = runIdentityT $ foldrS (\x xs -> lift $ f x (runIdentityT xs)) (lift z) s
1221{-# INLINE foldrS #-}
1222foldrS :: IsStream t => (a -> t m b -> t m b) -> t m b -> t m a -> t m b
1225-- | Right fold to a transformer monad. This is the most general right fold
1226-- function. 'foldrS' is a special case of 'foldrT', however 'foldrS'
1227-- implementation can be more efficient:
1230-- > foldrM f z s = runIdentityT $ foldrT (\x xs -> lift $ f x (runIdentityT xs)) (lift z) s
1232-- 'foldrT' can be used to translate streamly streams to other transformer
1233-- monads e.g. to a different streaming type.
1236{-# INLINE foldrT #-}
1237foldrT :: (IsStream t, Monad m, Monad (s m), MonadTrans s)
1238 => (a -> s m b -> s m b) -> s m b -> t m a -> s m b
1239foldrT f z s = S.foldrT f z (toStreamS s)
1241-- | Right fold, lazy for lazy monads and pure streams, and strict for strict
1244-- Please avoid using this routine in strict monads like IO unless you need a
1245-- strict right fold. This is provided only for use in lazy monads (e.g.
1246-- Identity) or pure streams. Note that with this signature it is not possible
1247-- to implement a lazy foldr when the monad @m@ is strict. In that case it
1248-- would be strict in its accumulator and therefore would necessarily consume
1253foldr :: Monad m => (a -> b -> b) -> b -> SerialT m a -> m b
1256-- XXX This seems to be of limited use as it cannot be used to construct
1257-- recursive structures and for reduction foldl1' is better.
1259-- | Lazy right fold for non-empty streams, using first element as the starting
1260-- value. Returns 'Nothing' if the stream is empty.
1263{-# INLINE foldr1 #-}
1264{-# DEPRECATED foldr1 "Use foldrM instead." #-}
1265foldr1 :: Monad m => (a -> a -> a) -> SerialT m a -> m (Maybe a)
1266foldr1 f m = S.foldr1 f (toStreamS m)
1268-- | Strict left fold with an extraction function. Like the standard strict
1269-- left fold, but applies a user supplied extraction function (the third
1270-- argument) to the folded value at the end. This is designed to work with the
1271-- @foldl@ library. The suffix @x@ is a mnemonic for extraction.
1274{-# DEPRECATED foldx "Please use foldl' followed by fmap instead." #-}
1276foldx :: Monad m => (x -> a -> x) -> x -> (x -> b) -> SerialT m a -> m b
1279-- | Left associative/strict push fold. @foldl' reduce initial stream@ invokes
1280-- @reduce@ with the accumulator and the next input in the input stream, using
1281-- @initial@ as the initial value of the current value of the accumulator. When
1282-- the input is exhausted the current value of the accumulator is returned.
1283-- Make sure to use a strict data structure for accumulator to not build
1284-- unnecessary lazy expressions unless that's what you want. See the previous
1285-- section for more details.
1288{-# INLINE foldl' #-}
1289foldl' :: Monad m => (b -> a -> b) -> b -> SerialT m a -> m b
1292-- | Strict left fold, for non-empty streams, using first element as the
1293-- starting value. Returns 'Nothing' if the stream is empty.
1296{-# INLINE foldl1' #-}
1297foldl1' :: Monad m => (a -> a -> a) -> SerialT m a -> m (Maybe a)
1301 Nothing -> return Nothing
1303 res <- foldl' step h t
1306-- | Like 'foldx', but with a monadic step function.
1309{-# DEPRECATED foldxM "Please use foldlM' followed by fmap instead." #-}
1310{-# INLINE foldxM #-}
1311foldxM :: Monad m => (x -> a -> m x) -> m x -> (x -> m b) -> SerialT m a -> m b
1314-- | Like 'foldl'' but with a monadic step function.
1317{-# INLINE foldlM' #-}
1318foldlM' :: Monad m => (b -> a -> m b) -> m b -> SerialT m a -> m b
1319foldlM' step begin m = S.foldlM' step begin $ toStreamS m
1321------------------------------------------------------------------------------
1323------------------------------------------------------------------------------
1325-- | Fold a stream using the supplied left fold.
1327-- >>> S.fold FL.sum (S.enumerateFromTo 1 100)
1332fold :: Monad m => Fold m a b -> SerialT m a -> m b
1335------------------------------------------------------------------------------
1337------------------------------------------------------------------------------
1340-- | Drain a stream to a 'Sink'.
1341{-# INLINE runSink #-}
1342runSink :: Monad m => Sink m a -> SerialT m a -> m ()
1343runSink = fold . toFold
1346------------------------------------------------------------------------------
1348------------------------------------------------------------------------------
1350-- | Parse a stream using the supplied 'Parser'.
1354{-# INLINE_NORMAL parseD #-}
1355parseD :: MonadThrow m => PRD.Parser m a b -> SerialT m a -> m b
1356parseD (PRD.Parser step initial extract) = P.parselMx' step initial extract
1358{-# INLINE parseK #-}
1359parseK :: MonadThrow m => PRK.Parser m a b -> SerialT m a -> m b
1362-- | Parse a stream using the supplied 'Parser'.
1366{-# INLINE [3] parse #-}
1367parse :: MonadThrow m => Parser m a b -> SerialT m a -> m b
1368parse = parseD . PRK.fromParserK
1370------------------------------------------------------------------------------
1372------------------------------------------------------------------------------
1375-- > drain = mapM_ (\_ -> return ())
1377-- Run a stream, discarding the results. By default it interprets the stream
1378-- as 'SerialT', to run other types of streams use the type adapting
1379-- combinators for example @drain . 'asyncly'@.
1383drain :: Monad m => SerialT m a -> m ()
1386-- | Run a stream, discarding the results. By default it interprets the stream
1387-- as 'SerialT', to run other types of streams use the type adapting
1388-- combinators for example @runStream . 'asyncly'@.
1391{-# DEPRECATED runStream "Please use \"drain\" instead" #-}
1392{-# INLINE runStream #-}
1393runStream :: Monad m => SerialT m a -> m ()
1397-- > drainN n = drain . take n
1399-- Run maximum up to @n@ iterations of a stream.
1402{-# INLINE drainN #-}
1403drainN :: Monad m => Int -> SerialT m a -> m ()
1404drainN n = drain . take n
1407-- > runN n = runStream . take n
1409-- Run maximum up to @n@ iterations of a stream.
1412{-# DEPRECATED runN "Please use \"drainN\" instead" #-}
1414runN :: Monad m => Int -> SerialT m a -> m ()
1418-- > drainWhile p = drain . takeWhile p
1420-- Run a stream as long as the predicate holds true.
1423{-# INLINE drainWhile #-}
1424drainWhile :: Monad m => (a -> Bool) -> SerialT m a -> m ()
1425drainWhile p = drain . takeWhile p
1428-- > runWhile p = runStream . takeWhile p
1430-- Run a stream as long as the predicate holds true.
1433{-# DEPRECATED runWhile "Please use \"drainWhile\" instead" #-}
1434{-# INLINE runWhile #-}
1435runWhile :: Monad m => (a -> Bool) -> SerialT m a -> m ()
1436runWhile = drainWhile
1438-- | Determine whether the stream is empty.
1442null :: Monad m => SerialT m a -> m Bool
1443null = S.null . toStreamS
1445-- | Extract the first element of the stream, if any.
1451head :: Monad m => SerialT m a -> m (Maybe a)
1452head = S.head . toStreamS
1454-- | Extract the first element of the stream, if any, otherwise use the
1455-- supplied default value. It can help avoid one branch in high performance
1459{-# INLINE headElse #-}
1460headElse :: Monad m => a -> SerialT m a -> m a
1461headElse x = D.headElse x . toStreamD
1464-- > tail = fmap (fmap snd) . uncons
1466-- Extract all but the first element of the stream, if any.
1470tail :: (IsStream t, Monad m) => SerialT m a -> m (Maybe (t m a))
1471tail m = K.tail (K.adapt m)
1473-- | Extract all but the last element of the stream, if any.
1477init :: (IsStream t, Monad m) => SerialT m a -> m (Maybe (t m a))
1478init m = K.init (K.adapt m)
1480-- | Extract the last element of the stream, if any.
1482-- > last xs = xs !! (length xs - 1)
1486last :: Monad m => SerialT m a -> m (Maybe a)
1487last m = S.last $ toStreamS m
1489-- | Determine whether an element is present in the stream.
1493elem :: (Monad m, Eq a) => a -> SerialT m a -> m Bool
1494elem e m = S.elem e (toStreamS m)
1496-- | Determine whether an element is not present in the stream.
1499{-# INLINE notElem #-}
1500notElem :: (Monad m, Eq a) => a -> SerialT m a -> m Bool
1501notElem e m = S.notElem e (toStreamS m)
1503-- | Determine the length of the stream.
1506{-# INLINE length #-}
1507length :: Monad m => SerialT m a -> m Int
1508length = foldl' (\n _ -> n + 1) 0
1510-- | Determine whether all elements of a stream satisfy a predicate.
1514all :: Monad m => (a -> Bool) -> SerialT m a -> m Bool
1515all p m = S.all p (toStreamS m)
1517-- | Determine whether any of the elements of a stream satisfy a predicate.
1521any :: Monad m => (a -> Bool) -> SerialT m a -> m Bool
1522any p m = S.any p (toStreamS m)
1524-- | Determines if all elements of a boolean stream are True.
1528and :: Monad m => SerialT m Bool -> m Bool
1531-- | Determines whether at least one element of a boolean stream is True.
1535or :: Monad m => SerialT m Bool -> m Bool
1538-- | Determine the sum of all elements of a stream of numbers. Returns @0@ when
1539-- the stream is empty. Note that this is not numerically stable for floating
1544sum :: (Monad m, Num a) => SerialT m a -> m a
1547-- | Determine the product of all elements of a stream of numbers. Returns @1@
1548-- when the stream is empty.
1551{-# INLINE product #-}
1552product :: (Monad m, Num a) => SerialT m a -> m a
1553product = foldl' (*) 1
1555-- | Fold a stream of monoid elements by appending them.
1558{-# INLINE mconcat #-}
1559mconcat :: (Monad m, Monoid a) => SerialT m a -> m a
1560mconcat = foldr mappend mempty
1564-- minimum = 'minimumBy' compare
1567-- Determine the minimum element in a stream.
1570{-# INLINE minimum #-}
1571minimum :: (Monad m, Ord a) => SerialT m a -> m (Maybe a)
1572minimum m = S.minimum (toStreamS m)
1574-- | Determine the minimum element in a stream using the supplied comparison
1578{-# INLINE minimumBy #-}
1579minimumBy :: Monad m => (a -> a -> Ordering) -> SerialT m a -> m (Maybe a)
1580minimumBy cmp m = S.minimumBy cmp (toStreamS m)
1584-- maximum = 'maximumBy' compare
1587-- Determine the maximum element in a stream.
1590{-# INLINE maximum #-}
1591maximum :: (Monad m, Ord a) => SerialT m a -> m (Maybe a)
1594-- | Determine the maximum element in a stream using the supplied comparison
1598{-# INLINE maximumBy #-}
1599maximumBy :: Monad m => (a -> a -> Ordering) -> SerialT m a -> m (Maybe a)
1600maximumBy cmp m = S.maximumBy cmp (toStreamS m)
1602-- | Lookup the element at the given index.
1606(!!) :: Monad m => SerialT m a -> Int -> m (Maybe a)
1607m !! i = toStreamS m S.!! i
1609-- | In a stream of (key-value) pairs @(a, b)@, return the value @b@ of the
1610-- first pair where the key equals the given value @a@.
1612-- > lookup = snd <$> find ((==) . fst)
1615{-# INLINE lookup #-}
1616lookup :: (Monad m, Eq a) => a -> SerialT m (a, b) -> m (Maybe b)
1617lookup a m = S.lookup a (toStreamS m)
1619-- | Like 'findM' but with a non-monadic predicate.
1621-- > find p = findM (return . p)
1625find :: Monad m => (a -> Bool) -> SerialT m a -> m (Maybe a)
1626find p m = S.find p (toStreamS m)
1628-- | Returns the first element that satisfies the given predicate.
1632findM :: Monad m => (a -> m Bool) -> SerialT m a -> m (Maybe a)
1633findM p m = S.findM p (toStreamS m)
1635-- | Find all the indices where the element in the stream satisfies the given
1639{-# INLINE findIndices #-}
1640findIndices :: (IsStream t, Monad m) => (a -> Bool) -> t m a -> t m Int
1641findIndices p m = fromStreamS $ S.findIndices p (toStreamS m)
1643-- | Returns the first index that satisfies the given predicate.
1646{-# INLINE findIndex #-}
1647findIndex :: Monad m => (a -> Bool) -> SerialT m a -> m (Maybe Int)
1648findIndex p = head . findIndices p
1650-- | Find all the indices where the value of the element in the stream is equal
1651-- to the given value.
1654{-# INLINE elemIndices #-}
1655elemIndices :: (IsStream t, Eq a, Monad m) => a -> t m a -> t m Int
1656elemIndices a = findIndices (==a)
1658-- | Returns the first index where a given value is found in the stream.
1660-- > elemIndex a = findIndex (== a)
1663{-# INLINE elemIndex #-}
1664elemIndex :: (Monad m, Eq a) => a -> SerialT m a -> m (Maybe Int)
1665elemIndex a = findIndex (== a)
1667------------------------------------------------------------------------------
1669------------------------------------------------------------------------------
1671-- | Returns 'True' if the first stream is the same as or a prefix of the
1672-- second. A stream is a prefix of itself.
1675-- > S.isPrefixOf (S.fromList "hello") (S.fromList "hello" :: SerialT IO Char)
1680{-# INLINE isPrefixOf #-}
1681isPrefixOf :: (Eq a, IsStream t, Monad m) => t m a -> t m a -> m Bool
1682isPrefixOf m1 m2 = D.isPrefixOf (toStreamD m1) (toStreamD m2)
1684-- Note: isPrefixOf uses the prefix stream only once. In contrast, isSuffixOf
1685-- may use the suffix stream many times. To run in optimal memory we do not
1686-- want to buffer the suffix stream in memory therefore we need an ability to
1687-- clone (or consume it multiple times) the suffix stream without any side
1688-- effects so that multiple potential suffix matches can proceed in parallel
1689-- without buffering the suffix stream. For example, we may create the suffix
1690-- stream from a file handle, however, if we evaluate the stream multiple
1691-- times, once for each match, we will need a different file handle each time
1692-- which may exhaust the file descriptors. Instead, we want to share the same
1693-- underlying file descriptor, use pread on it to generate the stream and clone
1694-- the stream for each match. Therefore the suffix stream should be built in
1695-- such a way that it can be consumed multiple times without any problems.
1697-- XXX Can be implemented with better space/time complexity.
1698-- Space: @O(n)@ worst case where @n@ is the length of the suffix.
1700-- | Returns 'True' if the first stream is a suffix of the second. A stream is
1701-- considered a suffix of itself.
1704-- > S.isSuffixOf (S.fromList "hello") (S.fromList "hello" :: SerialT IO Char)
1708-- Space: @O(n)@, buffers entire input stream and the suffix.
1712-- /Suboptimal/ - Help wanted.
1714{-# INLINE isSuffixOf #-}
1715isSuffixOf :: (Monad m, Eq a) => SerialT m a -> SerialT m a -> m Bool
1716isSuffixOf suffix stream = reverse suffix `isPrefixOf` reverse stream
1718-- | Returns 'True' if the first stream is an infix of the second. A stream is
1719-- considered an infix of itself.
1722-- > S.isInfixOf (S.fromList "hello") (S.fromList "hello" :: SerialT IO Char)
1726-- Space: @O(n)@ worst case where @n@ is the length of the infix.
1730-- /Requires 'Storable' constraint/ - Help wanted.
1732{-# INLINE isInfixOf #-}
1733isInfixOf :: (MonadIO m, Eq a, Enum a, Storable a)
1734 => SerialT m a -> SerialT m a -> m Bool
1735isInfixOf infx stream = do
1736 arr <- fold A.write infx
1737 -- XXX can use breakOnSeq instead (when available)
1738 r <- null $ drop 1 $ splitOnSeq arr FL.drain stream
1741-- | Returns 'True' if all the elements of the first stream occur, in order, in
1742-- the second stream. The elements do not have to occur consecutively. A stream
1743-- is a subsequence of itself.
1746-- > S.isSubsequenceOf (S.fromList "hlo") (S.fromList "hello" :: SerialT IO Char)
1751{-# INLINE isSubsequenceOf #-}
1752isSubsequenceOf :: (Eq a, IsStream t, Monad m) => t m a -> t m a -> m Bool
1753isSubsequenceOf m1 m2 = D.isSubsequenceOf (toStreamD m1) (toStreamD m2)
1755-- | Strip prefix if present and tell whether it was stripped or not. Returns
1756-- 'Nothing' if the stream does not start with the given prefix, stripped
1757-- stream otherwise. Returns @Just nil@ when the prefix is the same as the
1763{-# INLINE stripPrefix #-}
1765 :: (Eq a, IsStream t, Monad m)
1766 => t m a -> t m a -> m (Maybe (t m a))
1767stripPrefix m1 m2 = fmap fromStreamD <$>
1768 D.stripPrefix (toStreamD m1) (toStreamD m2)
1770-- Note: If we want to return a Maybe value to know whether the
1771-- suffix/infix was present or not along with the stripped stream then
1772-- we need to buffer the whole input stream.
1774-- | Drops the given suffix from a stream. Returns 'Nothing' if the stream does
1775-- not end with the given suffix. Returns @Just nil@ when the suffix is the
1776-- same as the stream.
1778-- It may be more efficient to convert the stream to an Array and use
1779-- stripSuffix on that especially if the elements have a Storable or Prim
1782-- Space: @O(n)@, buffers the entire input stream as well as the suffix
1785{-# INLINE stripSuffix #-}
1788 => SerialT m a -> SerialT m a -> m (Maybe (SerialT m a))
1789stripSuffix m1 m2 = fmap reverse <$> stripPrefix (reverse m1) (reverse m2)
1791-- | Drop prefix from the input stream if present.
1795-- /Unimplemented/ - Help wanted.
1796{-# INLINE dropPrefix #-}
1798 -- (Eq a, IsStream t, Monad m) =>
1799 t m a -> t m a -> t m a
1800dropPrefix = error "Not implemented yet!"
1802-- | Drop all matching infix from the input stream if present. Infix stream
1803-- may be consumed multiple times.
1805-- Space: @O(n)@ where n is the length of the infix.
1807-- /Unimplemented/ - Help wanted.
1808{-# INLINE dropInfix #-}
1810 -- (Eq a, IsStream t, Monad m) =>
1811 t m a -> t m a -> t m a
1812dropInfix = error "Not implemented yet!"
1814-- | Drop suffix from the input stream if present. Suffix stream may be
1815-- consumed multiple times.
1817-- Space: @O(n)@ where n is the length of the suffix.
1819-- /Unimplemented/ - Help wanted.
1820{-# INLINE dropSuffix #-}
1822 -- (Eq a, IsStream t, Monad m) =>
1823 t m a -> t m a -> t m a
1824dropSuffix = error "Not implemented yet!"
1826------------------------------------------------------------------------------
1828------------------------------------------------------------------------------
1830-- XXX this can utilize parallel mapping if we implement it as drain . mapM
1832-- > mapM_ = drain . mapM
1834-- Apply a monadic action to each element of the stream and discard the output
1835-- of the action. This is not really a pure transformation operation but a
1836-- transformation followed by fold.
1840mapM_ :: Monad m => (a -> m b) -> SerialT m a -> m ()
1841mapM_ f m = S.mapM_ f $ toStreamS m
1843------------------------------------------------------------------------------
1845------------------------------------------------------------------------------
1849-- toList = S.foldr (:) []
1852-- Convert a stream into a list in the underlying monad. The list can be
1853-- consumed lazily in a lazy monad (e.g. 'Identity'). In a strict monad (e.g.
1854-- IO) the whole list is generated and buffered before it can be consumed.
1856-- /Warning!/ working on large lists accumulated as buffers in memory could be
1857-- very inefficient, consider using "Streamly.Array" instead.
1860{-# INLINE toList #-}
1861toList :: Monad m => SerialT m a -> m [a]
1866-- toListRev = S.foldl' (flip (:)) []
1869-- Convert a stream into a list in reverse order in the underlying monad.
1871-- /Warning!/ working on large lists accumulated as buffers in memory could be
1872-- very inefficient, consider using "Streamly.Array" instead.
1875{-# INLINE toListRev #-}
1876toListRev :: Monad m => SerialT m a -> m [a]
1877toListRev = D.toListRev . toStreamD
1881-- toHandle h = S.mapM_ $ hPutStrLn h
1884-- Write a stream of Strings to an IO Handle.
1887{-# DEPRECATED toHandle
1888 "Please use Streamly.FileSystem.Handle module (see the changelog)" #-}
1889toHandle :: MonadIO m => IO.Handle -> SerialT m String -> m ()
1893 let stop = return ()
1894 single a = liftIO (IO.hPutStrLn h a)
1895 yieldk a r = liftIO (IO.hPutStrLn h a) >> go r
1896 in K.foldStream defState yieldk single stop m1
1898-- XXX rename these to write/writeRev to make the naming consistent with folds
1901-- | A fold that buffers its input to a pure stream.
1903-- /Warning!/ working on large streams accumulated as buffers in memory could
1904-- be very inefficient, consider using "Streamly.Array" instead.
1907{-# INLINE toStream #-}
1908toStream :: Monad m => Fold m a (SerialT Identity a)
1909toStream = Fold (\f x -> return $ f . (x `K.cons`))
1911 (return . ($ K.nil))
1913-- This is more efficient than 'toStream'. toStream is exactly the same as
1914-- reversing the stream after toStreamRev.
1916-- | Buffers the input stream to a pure stream in the reverse order of the
1919-- /Warning!/ working on large streams accumulated as buffers in memory could
1920-- be very inefficient, consider using "Streamly.Array" instead.
1924-- xn : ... : x2 : x1 : []
1925{-# INLINABLE toStreamRev #-}
1926toStreamRev :: Monad m => Fold m a (SerialT Identity a)
1927toStreamRev = Fold (\xs x -> return $ x `K.cons` xs) (return K.nil) return
1929-- | Convert a stream to a pure stream.
1932-- toPure = foldr cons nil
1937{-# INLINE toPure #-}
1938toPure :: Monad m => SerialT m a -> m (SerialT Identity a)
1939toPure = foldr K.cons K.nil
1941-- | Convert a stream to a pure stream in reverse order.
1944-- toPureRev = foldl' (flip cons) nil
1949{-# INLINE toPureRev #-}
1950toPureRev :: Monad m => SerialT m a -> m (SerialT Identity a)
1951toPureRev = foldl' (flip K.cons) K.nil
1953------------------------------------------------------------------------------
1954-- Concurrent Application
1955------------------------------------------------------------------------------
1963-- | Parallel transform application operator; applies a stream transformation
1964-- function @t m a -> t m b@ to a stream @t m a@ concurrently; the input stream
1965-- is evaluated asynchronously in an independent thread yielding elements to a
1966-- buffer and the transformation function runs in another thread consuming the
1967-- input from the buffer. '|$' is just like regular function application
1968-- operator '$' except that it is concurrent.
1970-- If you read the signature as @(t m a -> t m b) -> (t m a -> t m b)@ you can
1971-- look at it as a transformation that converts a transform function to a
1972-- buffered concurrent transform function.
1974-- The following code prints a value every second even though each stage adds a
1980-- S.mapM (\\x -> threadDelay 1000000 >> print x)
1981-- |$ S.repeatM (threadDelay 1000000 >> return 1)
1988(|$) :: (IsStream t, MonadAsync m) => (t m a -> t m b) -> (t m a -> t m b)
1989-- (|$) f = f . Async.mkAsync
1990(|$) f = f . D.mkParallel
1996{-# INLINE applyAsync #-}
1997applyAsync :: (IsStream t, MonadAsync m)
1998 => (t m a -> t m b) -> (t m a -> t m b)
2001-- | Parallel reverse function application operator for streams; just like the
2002-- regular reverse function application operator '&' except that it is
2007-- S.repeatM (threadDelay 1000000 >> return 1)
2008-- |& S.mapM (\\x -> threadDelay 1000000 >> print x)
2015(|&) :: (IsStream t, MonadAsync m) => t m a -> (t m a -> t m b) -> t m b
2018-- | Parallel fold application operator; applies a fold function @t m a -> m b@
2019-- to a stream @t m a@ concurrently; The the input stream is evaluated
2020-- asynchronously in an independent thread yielding elements to a buffer and
2021-- the folding action runs in another thread consuming the input from the
2024-- If you read the signature as @(t m a -> m b) -> (t m a -> m b)@ you can look
2025-- at it as a transformation that converts a fold function to a buffered
2026-- concurrent fold function.
2028-- The @.@ at the end of the operator is a mnemonic for termination of the
2032-- S.foldlM' (\\_ a -> threadDelay 1000000 >> print a) ()
2033-- |$. S.repeatM (threadDelay 1000000 >> return 1)
2040(|$.) :: (IsStream t, MonadAsync m) => (t m a -> m b) -> (t m a -> m b)
2041-- (|$.) f = f . Async.mkAsync
2042(|$.) f = f . D.mkParallel
2048{-# INLINE foldAsync #-}
2049foldAsync :: (IsStream t, MonadAsync m) => (t m a -> m b) -> (t m a -> m b)
2052-- | Parallel reverse function application operator for applying a run or fold
2053-- functions to a stream. Just like '|$.' except that the operands are reversed.
2056-- S.repeatM (threadDelay 1000000 >> return 1)
2057-- |&. S.foldlM' (\\_ a -> threadDelay 1000000 >> print a) ()
2064(|&.) :: (IsStream t, MonadAsync m) => t m a -> (t m a -> m b) -> m b
2067------------------------------------------------------------------------------
2068-- General Transformation
2069------------------------------------------------------------------------------
2071-- | Use a 'Pipe' to transform a stream.
2075{-# INLINE transform #-}
2076transform :: (IsStream t, Monad m) => Pipe m a b -> t m a -> t m b
2077transform pipe xs = fromStreamD $ D.transform pipe (toStreamD xs)
2079------------------------------------------------------------------------------
2080-- Transformation by Folding (Scans)
2081------------------------------------------------------------------------------
2083-- XXX It may be useful to have a version of scan where we can keep the
2084-- accumulator independent of the value emitted. So that we do not necessarily
2085-- have to keep a value in the accumulator which we are not using. We can pass
2086-- an extraction function that will take the accumulator and the current value
2087-- of the element and emit the next value in the stream. That will also make it
2088-- possible to modify the accumulator after using it. In fact, the step function
2089-- can return new accumulator and the value to be emitted. The signature would
2090-- be more like mapAccumL. Or we can change the signature of scanx to
2093-- | Strict left scan with an extraction function. Like 'scanl'', but applies a
2094-- user supplied extraction function (the third argument) at each step. This is
2095-- designed to work with the @foldl@ library. The suffix @x@ is a mnemonic for
2098-- /Since: 0.7.0 (Monad m constraint)/
2101{-# DEPRECATED scanx "Please use scanl followed by map instead." #-}
2103scanx :: (IsStream t, Monad m) => (x -> a -> x) -> x -> (x -> b) -> t m a -> t m b
2106-- XXX this needs to be concurrent
2107-- XXX because of the use of D.cons for appending, scanlM' has quadratic
2108-- complexity when iterated over a stream. We should use StreamK style scanlM'
2109-- for linear performance on iteration.
2111-- | Like 'scanl'' but with a monadic fold function.
2114{-# INLINE scanlM' #-}
2115scanlM' :: (IsStream t, Monad m) => (b -> a -> m b) -> b -> t m a -> t m b
2116scanlM' step begin m = fromStreamD $ D.scanlM' step begin $ toStreamD m
2118-- | @scanlMAfter' accumulate initial done stream@ is like 'scanlM'' except
2119-- that it provides an additional @done@ function to be applied on the
2120-- accumulator when the stream stops. The result of @done@ is also emitted in
2123-- This function can be used to allocate a resource in the beginning of the
2124-- scan and release it when the stream ends or to flush the internal state of
2125-- the scan at the end.
2129{-# INLINE scanlMAfter' #-}
2130scanlMAfter' :: (IsStream t, Monad m)
2131 => (b -> a -> m b) -> m b -> (b -> m b) -> t m a -> t m b
2132scanlMAfter' step initial done stream =
2133 fromStreamD $ D.scanlMAfter' step initial done $ toStreamD stream
2135-- XXX because of the use of D.cons for appending, scanl' has quadratic
2136-- complexity when iterated over a stream. We should use StreamK style scanlM'
2137-- for linear performance on iteration.
2139-- | Strict left scan. Like 'map', 'scanl'' too is a one to one transformation,
2140-- however it adds an extra element.
2143-- > S.toList $ S.scanl' (+) 0 $ fromList [1,2,3,4]
2148-- > S.toList $ S.scanl' (flip (:)) [] $ S.fromList [1,2,3,4]
2149-- [[],[1],[2,1],[3,2,1],[4,3,2,1]]
2152-- The output of 'scanl'' is the initial value of the accumulator followed by
2153-- all the intermediate steps and the final result of 'foldl''.
2155-- By streaming the accumulated state after each fold step, we can share the
2156-- state across multiple stages of stream composition. Each stage can modify or
2157-- extend the state, do some processing with it and emit it for the next stage,
2158-- thus modularizing the stream processing. This can be useful in
2159-- stateful or event-driven programming.
2161-- Consider the following monolithic example, computing the sum and the product
2162-- of the elements in a stream in one go using a @foldl'@:
2165-- > S.foldl' (\\(s, p) x -> (s + x, p * x)) (0,1) $ S.fromList \[1,2,3,4]
2169-- Using @scanl'@ we can make it modular by computing the sum in the first
2170-- stage and passing it down to the next stage for computing the product:
2173-- > S.foldl' (\\(_, p) (s, x) -> (s, p * x)) (0,1)
2174-- $ S.scanl' (\\(s, _) x -> (s + x, x)) (0,1)
2175-- $ S.fromList \[1,2,3,4]
2179-- IMPORTANT: 'scanl'' evaluates the accumulator to WHNF. To avoid building
2180-- lazy expressions inside the accumulator, it is recommended that a strict
2181-- data structure is used for accumulator.
2184{-# INLINE scanl' #-}
2185scanl' :: (IsStream t, Monad m) => (b -> a -> b) -> b -> t m a -> t m b
2186scanl' step z m = fromStreamS $ S.scanl' step z $ toStreamS m
2188-- | Like 'scanl'' but does not stream the initial value of the accumulator.
2190-- > postscanl' f z xs = S.drop 1 $ S.scanl' f z xs
2193{-# INLINE postscanl' #-}
2194postscanl' :: (IsStream t, Monad m) => (b -> a -> b) -> b -> t m a -> t m b
2195postscanl' step z m = fromStreamD $ D.postscanl' step z $ toStreamD m
2197-- XXX this needs to be concurrent
2198-- | Like 'postscanl'' but with a monadic step function.
2201{-# INLINE postscanlM' #-}
2202postscanlM' :: (IsStream t, Monad m) => (b -> a -> m b) -> b -> t m a -> t m b
2203postscanlM' step z m = fromStreamD $ D.postscanlM' step z $ toStreamD m
2205-- XXX prescanl does not sound very useful, enable only if there is a
2206-- compelling use case.
2208-- | Like scanl' but does not stream the final value of the accumulator.
2211{-# INLINE prescanl' #-}
2212prescanl' :: (IsStream t, Monad m) => (b -> a -> b) -> b -> t m a -> t m b
2213prescanl' step z m = fromStreamD $ D.prescanl' step z $ toStreamD m
2215-- XXX this needs to be concurrent
2216-- | Like postscanl' but with a monadic step function.
2219{-# INLINE prescanlM' #-}
2220prescanlM' :: (IsStream t, Monad m) => (b -> a -> m b) -> m b -> t m a -> t m b
2221prescanlM' step z m = fromStreamD $ D.prescanlM' step z $ toStreamD m
2223-- XXX this needs to be concurrent
2224-- | Like 'scanl1'' but with a monadic step function.
2227{-# INLINE scanl1M' #-}
2228scanl1M' :: (IsStream t, Monad m) => (a -> a -> m a) -> t m a -> t m a
2229scanl1M' step m = fromStreamD $ D.scanl1M' step $ toStreamD m
2231-- | Like 'scanl'' but for a non-empty stream. The first element of the stream
2232-- is used as the initial value of the accumulator. Does nothing if the stream
2236-- > S.toList $ S.scanl1 (+) $ fromList [1,2,3,4]
2241{-# INLINE scanl1' #-}
2242scanl1' :: (IsStream t, Monad m) => (a -> a -> a) -> t m a -> t m a
2243scanl1' step m = fromStreamD $ D.scanl1' step $ toStreamD m
2245------------------------------------------------------------------------------
2246-- Scanning with a Fold
2247------------------------------------------------------------------------------
2249-- | Scan a stream using the given monadic fold.
2253scan :: (IsStream t, Monad m) => Fold m a b -> t m a -> t m b
2254scan (Fold step begin done) = P.scanlMx' step begin done
2256-- | Postscan a stream using the given monadic fold.
2259{-# INLINE postscan #-}
2260postscan :: (IsStream t, Monad m) => Fold m a b -> t m a -> t m b
2261postscan (Fold step begin done) = P.postscanlMx' step begin done
2263------------------------------------------------------------------------------
2264-- Stateful Transformations
2265------------------------------------------------------------------------------
2267-- XXX this is not a one-to-one map so calling it map may not be right.
2268-- We can perhaps call it zipWithTail or rollWith.
2270-- | Apply a function on every two successive elements of a stream. If the
2271-- stream consists of a single element the output is an empty stream.
2273-- This is the stream equivalent of the list idiom @zipWith f xs (tail xs)@.
2277{-# INLINE rollingMap #-}
2278rollingMap :: (IsStream t, Monad m) => (a -> a -> b) -> t m a -> t m b
2279rollingMap f m = fromStreamD $ D.rollingMap f $ toStreamD m
2281-- | Like 'rollingMap' but with an effectful map function.
2285{-# INLINE rollingMapM #-}
2286rollingMapM :: (IsStream t, Monad m) => (a -> a -> m b) -> t m a -> t m b
2287rollingMapM f m = fromStreamD $ D.rollingMapM f $ toStreamD m
2289------------------------------------------------------------------------------
2290-- Transformation by Filtering
2291------------------------------------------------------------------------------
2293-- | Include only those elements that pass a predicate.
2296{-# INLINE filter #-}
2297#if __GLASGOW_HASKELL__ != 802
2298-- GHC 8.2.2 crashes with this code, when used with "stack"
2299filter :: (IsStream t, Monad m) => (a -> Bool) -> t m a -> t m a
2300filter p m = fromStreamS $ S.filter p $ toStreamS m
2302filter :: IsStream t => (a -> Bool) -> t m a -> t m a
2306-- | Same as 'filter' but with a monadic predicate.
2309{-# INLINE filterM #-}
2310filterM :: (IsStream t, Monad m) => (a -> m Bool) -> t m a -> t m a
2311filterM p m = fromStreamD $ D.filterM p $ toStreamD m
2313-- | Drop repeated elements that are adjacent to each other.
2317uniq :: (Eq a, IsStream t, Monad m) => t m a -> t m a
2318uniq = fromStreamD . D.uniq . toStreamD
2320-- | Ensures that all the elements of the stream are identical and then returns
2321-- that unique element.
2325the :: (Eq a, Monad m) => SerialT m a -> m (Maybe a)
2326the m = S.the (toStreamS m)
2328-- | Take first 'n' elements from the stream and discard the rest.
2332take :: (IsStream t, Monad m) => Int -> t m a -> t m a
2333take n m = fromStreamS $ S.take n $ toStreamS
2334 (maxYields (Just (fromIntegral n)) m)
2336-- | End the stream as soon as the predicate fails on an element.
2339{-# INLINE takeWhile #-}
2340takeWhile :: (IsStream t, Monad m) => (a -> Bool) -> t m a -> t m a
2341takeWhile p m = fromStreamS $ S.takeWhile p $ toStreamS m
2343-- | Same as 'takeWhile' but with a monadic predicate.
2346{-# INLINE takeWhileM #-}
2347takeWhileM :: (IsStream t, Monad m) => (a -> m Bool) -> t m a -> t m a
2348takeWhileM p m = fromStreamD $ D.takeWhileM p $ toStreamD m
2350-- | @takeByTime duration@ yields stream elements upto specified time
2351-- @duration@. The duration starts when the stream is evaluated for the first
2352-- time, before the first element is yielded. The time duration is checked
2353-- before generating each element, if the duration has expired the stream
2356-- The total time taken in executing the stream is guaranteed to be /at least/
2357-- @duration@, however, because the duration is checked before generating an
2358-- element, the upper bound is indeterminate and depends on the time taken in
2359-- generating and processing the last element.
2361-- No element is yielded if the duration is zero. At least one element is
2362-- yielded if the duration is non-zero.
2366{-# INLINE takeByTime #-}
2367takeByTime ::(MonadIO m, IsStream t, TimeUnit64 d) => d -> t m a -> t m a
2368takeByTime d = fromStreamD . D.takeByTime d . toStreamD
2370-- | Discard first 'n' elements from the stream and take the rest.
2374drop :: (IsStream t, Monad m) => Int -> t m a -> t m a
2375drop n m = fromStreamS $ S.drop n $ toStreamS m
2377-- | Drop elements in the stream as long as the predicate succeeds and then
2378-- take the rest of the stream.
2381{-# INLINE dropWhile #-}
2382dropWhile :: (IsStream t, Monad m) => (a -> Bool) -> t m a -> t m a
2383dropWhile p m = fromStreamS $ S.dropWhile p $ toStreamS m
2385-- | Same as 'dropWhile' but with a monadic predicate.
2388{-# INLINE dropWhileM #-}
2389dropWhileM :: (IsStream t, Monad m) => (a -> m Bool) -> t m a -> t m a
2390dropWhileM p m = fromStreamD $ D.dropWhileM p $ toStreamD m
2392-- | @dropByTime duration@ drops stream elements until specified @duration@ has
2393-- passed. The duration begins when the stream is evaluated for the first
2394-- time. The time duration is checked /after/ generating a stream element, the
2395-- element is yielded if the duration has expired otherwise it is dropped.
2397-- The time elapsed before starting to generate the first element is /at most/
2398-- @duration@, however, because the duration expiry is checked after the
2399-- element is generated, the lower bound is indeterminate and depends on the
2400-- time taken in generating an element.
2402-- All elements are yielded if the duration is zero.
2406{-# INLINE dropByTime #-}
2407dropByTime ::(MonadIO m, IsStream t, TimeUnit64 d) => d -> t m a -> t m a
2408dropByTime d = fromStreamD . D.dropByTime d . toStreamD
2410------------------------------------------------------------------------------
2411-- Transformation by Mapping
2412------------------------------------------------------------------------------
2416-- mapM f = sequence . map f
2419-- Apply a monadic function to each element of the stream and replace it with
2420-- the output of the resulting action.
2423-- > drain $ S.mapM putStr $ S.fromList ["a", "b", "c"]
2426-- drain $ S.replicateM 10 (return 1)
2427-- & (serially . S.mapM (\\x -> threadDelay 1000000 >> print x))
2429-- drain $ S.replicateM 10 (return 1)
2430-- & (asyncly . S.mapM (\\x -> threadDelay 1000000 >> print x))
2433-- /Concurrent (do not use with 'parallely' on infinite streams)/
2436{-# INLINE_EARLY mapM #-}
2437mapM :: (IsStream t, MonadAsync m) => (a -> m b) -> t m a -> t m b
2440{-# RULES "mapM serial" mapM = mapMSerial #-}
2441{-# INLINE mapMSerial #-}
2442mapMSerial :: Monad m => (a -> m b) -> SerialT m a -> SerialT m b
2443mapMSerial = Serial.mapM
2447-- sequence = mapM id
2450-- Replace the elements of a stream of monadic actions with the outputs of
2454-- > drain $ S.sequence $ S.fromList [putStr "a", putStr "b", putStrLn "c"]
2457-- drain $ S.replicateM 10 (return $ threadDelay 1000000 >> print 1)
2458-- & (serially . S.sequence)
2460-- drain $ S.replicateM 10 (return $ threadDelay 1000000 >> print 1)
2461-- & (asyncly . S.sequence)
2464-- /Concurrent (do not use with 'parallely' on infinite streams)/
2467{-# INLINE sequence #-}
2468sequence :: (IsStream t, MonadAsync m) => t m (m a) -> t m a
2469sequence m = fromStreamS $ S.sequence (toStreamS m)
2471------------------------------------------------------------------------------
2472-- Transformation by Map and Filter
2473------------------------------------------------------------------------------
2475-- | Map a 'Maybe' returning function to a stream, filter out the 'Nothing'
2476-- elements, and return a stream of values extracted from 'Just'.
2481-- mapMaybe f = S.map 'fromJust' . S.filter 'isJust' . S.map f
2485{-# INLINE mapMaybe #-}
2486mapMaybe :: (IsStream t, Monad m) => (a -> Maybe b) -> t m a -> t m b
2487mapMaybe f m = fromStreamS $ S.mapMaybe f $ toStreamS m
2489-- | Like 'mapMaybe' but maps a monadic function.
2494-- mapMaybeM f = S.map 'fromJust' . S.filter 'isJust' . S.mapM f
2497-- /Concurrent (do not use with 'parallely' on infinite streams)/
2500{-# INLINE_EARLY mapMaybeM #-}
2501mapMaybeM :: (IsStream t, MonadAsync m, Functor (t m))
2502 => (a -> m (Maybe b)) -> t m a -> t m b
2503mapMaybeM f = fmap fromJust . filter isJust . K.mapM f
2505{-# RULES "mapMaybeM serial" mapMaybeM = mapMaybeMSerial #-}
2506{-# INLINE mapMaybeMSerial #-}
2507mapMaybeMSerial :: Monad m => (a -> m (Maybe b)) -> SerialT m a -> SerialT m b
2508mapMaybeMSerial f m = fromStreamD $ D.mapMaybeM f $ toStreamD m
2510------------------------------------------------------------------------------
2511-- Transformation by Reordering
2512------------------------------------------------------------------------------
2514-- XXX Use a compact region list to temporarily store the list, in both reverse
2515-- as well as in reverse'.
2517-- /Note:/ 'reverse'' is much faster than this, use that when performance
2520-- > reverse = S.foldlT (flip S.cons) S.nil
2522-- | Returns the elements of the stream in reverse order. The stream must be
2523-- finite. Note that this necessarily buffers the entire stream in memory.
2525-- /Since 0.7.0 (Monad m constraint)/
2528{-# INLINE reverse #-}
2529reverse :: (IsStream t, Monad m) => t m a -> t m a
2530reverse s = fromStreamS $ S.reverse $ toStreamS s
2532-- | Like 'reverse' but several times faster, requires a 'Storable' instance.
2535{-# INLINE reverse' #-}
2536reverse' :: (IsStream t, MonadIO m, Storable a) => t m a -> t m a
2537reverse' s = fromStreamD $ D.reverse' $ toStreamD s
2539------------------------------------------------------------------------------
2540-- Transformation by Inserting
2541------------------------------------------------------------------------------
2543-- intersperseM = intersperseBySpan 1
2545-- | Insert an effect and its output before consuming an element of a stream
2546-- except the first one.
2549-- >>> S.toList $ S.trace putChar $ S.intersperseM (putChar '.' >> return ',') $ S.fromList "hello"
2550-- > h.,e.,l.,l.,o"h,e,l,l,o"
2554{-# INLINE intersperseM #-}
2555intersperseM :: (IsStream t, MonadAsync m) => m a -> t m a -> t m a
2556intersperseM m = fromStreamS . S.intersperseM m . toStreamS
2558-- | Insert a side effect before consuming an element of a stream except the
2562-- >>> S.drain $ S.trace putChar $ S.intersperseM_ (putChar '.') $ S.fromList "hello"
2567{-# INLINE intersperseM_ #-}
2568intersperseM_ :: (IsStream t, Monad m) => m b -> t m a -> t m a
2569intersperseM_ m = fromStreamD . D.intersperseM_ m . toStreamD
2571-- | Insert a pure value between successive elements of a stream.
2574-- > S.toList $ S.intersperse ',' $ S.fromList "hello"
2579{-# INLINE intersperse #-}
2580intersperse :: (IsStream t, MonadAsync m) => a -> t m a -> t m a
2581intersperse a = fromStreamS . S.intersperse a . toStreamS
2583-- | Insert an effect and its output after consuming an element of a stream.
2586-- >>> S.toList $ S.trace putChar $ S.intersperseSuffix (putChar '.' >> return ',') $ S.fromList "hello"
2587-- > h.,e.,l.,l.,o.,"h,e,l,l,o,"
2591{-# INLINE intersperseSuffix #-}
2592intersperseSuffix :: (IsStream t, MonadAsync m) => m a -> t m a -> t m a
2593intersperseSuffix m = fromStreamD . D.intersperseSuffix m . toStreamD
2595-- | Insert a side effect after consuming an element of a stream.
2598-- > S.mapM_ putChar $ S.intersperseSuffix_ (threadDelay 1000000) $ S.fromList "hello"
2603{-# INLINE intersperseSuffix_ #-}
2604intersperseSuffix_ :: (IsStream t, Monad m) => m b -> t m a -> t m a
2605intersperseSuffix_ m = fromStreamD . D.intersperseSuffix_ m . toStreamD
2607-- | Insert a side effect before consuming an element of a stream.
2610-- >>> S.toList $ S.trace putChar $ S.interspersePrefix_ (putChar '.' >> return ',') $ S.fromList "hello"
2611-- > .h.e.l.l.o"hello"
2614-- See also: 'trace_'
2620{-# INLINE interspersePrefix_ #-}
2621interspersePrefix_ :: (IsStream t, MonadAsync m) => m b -> t m a -> t m a
2622interspersePrefix_ m = mapM (\x -> void m >> return x)
2624-- Note: delay must be serial.
2626-- | Introduce a delay of specified seconds before consuming an element of the
2627-- stream except the first one.
2630-- >>> S.mapM_ print $ S.timestamped $ S.delay 1 $ S.enumerateFromTo 1 3
2631-- > (AbsTime (TimeSpec {sec = 2502706, nsec = 751137000}),1)
2632-- > (AbsTime (TimeSpec {sec = 2502707, nsec = 743535000}),2)
2633-- > (AbsTime (TimeSpec {sec = 2502708, nsec = 749758000}),3)
2639delay :: (IsStream t, MonadIO m) => Double -> t m a -> t m a
2640delay n = intersperseM_ $ liftIO $ threadDelay $ round $ n * 1000000
2642-- Note: delay must be serial.
2644-- | Introduce a delay of specified seconds after consuming an element of a
2648-- >>> S.mapM_ print $ S.timestamped $ S.delayPost 1 $ S.enumerateFromTo 1 3
2649-- > (AbsTime (TimeSpec {sec = 2502826, nsec = 119030000}),1)
2650-- > (AbsTime (TimeSpec {sec = 2502827, nsec = 111393000}),2)
2651-- > (AbsTime (TimeSpec {sec = 2502828, nsec = 112221000}),3)
2656{-# INLINE delayPost #-}
2657delayPost :: (IsStream t, MonadIO m) => Double -> t m a -> t m a
2658delayPost n = intersperseSuffix_ $ liftIO $ threadDelay $ round $ n * 1000000
2660-- Note: delay must be serial, that's why 'trace_' is used.
2662-- | Introduce a delay of specified seconds before consuming an element of a
2666-- >>> S.mapM_ print $ S.timestamped $ S.delayPre 1 $ S.enumerateFromTo 1 3
2667-- > (AbsTime (TimeSpec {sec = 2502207, nsec = 533177000}),1)
2668-- > (AbsTime (TimeSpec {sec = 2502208, nsec = 530859000}),2)
2669-- > (AbsTime (TimeSpec {sec = 2502209, nsec = 531619000}),3)
2674{-# INLINE delayPre #-}
2675delayPre :: (IsStream t, MonadIO m) => Double -> t m a -> t m a
2676delayPre n = trace_ $ liftIO $ threadDelay $ round $ n * 1000000
2678-- | Like 'intersperseSuffix' but intersperses an effectful action into the
2679-- input stream after every @n@ elements and after the last element.
2682-- > S.toList $ S.intersperseSuffixBySpan 2 (return ',') $ S.fromList "hello"
2688{-# INLINE intersperseSuffixBySpan #-}
2689intersperseSuffixBySpan :: (IsStream t, MonadAsync m)
2690 => Int -> m a -> t m a -> t m a
2691intersperseSuffixBySpan n eff =
2692 fromStreamD . D.intersperseSuffixBySpan n eff . toStreamD
2695-- | Intersperse a monadic action into the input stream after every @n@
2699-- > S.toList $ S.intersperseBySpan 2 (return ',') $ S.fromList "hello"
2704{-# INLINE intersperseBySpan #-}
2705intersperseBySpan :: IsStream t => Int -> m a -> t m a -> t m a
2706intersperseBySpan _n _f _xs = undefined
2709-- | Intersperse a monadic action into the input stream after every @n@
2713-- > S.drain $ S.interjectSuffix 1 (putChar ',') $ S.mapM (\\x -> threadDelay 1000000 >> putChar x) $ S.fromList "hello"
2718{-# INLINE interjectSuffix #-}
2720 :: (IsStream t, MonadAsync m)
2721 => Double -> m a -> t m a -> t m a
2722interjectSuffix n f xs = xs `Par.parallelFst` repeatM timed
2723 where timed = liftIO (threadDelay (round $ n * 1000000)) >> f
2725-- | @insertBy cmp elem stream@ inserts @elem@ before the first element in
2726-- @stream@ that is less than @elem@ when compared using @cmp@.
2729-- insertBy cmp x = 'mergeBy' cmp ('yield' x)
2733-- > S.toList $ S.insertBy compare 2 $ S.fromList [1,3,5]
2738{-# INLINE insertBy #-}
2740 (IsStream t, Monad m) => (a -> a -> Ordering) -> a -> t m a -> t m a
2741insertBy cmp x m = fromStreamS $ S.insertBy cmp x (toStreamS m)
2743------------------------------------------------------------------------------
2745------------------------------------------------------------------------------
2747-- | Deletes the first occurrence of the element in the stream that satisfies
2748-- the given equality predicate.
2751-- > S.toList $ S.deleteBy (==) 3 $ S.fromList [1,3,3,5]
2756{-# INLINE deleteBy #-}
2757deleteBy :: (IsStream t, Monad m) => (a -> a -> Bool) -> a -> t m a -> t m a
2758deleteBy cmp x m = fromStreamS $ S.deleteBy cmp x (toStreamS m)
2760------------------------------------------------------------------------------
2762------------------------------------------------------------------------------
2765-- > indexed = S.postscanl' (\(i, _) x -> (i + 1, x)) (-1,undefined)
2766-- > indexed = S.zipWith (,) (S.enumerateFrom 0)
2768-- Pair each element in a stream with its index, starting from index 0.
2771-- > S.toList $ S.indexed $ S.fromList "hello"
2772-- [(0,'h'),(1,'e'),(2,'l'),(3,'l'),(4,'o')]
2776{-# INLINE indexed #-}
2777indexed :: (IsStream t, Monad m) => t m a -> t m (Int, a)
2778indexed = fromStreamD . D.indexed . toStreamD
2781-- > indexedR n = S.postscanl' (\(i, _) x -> (i - 1, x)) (n + 1,undefined)
2782-- > indexedR n = S.zipWith (,) (S.enumerateFromThen n (n - 1))
2784-- Pair each element in a stream with its index, starting from the
2785-- given index @n@ and counting down.
2788-- > S.toList $ S.indexedR 10 $ S.fromList "hello"
2789-- [(10,'h'),(9,'e'),(8,'l'),(7,'l'),(6,'o')]
2793{-# INLINE indexedR #-}
2794indexedR :: (IsStream t, Monad m) => Int -> t m a -> t m (Int, a)
2795indexedR n = fromStreamD . D.indexedR n . toStreamD
2797-- Note: The timestamp stream must be the second stream in the zip so that the
2798-- timestamp is generated after generating the stream element and not before.
2799-- If we do not do that then the following example will generate the same
2800-- timestamp for first two elements:
2802-- S.mapM_ print $ S.timestamped $ S.delay $ S.enumerateFromTo 1 3
2804-- | Pair each element in a stream with an absolute timestamp, using a clock of
2805-- specified granularity. The timestamp is generated just before the element
2809-- >>> S.mapM_ print $ S.timestampWith 0.01 $ S.delay 1 $ S.enumerateFromTo 1 3
2814{-# INLINE timestampWith #-}
2815timestampWith :: (IsStream t, MonadAsync m, Functor (t m))
2816 => Double -> t m a -> t m (AbsTime, a)
2817timestampWith g stream = Z.zipWith (flip (,)) stream (absTimesWith g)
2819-- TBD: check performance vs a custom implementation without using zipWith.
2821-- | Pair each element in a stream with an absolute timestamp, using a clock of
2822-- 10 ms granularity. The timestamp is generated just before the element is
2826-- >>> S.mapM_ print $ S.timestamped $ S.delay 1 $ S.enumerateFromTo 1 3
2827-- (AbsTime (TimeSpec {sec = 2460689, nsec = 641121000}),1)
2828-- (AbsTime (TimeSpec {sec = 2460690, nsec = 639334000}),2)
2829-- (AbsTime (TimeSpec {sec = 2460691, nsec = 644479000}),3)
2834{-# INLINE timestamped #-}
2835timestamped :: (IsStream t, MonadAsync m, Functor (t m))
2836 => t m a -> t m (AbsTime, a)
2837timestamped = timestampWith 0.01
2839-- | Pair each element in a stream with relative times starting from 0, using a
2840-- clock with the specified granularity. The time is measured just before the
2841-- element is consumed.
2844-- >>> S.mapM_ print $ S.timeIndexWith 0.01 $ S.delay 1 $ S.enumerateFromTo 1 3
2849{-# INLINE timeIndexWith #-}
2850timeIndexWith :: (IsStream t, MonadAsync m, Functor (t m))
2851 => Double -> t m a -> t m (RelTime64, a)
2852timeIndexWith g stream = Z.zipWith (flip (,)) stream (relTimesWith g)
2854-- | Pair each element in a stream with relative times starting from 0, using a
2855-- 10 ms granularity clock. The time is measured just before the element is
2859-- >>> S.mapM_ print $ S.timeIndexed $ S.delay 1 $ S.enumerateFromTo 1 3
2860-- (RelTime64 (NanoSecond64 0),1)
2861-- (RelTime64 (NanoSecond64 996239000),2)
2862-- (RelTime64 (NanoSecond64 1996712000),3)
2867{-# INLINE timeIndexed #-}
2868timeIndexed :: (IsStream t, MonadAsync m, Functor (t m))
2869 => t m a -> t m (RelTime64, a)
2870timeIndexed = timeIndexWith 0.01
2872------------------------------------------------------------------------------
2874------------------------------------------------------------------------------
2876-- | Compare two streams for equality using an equality function.
2879{-# INLINABLE eqBy #-}
2880eqBy :: (IsStream t, Monad m) => (a -> b -> Bool) -> t m a -> t m b -> m Bool
2883-- | Compare two streams lexicographically using a comparison function.
2886{-# INLINABLE cmpBy #-}
2888 :: (IsStream t, Monad m)
2889 => (a -> b -> Ordering) -> t m a -> t m b -> m Ordering
2892------------------------------------------------------------------------------
2894------------------------------------------------------------------------------
2896-- | Merge two streams using a comparison function. The head elements of both
2897-- the streams are compared and the smaller of the two elements is emitted, if
2898-- both elements are equal then the element from the first stream is used
2901-- If the streams are sorted in ascending order, the resulting stream would
2902-- also remain sorted in ascending order.
2905-- > S.toList $ S.mergeBy compare (S.fromList [1,3,5]) (S.fromList [2,4,6,8])
2910{-# INLINABLE mergeBy #-}
2912 (IsStream t, Monad m) => (a -> a -> Ordering) -> t m a -> t m a -> t m a
2913mergeBy f m1 m2 = fromStreamS $ S.mergeBy f (toStreamS m1) (toStreamS m2)
2915-- | Like 'mergeBy' but with a monadic comparison function.
2917-- Merge two streams randomly:
2920-- > randomly _ _ = randomIO >>= \x -> return $ if x then LT else GT
2921-- > S.toList $ S.mergeByM randomly (S.fromList [1,1,1,1]) (S.fromList [2,2,2,2])
2925-- Merge two streams in a proportion of 2:1:
2928-- proportionately m n = do
2929-- ref <- newIORef $ cycle $ concat [replicate m LT, replicate n GT]
2930-- return $ \\_ _ -> do
2931-- r <- readIORef ref
2932-- writeIORef ref $ tail r
2936-- f <- proportionately 2 1
2937-- xs <- S.toList $ S.mergeByM f (S.fromList [1,1,1,1,1,1]) (S.fromList [2,2,2])
2941-- [1,1,2,1,1,2,1,1,2]
2945{-# INLINABLE mergeByM #-}
2947 :: (IsStream t, Monad m)
2948 => (a -> a -> m Ordering) -> t m a -> t m a -> t m a
2949mergeByM f m1 m2 = fromStreamS $ S.mergeByM f (toStreamS m1) (toStreamS m2)
2952-- | Like 'mergeByM' but stops merging as soon as any of the two streams stops.
2953{-# INLINABLE mergeEndByAny #-}
2955 :: (IsStream t, Monad m)
2956 => (a -> a -> m Ordering) -> t m a -> t m a -> t m a
2957mergeEndByAny f m1 m2 = fromStreamD $
2958 D.mergeEndByAny f (toStreamD m1) (toStreamD m2)
2960-- Like 'mergeByM' but stops merging as soon as the first stream stops.
2961{-# INLINABLE mergeEndByFirst #-}
2963 :: (IsStream t, Monad m)
2964 => (a -> a -> m Ordering) -> t m a -> t m a -> t m a
2965mergeEndByFirst f m1 m2 = fromStreamS $
2966 D.mergeEndByFirst f (toStreamD m1) (toStreamD m2)
2969-- Holding this back for now, we may want to use the name "merge" differently
2971-- | Same as @'mergeBy' 'compare'@.
2974-- > S.toList $ S.merge (S.fromList [1,3,5]) (S.fromList [2,4,6,8])
2979{-# INLINABLE merge #-}
2981 (IsStream t, Monad m, Ord a) => t m a -> t m a -> t m a
2982merge = mergeBy compare
2985-- | Like 'mergeBy' but merges concurrently (i.e. both the elements being
2986-- merged are generated concurrently).
2989{-# INLINE mergeAsyncBy #-}
2990mergeAsyncBy :: (IsStream t, MonadAsync m)
2991 => (a -> a -> Ordering) -> t m a -> t m a -> t m a
2992mergeAsyncBy f = mergeAsyncByM (\a b -> return $ f a b)
2994-- | Like 'mergeByM' but merges concurrently (i.e. both the elements being
2995-- merged are generated concurrently).
2998{-# INLINE mergeAsyncByM #-}
2999mergeAsyncByM :: (IsStream t, MonadAsync m)
3000 => (a -> a -> m Ordering) -> t m a -> t m a -> t m a
3001mergeAsyncByM f m1 m2 = fromStreamD $
3002 D.mergeByM f (D.mkParallelD $ toStreamD m1) (D.mkParallelD $ toStreamD m2)
3004------------------------------------------------------------------------------
3006------------------------------------------------------------------------------
3008-- | @concatMapWith merge map stream@ is a two dimensional looping combinator.
3009-- The first argument specifies a merge or concat function that is used to
3010-- merge the streams generated by applying the second argument i.e. the @map@
3011-- function to each element of the input stream. The concat function could be
3012-- 'serial', 'parallel', 'async', 'ahead' or any other zip or merge function
3013-- and the second argument could be any stream generation function using a
3016-- /Compare 'foldMapWith'/
3019{-# INLINE concatMapWith #-}
3022 => (t m b -> t m b -> t m b)
3026concatMapWith = K.concatMapBy
3028-- | Map a stream producing function on each element of the stream and then
3029-- flatten the results into a single stream.
3032-- concatMap = 'concatMapWith' 'Serial.serial'
3033-- concatMap f = 'concatMapM' (return . f)
3034-- concatMap f = 'concatUnfold' (UF.lmap f UF.fromStream)
3038{-# INLINE concatMap #-}
3039concatMap ::(IsStream t, Monad m) => (a -> t m b) -> t m a -> t m b
3040concatMap f m = fromStreamD $ D.concatMap (toStreamD . f) (toStreamD m)
3042-- | Flatten a stream of streams to a single stream.
3045-- concat = concatMap id
3049{-# INLINE concat #-}
3050concat :: (IsStream t, Monad m) => t m (t m a) -> t m a
3051concat = concatMap id
3053-- | Append the outputs of two streams, yielding all the elements from the
3054-- first stream and then yielding all the elements from the second stream.
3056-- IMPORTANT NOTE: This could be 100x faster than @serial/<>@ for appending a
3057-- few (say 100) streams because it can fuse via stream fusion. However, it
3058-- does not scale for a large number of streams (say 1000s) and becomes
3059-- qudartically slow. Therefore use this for custom appending of a few streams
3060-- but use 'concatMap' or 'concatMapWith serial' for appending @n@ streams or
3061-- infinite containers of streams.
3064{-# INLINE append #-}
3065append ::(IsStream t, Monad m) => t m b -> t m b -> t m b
3066append m1 m2 = fromStreamD $ D.append (toStreamD m1) (toStreamD m2)
3068-- XXX Same as 'wSerial'. We should perhaps rename wSerial to interleave.
3069-- XXX Document the interleaving behavior of side effects in all the
3070-- interleaving combinators.
3071-- XXX Write time-domain equivalents of these. In the time domain we can
3072-- interleave two streams such that the value of second stream is always taken
3073-- from its last value even if no new value is being yielded, like
3074-- zipWithLatest. It would be something like interleaveWithLatest.
3076-- | Interleaves the outputs of two streams, yielding elements from each stream
3077-- alternately, starting from the first stream. If any of the streams finishes
3078-- early the other stream continues alone until it too finishes.
3080-- >>> :set -XOverloadedStrings
3081-- >>> interleave "ab" ",,,," :: SerialT Identity Char
3083-- >>> interleave "abcd" ",," :: SerialT Identity Char
3086-- 'interleave' is dual to 'interleaveMin', it can be called @interleaveMax@.
3088-- Do not use at scale in concatMapWith.
3091{-# INLINE interleave #-}
3092interleave ::(IsStream t, Monad m) => t m b -> t m b -> t m b
3093interleave m1 m2 = fromStreamD $ D.interleave (toStreamD m1) (toStreamD m2)
3095-- | Interleaves the outputs of two streams, yielding elements from each stream
3096-- alternately, starting from the first stream. As soon as the first stream
3097-- finishes, the output stops, discarding the remaining part of the second
3098-- stream. In this case, the last element in the resulting stream would be from
3099-- the second stream. If the second stream finishes early then the first stream
3100-- still continues to yield elements until it finishes.
3102-- >>> :set -XOverloadedStrings
3103-- >>> interleaveSuffix "abc" ",,,," :: SerialT Identity Char
3105-- >>> interleaveSuffix "abc" "," :: SerialT Identity Char
3108-- 'interleaveSuffix' is a dual of 'interleaveInfix'.
3110-- Do not use at scale in concatMapWith.
3113{-# INLINE interleaveSuffix #-}
3114interleaveSuffix ::(IsStream t, Monad m) => t m b -> t m b -> t m b
3115interleaveSuffix m1 m2 =
3116 fromStreamD $ D.interleaveSuffix (toStreamD m1) (toStreamD m2)
3118-- | Interleaves the outputs of two streams, yielding elements from each stream
3119-- alternately, starting from the first stream and ending at the first stream.
3120-- If the second stream is longer than the first, elements from the second
3121-- stream are infixed with elements from the first stream. If the first stream
3122-- is longer then it continues yielding elements even after the second stream
3125-- >>> :set -XOverloadedStrings
3126-- >>> interleaveInfix "abc" ",,,," :: SerialT Identity Char
3128-- >>> interleaveInfix "abc" "," :: SerialT Identity Char
3131-- 'interleaveInfix' is a dual of 'interleaveSuffix'.
3133-- Do not use at scale in concatMapWith.
3136{-# INLINE interleaveInfix #-}
3137interleaveInfix ::(IsStream t, Monad m) => t m b -> t m b -> t m b
3138interleaveInfix m1 m2 =
3139 fromStreamD $ D.interleaveInfix (toStreamD m1) (toStreamD m2)
3141-- | Interleaves the outputs of two streams, yielding elements from each stream
3142-- alternately, starting from the first stream. The output stops as soon as any
3143-- of the two streams finishes, discarding the remaining part of the other
3144-- stream. The last element of the resulting stream would be from the longer
3147-- >>> :set -XOverloadedStrings
3148-- >>> interleaveMin "ab" ",,,," :: SerialT Identity Char
3150-- >>> interleaveMin "abcd" ",," :: SerialT Identity Char
3153-- 'interleaveMin' is dual to 'interleave'.
3155-- Do not use at scale in concatMapWith.
3158{-# INLINE interleaveMin #-}
3159interleaveMin ::(IsStream t, Monad m) => t m b -> t m b -> t m b
3160interleaveMin m1 m2 = fromStreamD $ D.interleaveMin (toStreamD m1) (toStreamD m2)
3162-- | Schedule the execution of two streams in a fair round-robin manner,
3163-- executing each stream once, alternately. Execution of a stream may not
3164-- necessarily result in an output, a stream may chose to @Skip@ producing an
3165-- element until later giving the other stream a chance to run. Therefore, this
3166-- combinator fairly interleaves the execution of two streams rather than
3167-- fairly interleaving the output of the two streams. This can be useful in
3168-- co-operative multitasking without using explicit threads. This can be used
3169-- as an alternative to `async`.
3171-- Do not use at scale in concatMapWith.
3174{-# INLINE roundrobin #-}
3175roundrobin ::(IsStream t, Monad m) => t m b -> t m b -> t m b
3176roundrobin m1 m2 = fromStreamD $ D.roundRobin (toStreamD m1) (toStreamD m2)
3178-- | Map a stream producing monadic function on each element of the stream
3179-- and then flatten the results into a single stream. Since the stream
3180-- generation function is monadic, unlike 'concatMap', it can produce an
3181-- effect at the beginning of each iteration of the inner loop.
3184{-# INLINE concatMapM #-}
3185concatMapM :: (IsStream t, Monad m) => (a -> m (t m b)) -> t m a -> t m b
3186concatMapM f m = fromStreamD $ D.concatMapM (fmap toStreamD . f) (toStreamD m)
3188-- | Given a stream value in the underlying monad, lift and join the underlying
3189-- monad with the stream monad.
3191-- Compare with 'concat' and 'sequence'.
3195{-# INLINE concatM #-}
3196concatM :: (IsStream t, Monad m) => m (t m a) -> t m a
3197concatM generator = concatMapM (\() -> generator) (yield ())
3199-- | Like 'concatMap' but uses an 'Unfold' for stream generation. Unlike
3200-- 'concatMap' this can fuse the 'Unfold' code with the inner loop and
3201-- therefore provide many times better performance.
3204{-# INLINE concatUnfold #-}
3205concatUnfold ::(IsStream t, Monad m) => Unfold m a b -> t m a -> t m b
3206concatUnfold u m = fromStreamD $ D.concatMapU u (toStreamD m)
3208-- | Like 'concatUnfold' but interleaves the streams in the same way as
3209-- 'interleave' behaves instead of appending them.
3212{-# INLINE concatUnfoldInterleave #-}
3213concatUnfoldInterleave ::(IsStream t, Monad m)
3214 => Unfold m a b -> t m a -> t m b
3215concatUnfoldInterleave u m =
3216 fromStreamD $ D.concatUnfoldInterleave u (toStreamD m)
3218-- | Like 'concatUnfold' but executes the streams in the same way as
3222{-# INLINE concatUnfoldRoundrobin #-}
3223concatUnfoldRoundrobin ::(IsStream t, Monad m)
3224 => Unfold m a b -> t m a -> t m b
3225concatUnfoldRoundrobin u m =
3226 fromStreamD $ D.concatUnfoldRoundrobin u (toStreamD m)
3228-- XXX we can swap the order of arguments to gintercalate so that the
3229-- definition of concatUnfold becomes simpler? The first stream should be
3230-- infixed inside the second one. However, if we change the order in
3231-- "interleave" as well similarly, then that will make it a bit unintuitive.
3233-- > concatUnfold unf str =
3234-- > gintercalate unf str (UF.nilM (\_ -> return ())) (repeat ())
3236-- | 'interleaveInfix' followed by unfold and concat.
3239{-# INLINE gintercalate #-}
3241 :: (IsStream t, Monad m)
3242 => Unfold m a c -> t m a -> Unfold m b c -> t m b -> t m c
3243gintercalate unf1 str1 unf2 str2 =
3244 D.fromStreamD $ D.gintercalate
3245 unf1 (D.toStreamD str1)
3246 unf2 (D.toStreamD str2)
3248-- XXX The order of arguments in "intercalate" is consistent with the list
3249-- intercalate but inconsistent with gintercalate and other stream interleaving
3250-- combinators. We can change the order of the arguments in other combinators
3251-- but then 'interleave' combinator may become a bit unintuitive because we
3252-- will be starting with the second stream.
3254-- > intercalate seed unf str = gintercalate unf str unf (repeatM seed)
3255-- > intercalate a unf str = concatUnfold unf $ intersperse a str
3257-- | 'intersperse' followed by unfold and concat.
3259-- > unwords = intercalate " " UF.fromList
3261-- >>> intercalate " " UF.fromList ["abc", "def", "ghi"]
3265{-# INLINE intercalate #-}
3266intercalate :: (IsStream t, Monad m)
3267 => b -> Unfold m b c -> t m b -> t m c
3268intercalate seed unf str = D.fromStreamD $
3269 D.concatMapU unf $ D.intersperse seed (toStreamD str)
3271-- > interpose x unf str = gintercalate unf str UF.identity (repeat x)
3273-- | Unfold the elements of a stream, intersperse the given element between the
3274-- unfolded streams and then concat them into a single stream.
3276-- > unwords = S.interpose ' '
3279{-# INLINE interpose #-}
3280interpose :: (IsStream t, Monad m)
3281 => c -> Unfold m b c -> t m b -> t m c
3282interpose x unf str =
3283 D.fromStreamD $ D.interpose (return x) unf (D.toStreamD str)
3285-- | 'interleaveSuffix' followed by unfold and concat.
3288{-# INLINE gintercalateSuffix #-}
3290 :: (IsStream t, Monad m)
3291 => Unfold m a c -> t m a -> Unfold m b c -> t m b -> t m c
3292gintercalateSuffix unf1 str1 unf2 str2 =
3293 D.fromStreamD $ D.gintercalateSuffix
3294 unf1 (D.toStreamD str1)
3295 unf2 (D.toStreamD str2)
3297-- > intercalateSuffix seed unf str = gintercalateSuffix unf str unf (repeatM seed)
3298-- > intercalateSuffix a unf str = concatUnfold unf $ intersperseSuffix a str
3300-- | 'intersperseSuffix' followed by unfold and concat.
3302-- > unlines = intercalateSuffix "\n" UF.fromList
3304-- >>> intercalate "\n" UF.fromList ["abc", "def", "ghi"]
3305-- > "abc\ndef\nghi\n"
3308{-# INLINE intercalateSuffix #-}
3309intercalateSuffix :: (IsStream t, Monad m)
3310 => b -> Unfold m b c -> t m b -> t m c
3311intercalateSuffix seed unf str = fromStreamD $ D.concatMapU unf
3312 $ D.intersperseSuffix (return seed) (D.toStreamD str)
3314-- interposeSuffix x unf str = gintercalateSuffix unf str UF.identity (repeat x)
3316-- | Unfold the elements of a stream, append the given element after each
3317-- unfolded stream and then concat them into a single stream.
3319-- > unlines = S.interposeSuffix '\n'
3322{-# INLINE interposeSuffix #-}
3323interposeSuffix :: (IsStream t, Monad m)
3324 => c -> Unfold m b c -> t m b -> t m c
3325interposeSuffix x unf str =
3326 D.fromStreamD $ D.interposeSuffix (return x) unf (D.toStreamD str)
3328------------------------------------------------------------------------------
3330------------------------------------------------------------------------------
3332-- | Like 'iterateM' but using a stream generator function.
3336{-# INLINE concatMapIterateWith #-}
3339 => (t m a -> t m a -> t m a)
3343concatMapIterateWith combine f = concatMapWith combine go
3345 go x = yield x `combine` concatMapWith combine go (f x)
3347-- concatMapIterateLeftsWith
3349-- | Traverse a forest with recursive tree structures whose non-leaf nodes are
3350-- of type @a@ and leaf nodes are of type @b@, flattening all the trees into
3351-- streams and combining the streams into a single stream consisting of both
3352-- leaf and non-leaf nodes.
3354-- 'concatMapTreeWith' is a generalization of 'concatMap', using a recursive
3355-- feedback loop to append the non-leaf nodes back to the input stream enabling
3356-- recursive traversal. 'concatMap' flattens a single level nesting whereas
3357-- 'concatMapTreeWith' flattens a recursively nested structure.
3359-- Traversing a directory tree recursively is a canonical use case of
3360-- 'concatMapTreeWith'.
3363-- concatMapTreeWith combine f xs = concatMapIterateWith combine g xs
3365-- g (Left tree) = f tree
3366-- g (Right leaf) = nil
3371{-# INLINE concatMapTreeWith #-}
3374 => (t m (Either a b) -> t m (Either a b) -> t m (Either a b))
3375 -> (a -> t m (Either a b))
3376 -> t m (Either a b) -- Should be t m a?
3378concatMapTreeWith combine f = concatMapWith combine go
3380 go (Left tree) = yield (Left tree) `combine` concatMapWith combine go (f tree)
3381 go (Right leaf) = yield $ Right leaf
3384-- | Like concatMapTreeWith but produces only stream of leaf elements.
3385-- On an either stream, iterate lefts but yield only rights.
3387-- concatMapEitherYieldRightsWith combine f xs =
3388-- catRights $ concatMapTreeWith combine f xs
3390{-# INLINE concatMapEitherYieldRightsWith #-}
3391concatMapEitherYieldRightsWith :: (IsStream t, MonadAsync m)
3392 => _ -> (a -> t m (Either a b)) -> t m (Either a b) -> t m b
3393concatMapEitherYieldRightsWith combine f xs = undefined
3397{-# INLINE concatUnfoldTree #-}
3398concatUnfoldTree :: (IsStream t, MonadAsync m)
3399 => Unfold m a (Either a b) -> t m (Either a b) -> t m (Either a b)
3400concatUnfoldTree unf xs = undefined
3403------------------------------------------------------------------------------
3405------------------------------------------------------------------------------
3407-- We can perhaps even implement the SVar using this. The stream we are mapping
3408-- on is the work queue. When evaluated it results in either a leaf element to
3409-- yield or a tail stream to queue back to the work queue.
3411-- | Flatten a stream with a feedback loop back into the input.
3413-- For example, exceptions generated by the output stream can be fed back to
3414-- the input to take any corrective action. The corrective action may be to
3415-- retry the action or do nothing or log the errors. For the retry case we need
3420{-# INLINE concatMapLoopWith #-}
3422 :: (IsStream t, MonadAsync m)
3423 => (forall x. t m x -> t m x -> t m x)
3424 -> (a -> t m (Either b c))
3425 -> (b -> t m a) -- ^ feedback function to feed @b@ back into input
3428concatMapLoopWith combine f fb xs =
3429 concatMapWith combine go $ concatMapWith combine f xs
3431 go (Left b) = concatMapLoopWith combine f fb $ fb b
3432 go (Right c) = yield c
3434-- | Concat a stream of trees, generating only leaves.
3436-- Compare with 'concatMapTreeWith'. While the latter returns all nodes in the
3437-- tree, this one returns only the leaves.
3439-- Traversing a directory tree recursively and yielding on the files is a
3440-- canonical use case of 'concatMapTreeYieldLeavesWith'.
3443-- concatMapTreeYieldLeavesWith combine f = concatMapLoopWith combine f yield
3448{-# INLINE concatMapTreeYieldLeavesWith #-}
3449concatMapTreeYieldLeavesWith
3450 :: (IsStream t, MonadAsync m)
3451 => (forall x. t m x -> t m x -> t m x)
3452 -> (a -> t m (Either a b))
3455concatMapTreeYieldLeavesWith combine f = concatMapLoopWith combine f yield
3457------------------------------------------------------------------------------
3459------------------------------------------------------------------------------
3461-- Splitting operations that take a predicate and a Fold can be
3462-- expressed using parseMany. Operations like chunksOf, intervalsOf, split*,
3463-- can be expressed using parseMany when used with an appropriate Parser.
3465-- XXX We need takeGE/takeBetween to implement "some" using "many".
3467-- | Apply a 'Parser' repeatedly on a stream and emit the parsed values in the
3470-- This is the streaming equivalent of the 'Streamly.Internal.Data.Parser.many'
3473-- >>> S.toList $ S.parseMany (PR.take 2 $ PR.fromFold FL.sum) $ S.fromList [1..10]
3476-- >>> S.toList $ S.parseMany (PR.line FL.toList) $ S.fromList "hello\nworld"
3477-- > ["hello\n","world"]
3481{-# INLINE parseMany #-}
3483 :: (IsStream t, MonadThrow m)
3488 D.fromStreamD $ D.parseMany (PRK.fromParserK p) (D.toStreamD m)
3490-- | @parseManyTill collect test stream@ tries the parser @test@ on the input,
3491-- if @test@ fails it backtracks and tries @collect@, after @collect@ succeeds
3492-- @test@ is tried again and so on. The parser stops when @test@ succeeds. The
3493-- output of @test@ is discarded and the output of @collect@ is emitted in the
3494-- output stream. The parser fails if @collect@ fails.
3498{-# INLINE parseManyTill #-}
3500 -- (IsStream t, MonadThrow m) =>
3505parseManyTill = undefined
3507-- | Iterate a parser generating function on a stream. The initial value @b@ is
3508-- used to generate the first parser, the parser is applied on the stream and
3509-- the result is used to generate the next parser and so on.
3511-- >>> S.toList $ S.map getSum $ S.parseIterate (\b -> PR.take 2 (FL.mconcatTo b)) 0 $ S.map Sum $ S.fromList [1..10]
3512-- > [3,10,21,36,55,55]
3514-- This is the streaming equivalent of monad like sequenced application of
3515-- parsers where next parser is dependent on the previous parser.
3519{-# INLINE parseIterate #-}
3521 :: (IsStream t, MonadThrow m)
3522 => (b -> Parser m a b)
3526parseIterate f i m = D.fromStreamD $
3527 D.parseIterate (PRK.fromParserK . f) i (D.toStreamD m)
3529------------------------------------------------------------------------------
3530-- Grouping/Splitting
3531------------------------------------------------------------------------------
3533------------------------------------------------------------------------------
3534-- Grouping without looking at elements
3535------------------------------------------------------------------------------
3537------------------------------------------------------------------------------
3539------------------------------------------------------------------------------
3542------------------------------------------------------------------------------
3544------------------------------------------------------------------------------
3546------------------------------------------------------------------------------
3547-- Generalized grouping
3548------------------------------------------------------------------------------
3550-- This combinator is the most general grouping combinator and can be used to
3551-- implement all other grouping combinators.
3553-- XXX check if this can implement the splitOn combinator i.e. we can slide in
3554-- new elements, slide out old elements and incrementally compute the hash.
3555-- Also, can we implement the windowed classification combinators using this?
3557-- In fact this is a parse. Instead of using a special return value in the fold
3558-- we are using a mapping function.
3560-- Note that 'scanl'' (usually followed by a map to extract the desired value
3561-- from the accumulator) can be used to realize many implementations e.g. a
3562-- sliding window implementation. A scan followed by a mapMaybe is also a good
3563-- pattern to express many problems where we want to emit a filtered output and
3564-- not emit an output on every input.
3566-- Passing on of the initial accumulator value to the next fold is equivalent
3567-- to returning the leftover concept.
3570-- | @groupScan splitter fold stream@ folds the input stream using @fold@.
3571-- @splitter@ is applied on the accumulator of the fold every time an item is
3572-- consumed by the fold. The fold continues until @splitter@ returns a 'Just'
3573-- value. A 'Just' result from the @splitter@ specifies a result to be emitted
3574-- in the output stream and the initial value of the accumulator for the next
3575-- group's fold. This allows us to control whether to start fresh for the next
3576-- fold or to continue from the previous fold's output.
3578{-# INLINE groupScan #-}
3580 :: (IsStream t, Monad m)
3581 => (x -> m (Maybe (b, x))) -> Fold m a x -> t m a -> t m b
3582groupScan split fold m = undefined
3585-- | Group the input stream into groups of @n@ elements each and then fold each
3586-- group using the provided fold function.
3588-- >> S.toList $ S.chunksOf 2 FL.sum (S.enumerateFromTo 1 10)
3591-- This can be considered as an n-fold version of 'ltake' where we apply
3592-- 'ltake' repeatedly on the leftover stream until the stream exhausts.
3595{-# INLINE chunksOf #-}
3597 :: (IsStream t, Monad m)
3598 => Int -> Fold m a b -> t m a -> t m b
3599chunksOf n f m = D.fromStreamD $ D.groupsOf n f (D.toStreamD m)
3604{-# INLINE chunksOf2 #-}
3606 :: (IsStream t, Monad m)
3607 => Int -> m c -> Fold2 m c a b -> t m a -> t m b
3608chunksOf2 n action f m = D.fromStreamD $ D.groupsOf2 n action f (D.toStreamD m)
3610-- | @arraysOf n stream@ groups the elements in the input stream into arrays of
3611-- @n@ elements each.
3613-- Same as the following but may be more efficient:
3615-- > arraysOf n = S.chunksOf n (A.writeN n)
3618{-# INLINE arraysOf #-}
3619arraysOf :: (IsStream t, MonadIO m, Storable a)
3620 => Int -> t m a -> t m (Array a)
3621arraysOf n = chunksOf n (writeNUnsafe n)
3623-- XXX we can implement this by repeatedly applying the 'lrunFor' fold.
3624-- XXX add this example after fixing the serial stream rate control
3625-- >>> S.toList $ S.take 5 $ intervalsOf 1 FL.sum $ constRate 2 $ S.enumerateFrom 1
3628-- | Group the input stream into windows of @n@ second each and then fold each
3629-- group using the provided fold function.
3632{-# INLINE intervalsOf #-}
3634 :: (IsStream t, MonadAsync m)
3635 => Double -> Fold m a b -> t m a -> t m b
3637 splitWithSuffix isNothing (FL.lcatMaybes f)
3638 (interjectSuffix n (return Nothing) (Serial.map Just xs))
3640------------------------------------------------------------------------------
3642------------------------------------------------------------------------------
3644-- | @groupsBy cmp f $ S.fromList [a,b,c,...]@ assigns the element @a@ to the
3645-- first group, if @b \`cmp` a@ is 'True' then @b@ is also assigned to the same
3646-- group. If @c \`cmp` a@ is 'True' then @c@ is also assigned to the same
3647-- group and so on. When the comparison fails a new group is started. Each
3648-- group is folded using the fold @f@ and the result of the fold is emitted in
3649-- the output stream.
3651-- >>> S.toList $ S.groupsBy (>) FL.toList $ S.fromList [1,3,7,0,2,5]
3652-- > [[1,3,7],[0,2,5]]
3655{-# INLINE groupsBy #-}
3657 :: (IsStream t, Monad m)
3662groupsBy cmp f m = D.fromStreamD $ D.groupsBy cmp f (D.toStreamD m)
3664-- | Unlike @groupsBy@ this function performs a rolling comparison of two
3665-- successive elements in the input stream. @groupsByRolling cmp f $ S.fromList
3666-- [a,b,c,...]@ assigns the element @a@ to the first group, if @a \`cmp` b@ is
3667-- 'True' then @b@ is also assigned to the same group. If @b \`cmp` c@ is
3668-- 'True' then @c@ is also assigned to the same group and so on. When the
3669-- comparison fails a new group is started. Each group is folded using the fold
3672-- >>> S.toList $ S.groupsByRolling (\a b -> a + 1 == b) FL.toList $ S.fromList [1,2,3,7,8,9]
3673-- > [[1,2,3],[7,8,9]]
3676{-# INLINE groupsByRolling #-}
3678 :: (IsStream t, Monad m)
3683groupsByRolling cmp f m = D.fromStreamD $ D.groupsRollingBy cmp f (D.toStreamD m)
3686-- > groups = groupsBy (==)
3687-- > groups = groupsByRolling (==)
3689-- Groups contiguous spans of equal elements together in individual groups.
3691-- >>> S.toList $ S.groups FL.toList $ S.fromList [1,1,2,2]
3695groups :: (IsStream t, Monad m, Eq a) => Fold m a b -> t m a -> t m b
3696groups = groupsBy (==)
3698------------------------------------------------------------------------------
3699-- N-ary split on a predicate
3700------------------------------------------------------------------------------
3702-- TODO: Use a Splitter configuration similar to the "split" package to make it
3703-- possible to express all splitting combinations. In general, we can have
3704-- infix/suffix/prefix/condensing of separators, dropping both leading/trailing
3705-- separators. We can have a single split operation taking the splitter config
3708-- | Split on an infixed separator element, dropping the separator. Splits the
3709-- stream on separator elements determined by the supplied predicate, separator
3710-- is considered as infixed between two segments, if one side of the separator
3711-- is missing then it is parsed as an empty stream. The supplied 'Fold' is
3712-- applied on the split segments. With '-' representing non-separator elements
3713-- and '.' as separator, 'splitOn' splits as follows:
3716-- "--.--" => "--" "--"
3721-- @splitOn (== x)@ is an inverse of @intercalate (S.yield x)@
3723-- Let's use the following definition for illustration:
3725-- > splitOn' p xs = S.toList $ S.splitOn p (FL.toList) (S.fromList xs)
3727-- >>> splitOn' (== '.') ""
3730-- >>> splitOn' (== '.') "."
3733-- >>> splitOn' (== '.') ".a"
3736-- >>> splitOn' (== '.') "a."
3739-- >>> splitOn' (== '.') "a.b"
3742-- >>> splitOn' (== '.') "a..b"
3747-- This can be considered as an n-fold version of 'breakOn' where we apply
3748-- 'breakOn' successively on the input stream, dropping the first element
3749-- of the second segment after each break.
3751{-# INLINE splitOn #-}
3753 :: (IsStream t, Monad m)
3754 => (a -> Bool) -> Fold m a b -> t m a -> t m b
3755splitOn predicate f m =
3756 D.fromStreamD $ D.splitBy predicate f (D.toStreamD m)
3758-- | Like 'splitOn' but the separator is considered as suffixed to the segments
3759-- in the stream. A missing suffix at the end is allowed. A separator at the
3760-- beginning is parsed as empty segment. With '-' representing elements and
3761-- '.' as separator, 'splitOnSuffix' splits as follows:
3764-- "--.--." => "--" "--"
3765-- "--.--" => "--" "--"
3769-- > splitOnSuffix' p xs = S.toList $ S.splitSuffixBy p (FL.toList) (S.fromList xs)
3771-- >>> splitOnSuffix' (== '.') ""
3774-- >>> splitOnSuffix' (== '.') "."
3777-- >>> splitOnSuffix' (== '.') "a"
3780-- >>> splitOnSuffix' (== '.') ".a"
3783-- >>> splitOnSuffix' (== '.') "a."
3786-- >>> splitOnSuffix' (== '.') "a.b"
3789-- >>> splitOnSuffix' (== '.') "a.b."
3792-- >>> splitOnSuffix' (== '.') "a..b.."
3795-- > lines = splitOnSuffix (== '\n')
3799-- This can be considered as an n-fold version of 'breakPost' where we apply
3800-- 'breakPost' successively on the input stream, dropping the first element
3801-- of the second segment after each break.
3803{-# INLINE splitOnSuffix #-}
3805 :: (IsStream t, Monad m)
3806 => (a -> Bool) -> Fold m a b -> t m a -> t m b
3807splitOnSuffix predicate f m =
3808 D.fromStreamD $ D.splitSuffixBy predicate f (D.toStreamD m)
3810-- | Like 'splitOn' after stripping leading, trailing, and repeated separators.
3811-- Therefore, @".a..b."@ with '.' as the separator would be parsed as
3812-- @["a","b"]@. In other words, its like parsing words from whitespace
3815-- > wordsBy' p xs = S.toList $ S.wordsBy p (FL.toList) (S.fromList xs)
3817-- >>> wordsBy' (== ',') ""
3820-- >>> wordsBy' (== ',') ","
3823-- >>> wordsBy' (== ',') ",a,,b,"
3826-- > words = wordsBy isSpace
3830-- It is equivalent to splitting in any of the infix/prefix/suffix styles
3831-- followed by removal of empty segments.
3832{-# INLINE wordsBy #-}
3834 :: (IsStream t, Monad m)
3835 => (a -> Bool) -> Fold m a b -> t m a -> t m b
3836wordsBy predicate f m =
3837 D.fromStreamD $ D.wordsBy predicate f (D.toStreamD m)
3839-- | Like 'splitOnSuffix' but keeps the suffix attached to the resulting
3842-- > splitWithSuffix' p xs = S.toList $ S.splitWithSuffix p (FL.toList) (S.fromList xs)
3844-- >>> splitWithSuffix' (== '.') ""
3847-- >>> splitWithSuffix' (== '.') "."
3850-- >>> splitWithSuffix' (== '.') "a"
3853-- >>> splitWithSuffix' (== '.') ".a"
3856-- >>> splitWithSuffix' (== '.') "a."
3859-- >>> splitWithSuffix' (== '.') "a.b"
3862-- >>> splitWithSuffix' (== '.') "a.b."
3865-- >>> splitWithSuffix' (== '.') "a..b.."
3866-- > ["a.",".","b.","."]
3870-- This can be considered as an n-fold version of 'breakPost' where we apply
3871-- 'breakPost' successively on the input stream.
3873{-# INLINE splitWithSuffix #-}
3875 :: (IsStream t, Monad m)
3876 => (a -> Bool) -> Fold m a b -> t m a -> t m b
3877splitWithSuffix predicate f m =
3878 D.fromStreamD $ D.splitSuffixBy' predicate f (D.toStreamD m)
3880------------------------------------------------------------------------------
3881-- Split on a delimiter sequence
3882------------------------------------------------------------------------------
3884-- Int list examples for splitOn:
3886-- >>> splitList [] [1,2,3,3,4]
3887-- > [[1],[2],[3],[3],[4]]
3889-- >>> splitList [5] [1,2,3,3,4]
3892-- >>> splitList [1] [1,2,3,3,4]
3895-- >>> splitList [4] [1,2,3,3,4]
3898-- >>> splitList [2] [1,2,3,3,4]
3901-- >>> splitList [3] [1,2,3,3,4]
3904-- >>> splitList [3,3] [1,2,3,3,4]
3907-- >>> splitList [1,2,3,3,4] [1,2,3,3,4]
3910-- | Like 'splitOn' but the separator is a sequence of elements instead of a
3913-- For illustration, let's define a function that operates on pure lists:
3916-- splitOnSeq' pat xs = S.toList $ S.splitOnSeq (A.fromList pat) (FL.toList) (S.fromList xs)
3919-- >>> splitOnSeq' "" "hello"
3920-- > ["h","e","l","l","o"]
3922-- >>> splitOnSeq' "hello" ""
3925-- >>> splitOnSeq' "hello" "hello"
3928-- >>> splitOnSeq' "x" "hello"
3931-- >>> splitOnSeq' "h" "hello"
3934-- >>> splitOnSeq' "o" "hello"
3937-- >>> splitOnSeq' "e" "hello"
3940-- >>> splitOnSeq' "l" "hello"
3943-- >>> splitOnSeq' "ll" "hello"
3946-- 'splitOnSeq' is an inverse of 'intercalate'. The following law always holds:
3948-- > intercalate . splitOn == id
3950-- The following law holds when the separator is non-empty and contains none of
3951-- the elements present in the input lists:
3953-- > splitOn . intercalate == id
3957-- XXX We can use a polymorphic vector implemented by Array# to represent the
3958-- sequence, that way we can avoid the Storable constraint. If we still need
3959-- Storable Array for performance, we can use a separate splitOnArray API for
3960-- that. We can also have an API where the sequence itself is a lazy stream, so
3961-- that we can search files in files for example.
3962{-# INLINE splitOnSeq #-}
3964 :: (IsStream t, MonadIO m, Storable a, Enum a, Eq a)
3965 => Array a -> Fold m a b -> t m a -> t m b
3966splitOnSeq patt f m = D.fromStreamD $ D.splitOn patt f (D.toStreamD m)
3969-- This can be implemented easily using Rabin Karp
3970-- | Split on any one of the given patterns.
3971{-# INLINE splitOnAny #-}
3973 :: (IsStream t, Monad m, Storable a, Integral a)
3974 => [Array a] -> Fold m a b -> t m a -> t m b
3975splitOnAny subseq f m = undefined -- D.fromStreamD $ D.splitOnAny f subseq (D.toStreamD m)
3978-- | Like 'splitSuffixBy' but the separator is a sequence of elements, instead
3979-- of a predicate for a single element.
3981-- > splitSuffixOn_ pat xs = S.toList $ S.splitSuffixOn (A.fromList pat) (FL.toList) (S.fromList xs)
3983-- >>> splitSuffixOn_ "." ""
3986-- >>> splitSuffixOn_ "." "."
3989-- >>> splitSuffixOn_ "." "a"
3992-- >>> splitSuffixOn_ "." ".a"
3995-- >>> splitSuffixOn_ "." "a."
3998-- >>> splitSuffixOn_ "." "a.b"
4001-- >>> splitSuffixOn_ "." "a.b."
4004-- >>> splitSuffixOn_ "." "a..b.."
4007-- > lines = splitSuffixOn "\n"
4010{-# INLINE splitOnSuffixSeq #-}
4012 :: (IsStream t, MonadIO m, Storable a, Enum a, Eq a)
4013 => Array a -> Fold m a b -> t m a -> t m b
4014splitOnSuffixSeq patt f m =
4015 D.fromStreamD $ D.splitSuffixOn False patt f (D.toStreamD m)
4018-- | Like 'splitOn' but drops any empty splits.
4020{-# INLINE wordsOn #-}
4022 :: (IsStream t, Monad m, Storable a, Eq a)
4023 => Array a -> Fold m a b -> t m a -> t m b
4024wordsOn subseq f m = undefined -- D.fromStreamD $ D.wordsOn f subseq (D.toStreamD m)
4027-- XXX use a non-monadic intersperse to remove the MonadAsync constraint.
4029-- | Like 'splitOnSeq' but splits the separator as well, as an infix token.
4031-- > splitOn'_ pat xs = S.toList $ S.splitOn' (A.fromList pat) (FL.toList) (S.fromList xs)
4033-- >>> splitOn'_ "" "hello"
4034-- > ["h","","e","","l","","l","","o"]
4036-- >>> splitOn'_ "hello" ""
4039-- >>> splitOn'_ "hello" "hello"
4042-- >>> splitOn'_ "x" "hello"
4045-- >>> splitOn'_ "h" "hello"
4048-- >>> splitOn'_ "o" "hello"
4051-- >>> splitOn'_ "e" "hello"
4054-- >>> splitOn'_ "l" "hello"
4055-- > ["he","l","","l","o"]
4057-- >>> splitOn'_ "ll" "hello"
4061{-# INLINE splitBySeq #-}
4063 :: (IsStream t, MonadAsync m, Storable a, Enum a, Eq a)
4064 => Array a -> Fold m a b -> t m a -> t m b
4065splitBySeq patt f m =
4066 intersperseM (fold f (A.toStream patt)) $ splitOnSeq patt f m
4068-- | Like 'splitSuffixOn' but keeps the suffix intact in the splits.
4070-- > splitSuffixOn'_ pat xs = S.toList $ FL.splitSuffixOn' (A.fromList pat) (FL.toList) (S.fromList xs)
4072-- >>> splitSuffixOn'_ "." ""
4075-- >>> splitSuffixOn'_ "." "."
4078-- >>> splitSuffixOn'_ "." "a"
4081-- >>> splitSuffixOn'_ "." ".a"
4084-- >>> splitSuffixOn'_ "." "a."
4087-- >>> splitSuffixOn'_ "." "a.b"
4090-- >>> splitSuffixOn'_ "." "a.b."
4093-- >>> splitSuffixOn'_ "." "a..b.."
4094-- > ["a.",".","b.","."]
4097{-# INLINE splitWithSuffixSeq #-}
4099 :: (IsStream t, MonadIO m, Storable a, Enum a, Eq a)
4100 => Array a -> Fold m a b -> t m a -> t m b
4101splitWithSuffixSeq patt f m =
4102 D.fromStreamD $ D.splitSuffixOn True patt f (D.toStreamD m)
4105-- This can be implemented easily using Rabin Karp
4106-- | Split post any one of the given patterns.
4107{-# INLINE splitSuffixOnAny #-}
4109 :: (IsStream t, Monad m, Storable a, Integral a)
4110 => [Array a] -> Fold m a b -> t m a -> t m b
4111splitSuffixOnAny subseq f m = undefined
4112 -- D.fromStreamD $ D.splitPostAny f subseq (D.toStreamD m)
4115------------------------------------------------------------------------------
4117------------------------------------------------------------------------------
4119-- | @splitInnerBy splitter joiner stream@ splits the inner containers @f a@ of
4120-- an input stream @t m (f a)@ using the @splitter@ function. Container
4121-- elements @f a@ are collected until a split occurs, then all the elements
4122-- before the split are joined using the @joiner@ function.
4124-- For example, if we have a stream of @Array Word8@, we may want to split the
4125-- stream into arrays representing lines separated by '\n' byte such that the
4126-- resulting stream after a split would be one array for each line.
4128-- CAUTION! This is not a true streaming function as the container size after
4129-- the split and merge may not be bounded.
4132{-# INLINE splitInnerBy #-}
4134 :: (IsStream t, Monad m)
4135 => (f a -> m (f a, Maybe (f a))) -- splitter
4136 -> (f a -> f a -> m (f a)) -- joiner
4139splitInnerBy splitter joiner xs =
4140 D.fromStreamD $ D.splitInnerBy splitter joiner $ D.toStreamD xs
4142-- | Like 'splitInnerBy' but splits assuming the separator joins the segment in
4146{-# INLINE splitInnerBySuffix #-}
4148 :: (IsStream t, Monad m, Eq (f a), Monoid (f a))
4149 => (f a -> m (f a, Maybe (f a))) -- splitter
4150 -> (f a -> f a -> m (f a)) -- joiner
4153splitInnerBySuffix splitter joiner xs =
4154 D.fromStreamD $ D.splitInnerBySuffix splitter joiner $ D.toStreamD xs
4156------------------------------------------------------------------------------
4157-- Reorder in sequence
4158------------------------------------------------------------------------------
4161-- Buffer until the next element in sequence arrives. The function argument
4162-- determines the difference in sequence numbers. This could be useful in
4163-- implementing sequenced streams, for example, TCP reassembly.
4164{-# INLINE reassembleBy #-}
4166 :: (IsStream t, Monad m)
4171reassembleBy = undefined
4174------------------------------------------------------------------------------
4176------------------------------------------------------------------------------
4178-- | Tap the data flowing through a stream into a 'Fold'. For example, you may
4179-- add a tap to log the contents flowing through the stream. The fold is used
4180-- only for effects, its result is discarded.
4185-- -----stream m a ---------------stream m a-----
4190-- > S.drain $ S.tap (FL.drainBy print) (S.enumerateFromTo 1 2)
4195-- Compare with 'trace'.
4199tap :: (IsStream t, Monad m) => FL.Fold m a b -> t m a -> t m a
4200tap f xs = D.fromStreamD $ D.tap f (D.toStreamD xs)
4202-- | @tapOffsetEvery offset n@ taps every @n@th element in the stream
4203-- starting at @offset@. @offset@ can be between @0@ and @n - 1@. Offset 0
4204-- means start at the first element in the stream. If the offset is outside
4205-- this range then @offset `mod` n@ is used as offset.
4208-- >>> S.drain $ S.tapOffsetEvery 0 2 (FL.mapM print FL.toList) $ S.enumerateFromTo 0 10
4214{-# INLINE tapOffsetEvery #-}
4215tapOffsetEvery :: (IsStream t, Monad m)
4216 => Int -> Int -> FL.Fold m a b -> t m a -> t m a
4217tapOffsetEvery offset n f xs =
4218 D.fromStreamD $ D.tapOffsetEvery offset n f (D.toStreamD xs)
4220-- | Redirect a copy of the stream to a supplied fold and run it concurrently
4221-- in an independent thread. The fold may buffer some elements. The buffer size
4222-- is determined by the prevailing 'maxBuffer' setting.
4227-- -----stream m a ---------------stream m a-----
4232-- > S.drain $ S.tapAsync (S.mapM_ print) (S.enumerateFromTo 1 2)
4237-- Exceptions from the concurrently running fold are propagated to the current
4238-- computation. Note that, because of buffering in the fold, exceptions may be
4239-- delayed and may not correspond to the current element being processed in the
4240-- parent stream, but we guarantee that before the parent stream stops the tap
4241-- finishes and all exceptions from it are drained.
4244-- Compare with 'tap'.
4247{-# INLINE tapAsync #-}
4248tapAsync :: (IsStream t, MonadAsync m) => FL.Fold m a b -> t m a -> t m a
4249tapAsync f xs = D.fromStreamD $ D.tapAsync f (D.toStreamD xs)
4251-- | @pollCounts predicate transform fold stream@ counts those elements in the
4252-- stream that pass the @predicate@. The resulting count stream is sent to
4253-- another thread which transforms it using @transform@ and then folds it using
4254-- @fold@. The thread is automatically cleaned up if the stream stops or
4255-- aborts due to exception.
4257-- For example, to print the count of elements processed every second:
4260-- > S.drain $ S.pollCounts (const True) (S.rollingMap (-) . S.delayPost 1) (FL.drainBy print)
4261-- $ S.enumerateFrom 0
4264-- Note: This may not work correctly on 32-bit machines.
4268{-# INLINE pollCounts #-}
4270 (IsStream t, MonadAsync m)
4272 -> (t m Int -> t m Int)
4276pollCounts predicate transf f xs =
4278 $ D.pollCounts predicate (D.toStreamD . transf . D.fromStreamD) f
4281-- | Calls the supplied function with the number of elements consumed
4282-- every @n@ seconds. The given function is run in a separate thread
4283-- until the end of the stream. In case there is an exception in the
4284-- stream the thread is killed during the next major GC.
4286-- Note: The action is not guaranteed to run if the main thread exits.
4289-- > delay n = threadDelay (round $ n * 1000000) >> return n
4290-- > S.drain $ S.tapRate 2 (\\n -> print $ show n ++ " elements processed") (delay 1 S.|: delay 0.5 S.|: delay 0.5 S.|: S.nil)
4291-- 2 elements processed
4292-- 1 elements processed
4295-- Note: This may not work correctly on 32-bit machines.
4298{-# INLINE tapRate #-}
4300 (IsStream t, MonadAsync m, MonadCatch m)
4305tapRate n f xs = D.fromStreamD $ D.tapRate n f $ D.toStreamD xs
4307-- | Apply a monadic function to each element flowing through the stream and
4308-- discard the results.
4311-- > S.drain $ S.trace print (S.enumerateFromTo 1 2)
4316-- Compare with 'tap'.
4320trace :: (IsStream t, MonadAsync m) => (a -> m b) -> t m a -> t m a
4321trace f = mapM (\x -> void (f x) >> return x)
4323-- | Perform a side effect before yielding each element of the stream and
4324-- discard the results.
4327-- > S.drain $ S.trace_ (print "got here") (S.enumerateFromTo 1 2)
4332-- See also: 'trace', 'interspersePrefix_'
4335{-# INLINE trace_ #-}
4336trace_ :: (IsStream t, Monad m) => m b -> t m a -> t m a
4337trace_ eff = Serial.mapM (\x -> eff >> return x)
4339------------------------------------------------------------------------------
4340-- Windowed classification
4341------------------------------------------------------------------------------
4343-- We divide the stream into windows or chunks in space or time and each window
4344-- can be associated with a key, all events associated with a particular key in
4345-- the window can be folded to a single result. The stream can be split into
4346-- windows by size or by using a split predicate on the elements in the stream.
4347-- For example, when we receive a closing flag, we can close the window.
4349-- A "chunk" is a space window and a "session" is a time window. Are there any
4350-- other better short words to describe them. An alternative is to use
4351-- "swindow" and "twindow". Another word for "session" could be "spell".
4353-- TODO: To mark the position in space or time we can have Indexed or
4354-- TimeStamped types. That can make it easy to deal with the position indices
4357------------------------------------------------------------------------------
4358-- Keyed Sliding Windows
4359------------------------------------------------------------------------------
4362{-# INLINABLE classifySlidingChunks #-}
4363classifySlidingChunks
4364 :: (IsStream t, MonadAsync m, Ord k)
4365 => Int -- ^ window size
4366 -> Int -- ^ window slide
4367 -> Fold m a b -- ^ Fold to be applied to window events
4368 -> t m (k, a, Bool) -- ^ window key, data, close event
4370classifySlidingChunks wsize wslide (Fold step initial extract) str
4373-- XXX Another variant could be to slide the window on an event, e.g. in TCP we
4374-- slide the send window when an ack is received and we slide the receive
4375-- window when a sequence is complete. Sliding is stateful in case of TCP,
4376-- sliding releases the send buffer or makes data available to the user from
4377-- the receive buffer.
4378{-# INLINABLE classifySlidingSessions #-}
4379classifySlidingSessions
4380 :: (IsStream t, MonadAsync m, Ord k)
4381 => Double -- ^ timer tick in seconds
4382 -> Double -- ^ time window size
4383 -> Double -- ^ window slide
4384 -> Fold m a b -- ^ Fold to be applied to window events
4385 -> t m (k, a, Bool, AbsTime) -- ^ window key, data, close flag, timestamp
4387classifySlidingSessions tick interval slide (Fold step initial extract) str
4391------------------------------------------------------------------------------
4392-- Sliding Window Buffers
4393------------------------------------------------------------------------------
4395-- These buffered versions could be faster than concurrent incremental folds of
4396-- all overlapping windows as in many cases we may not need all the values to
4397-- compute the fold, we can just compute the result using the old value and new
4398-- value. However, we may need the buffer once in a while, for example for
4399-- string search we usually compute the hash incrementally but when the hash
4400-- matches the hash of the pattern we need to compare the whole string.
4402-- XXX we should be able to implement sequence based splitting combinators
4403-- using this combinator.
4406-- | Buffer n elements of the input in a ring buffer. When t new elements are
4407-- collected, slide the window to remove the same number of oldest elements,
4408-- insert the new elements, and apply an incremental fold on the sliding
4409-- window, supplying the outgoing elements, the new ring buffer as arguments.
4411 :: (IsStream t, Monad m, Ord a, Storable a)
4412 => Int -- window size
4413 -> Int -- window slide
4414 -> Fold m (Ring a, Array a) b
4417slidingChunkBuffer = undefined
4419-- Buffer n seconds worth of stream elements of the input in a radix tree.
4420-- Every t seconds, remove the items that are older than n seconds, and apply
4421-- an incremental fold on the sliding window, supplying the outgoing elements,
4422-- and the new radix tree buffer as arguments.
4424 :: (IsStream t, Monad m, Ord a, Storable a)
4425 => Int -- window size
4427 -> Fold m (RTree a, Array a) b
4430slidingSessionBuffer = undefined
4433------------------------------------------------------------------------------
4434-- Keyed Session Windows
4435------------------------------------------------------------------------------
4438-- | Keyed variable size space windows. Close the window if we do not receive a
4439-- window event in the next "spaceout" elements.
4440{-# INLINABLE classifyChunksBy #-}
4442 :: (IsStream t, MonadAsync m, Ord k)
4443 => Int -- ^ window spaceout (spread)
4444 -> Bool -- ^ reset the spaceout when a chunk window element is received
4445 -> Fold m a b -- ^ Fold to be applied to chunk window elements
4446 -> t m (k, a, Bool) -- ^ chunk key, data, last element
4448classifyChunksBy spanout reset (Fold step initial extract) str = undefined
4450-- | Like 'classifyChunksOf' but the chunk size is reset if an element is
4451-- received within the chunk size window. The chunk gets closed only if no
4452-- element is received within the chunk window.
4454{-# INLINABLE classifyKeepAliveChunks #-}
4455classifyKeepAliveChunks
4456 :: (IsStream t, MonadAsync m, Ord k)
4457 => Int -- ^ window spaceout (spread)
4458 -> Fold m a b -- ^ Fold to be applied to chunk window elements
4459 -> t m (k, a, Bool) -- ^ chunk key, data, last element
4461classifyKeepAliveChunks spanout = classifyChunksBy spanout True
4464data SessionState t m k a b = SessionState
4465 { sessionCurTime :: !AbsTime -- ^ time since last event
4466 , sessionEventTime :: !AbsTime -- ^ time as per last event
4467 , sessionCount :: !Int -- ^ total number sessions in progress
4468 , sessionTimerHeap :: H.Heap (H.Entry AbsTime k) -- ^ heap for timeouts
4469 , sessionKeyValueMap :: Map.Map k a -- ^ Stored sessions for keys
4470 , sessionOutputStream :: t (m :: Type -> Type) (k, b) -- ^ Completed sessions
4475-- | @classifySessionsBy tick timeout idle pred f stream@ groups timestamped
4476-- events in an input event stream into sessions based on a session key. Each
4477-- element in the stream is an event consisting of a triple @(session key,
4478-- sesssion data, timestamp)@. @session key@ is a key that uniquely identifies
4479-- the session. All the events belonging to a session are folded using the
4480-- fold @f@ until the fold returns a 'Left' result or a timeout has occurred.
4481-- The session key and the result of the fold are emitted in the output stream
4482-- when the session is purged.
4484-- When @idle@ is 'False', @timeout@ is the maximum lifetime of a session in
4485-- seconds, measured from the @timestamp@ of the first event in that session.
4486-- When @idle@ is 'True' then the timeout is an idle timeout, it is reset after
4487-- every event received in the session.
4489-- @timestamp@ in an event characterizes the time when the input event was
4490-- generated, this is an absolute time measured from some @Epoch@. The notion
4491-- of current time is maintained by a monotonic event time clock using the
4492-- timestamps seen in the input stream. The latest timestamp seen till now is
4493-- used as the base for the current time. When no new events are seen, a timer
4494-- is started with a tick duration specified by @tick@. This timer is used to
4495-- detect session timeouts in the absence of new events.
4497-- The predicate @pred@ is invoked with the current session count, if it
4498-- returns 'True' a session is ejected from the session cache before inserting
4499-- a new session. This could be useful to alert or eject sessions when the
4500-- number of sessions becomes too high.
4505-- XXX Perhaps we should use an "Event a" type to represent timestamped data.
4506{-# INLINABLE classifySessionsBy #-}
4508 :: (IsStream t, MonadAsync m, Ord k)
4509 => Double -- ^ timer tick in seconds
4510 -> Double -- ^ session timeout in seconds
4511 -> Bool -- ^ reset the timeout when an event is received
4512 -> (Int -> m Bool) -- ^ predicate to eject sessions based on session count
4513 -> Fold m a (Either b b) -- ^ Fold to be applied to session events
4514 -> t m (k, a, AbsTime) -- ^ session key, data, timestamp
4515 -> t m (k, b) -- ^ session key, fold result
4516classifySessionsBy tick tmout reset ejectPred
4517 (Fold step initial extract) str =
4518 concatMap sessionOutputStream $
4519 scanlMAfter' sstep (return szero) flush stream
4523 timeoutMs = toRelTime (round (tmout * 1000) :: MilliSecond64)
4524 tickMs = toRelTime (round (tick * 1000) :: MilliSecond64)
4525 szero = SessionState
4526 { sessionCurTime = toAbsTime (0 :: MilliSecond64)
4527 , sessionEventTime = toAbsTime (0 :: MilliSecond64)
4529 , sessionTimerHeap = H.empty
4530 , sessionKeyValueMap = Map.empty
4531 , sessionOutputStream = K.nil
4534 -- We can eject sessions based on the current session count to limit
4535 -- memory consumption. There are two possible strategies:
4537 -- 1) Eject old sessions or sessions beyond a certain/lower timeout
4538 -- threshold even before timeout, effectively reduce the timeout.
4539 -- 2) Drop creation of new sessions but keep accepting new events for the
4542 -- We use the first strategy as of now.
4544 -- Got a new stream input element
4545 sstep session@SessionState{..} (Just (key, value, timestamp)) = do
4546 -- XXX we should use a heap in pinned memory to scale it to a large
4549 -- To detect session inactivity we keep a timestamp of the latest event
4550 -- in the Map along with the fold result. When we purge the session
4551 -- from the heap we match the timestamp in the heap with the timestamp
4552 -- in the Map, if the latest timestamp is newer and has not expired we
4553 -- reinsert the key in the heap.
4555 -- XXX if the key is an Int, we can also use an IntMap for slightly
4556 -- better performance.
4558 let curTime = max sessionEventTime timestamp
4562 Just (Tuple' _ acc) -> return acc
4563 new <- step old value
4564 return $ Tuple' timestamp new
4565 mOld = Map.lookup key sessionKeyValueMap
4567 acc@(Tuple' _ fres) <- accumulate mOld
4571 -- deleting a key from the heap is expensive, so we never
4572 -- delete a key from heap, we just purge it from the Map and it
4573 -- gets purged from the heap on timeout. We just need an extra
4574 -- lookup in the Map when the key is purged from the heap, that
4575 -- should not be expensive.
4577 let (mp, cnt) = case mOld of
4578 Nothing -> (sessionKeyValueMap, sessionCount)
4579 Just _ -> (Map.delete key sessionKeyValueMap
4582 { sessionCurTime = curTime
4583 , sessionEventTime = curTime
4584 , sessionCount = cnt
4585 , sessionKeyValueMap = mp
4586 , sessionOutputStream = yield (key, x)
4589 (hp1, mp1, out1, cnt1) <- do
4590 let vars = (sessionTimerHeap, sessionKeyValueMap,
4591 K.nil, sessionCount)
4593 -- inserting new entry
4595 -- Eject a session from heap and map is needed
4596 eject <- ejectPred sessionCount
4597 (hp, mp, out, cnt) <-
4602 -- Insert the new session in heap
4603 let expiry = addToAbsTime timestamp timeoutMs
4604 hp' = H.insert (Entry expiry key) hp
4605 in return (hp', mp, out, cnt + 1)
4606 -- updating old entry
4607 Just _ -> return vars
4609 let mp2 = Map.insert key acc mp1
4610 return $ SessionState
4611 { sessionCurTime = curTime
4612 , sessionEventTime = curTime
4613 , sessionCount = cnt1
4614 , sessionTimerHeap = hp1
4615 , sessionKeyValueMap = mp2
4616 , sessionOutputStream = out1
4619 -- Got a timer tick event
4620 sstep sessionState@SessionState{..} Nothing =
4621 let curTime = addToAbsTime sessionCurTime tickMs
4622 in ejectExpired sessionState curTime
4624 flush session@SessionState{..} = do
4625 (hp', mp', out, count) <-
4628 , sessionKeyValueMap
4633 { sessionCount = count
4634 , sessionTimerHeap = hp'
4635 , sessionKeyValueMap = mp'
4636 , sessionOutputStream = out
4644 -- delete from map and output the fold accumulator
4645 ejectEntry hp mp out cnt acc key = do
4647 let out1 = (key, fromEither sess) `K.cons` out
4648 let mp1 = Map.delete key mp
4649 return (hp, mp1, out1, cnt - 1)
4651 ejectAll (hp, mp, out, !cnt) = do
4652 let hres = H.uncons hp
4654 Just (Entry _ key, hp1) -> do
4655 r <- case Map.lookup key mp of
4656 Nothing -> return (hp1, mp, out, cnt)
4657 Just (Tuple' _ acc) -> ejectEntry hp1 mp out cnt acc key
4660 assert (Map.null mp) (return ())
4661 return (hp, mp, out, cnt)
4663 ejectOne (hp, mp, out, !cnt) = do
4664 let hres = H.uncons hp
4666 Just (Entry expiry key, hp1) ->
4667 case Map.lookup key mp of
4668 Nothing -> ejectOne (hp1, mp, out, cnt)
4669 Just (Tuple' latestTS acc) -> do
4670 let expiry1 = addToAbsTime latestTS timeoutMs
4671 if not reset || expiry1 <= expiry
4672 then ejectEntry hp1 mp out cnt acc key
4674 -- reset the session timeout and continue
4675 let hp2 = H.insert (Entry expiry1 key) hp1
4676 in ejectOne (hp2, mp, out, cnt)
4678 assert (Map.null mp) (return ())
4679 return (hp, mp, out, cnt)
4681 ejectExpired session@SessionState{..} curTime = do
4682 (hp', mp', out, count) <-
4683 ejectLoop sessionTimerHeap sessionKeyValueMap K.nil sessionCount
4685 { sessionCurTime = curTime
4686 , sessionCount = count
4687 , sessionTimerHeap = hp'
4688 , sessionKeyValueMap = mp'
4689 , sessionOutputStream = out
4694 ejectLoop hp mp out !cnt = do
4695 let hres = H.uncons hp
4697 Just (Entry expiry key, hp1) -> do
4699 if curTime >= expiry
4700 then return (True, False)
4706 case Map.lookup key mp of
4707 Nothing -> ejectLoop hp1 mp out cnt
4708 Just (Tuple' latestTS acc) -> do
4709 let expiry1 = addToAbsTime latestTS timeoutMs
4710 if expiry1 <= curTime || not reset || force
4712 (hp2,mp1,out1,cnt1) <-
4713 ejectEntry hp1 mp out cnt acc key
4714 ejectLoop hp2 mp1 out1 cnt1
4716 -- reset the session timeout and continue
4717 let hp2 = H.insert (Entry expiry1 key) hp1
4718 in ejectLoop hp2 mp out cnt
4719 else return (hp, mp, out, cnt)
4721 assert (Map.null mp) (return ())
4722 return (hp, mp, out, cnt)
4724 -- merge timer events in the stream
4725 stream = Serial.map Just str `Par.parallelFst` repeatM timer
4727 liftIO $ threadDelay (round $ tick * 1000000)
4730-- | Like 'classifySessionsOf' but the session is kept alive if an event is
4731-- received within the session window. The session times out and gets closed
4732-- only if no event is received within the specified session window size.
4734-- If the ejection predicate returns 'True', the session that was idle for
4735-- the longest time is ejected before inserting a new session.
4738-- classifyKeepAliveSessions timeout pred = classifySessionsBy 1 timeout True pred
4743{-# INLINABLE classifyKeepAliveSessions #-}
4744classifyKeepAliveSessions
4745 :: (IsStream t, MonadAsync m, Ord k)
4746 => Double -- ^ session inactive timeout
4747 -> (Int -> m Bool) -- ^ predicate to eject sessions on session count
4748 -> Fold m a (Either b b) -- ^ Fold to be applied to session payload data
4749 -> t m (k, a, AbsTime) -- ^ session key, data, timestamp
4751classifyKeepAliveSessions tmout =
4752 classifySessionsBy 1 tmout True
4754------------------------------------------------------------------------------
4755-- Keyed tumbling windows
4756------------------------------------------------------------------------------
4758-- Tumbling windows is a special case of sliding windows where the window slide
4759-- is the same as the window size. Or it can be a special case of session
4760-- windows where the reset flag is set to False.
4762-- XXX instead of using the early termination flag in the stream, we can use an
4763-- early terminating fold instead.
4766-- | Split the stream into fixed size chunks of specified size. Within each
4767-- such chunk fold the elements in buckets identified by the keys. A particular
4768-- bucket fold can be terminated early if a closing flag is encountered in an
4769-- element for that key.
4772{-# INLINABLE classifyChunksOf #-}
4774 :: (IsStream t, MonadAsync m, Ord k)
4775 => Int -- ^ window size
4776 -> Fold m a b -- ^ Fold to be applied to window events
4777 -> t m (k, a, Bool) -- ^ window key, data, close event
4779classifyChunksOf wsize = classifyChunksBy wsize False
4782-- | Split the stream into fixed size time windows of specified interval in
4783-- seconds. Within each such window, fold the elements in sessions identified
4784-- by the session keys. The fold result is emitted in the output stream if the
4785-- fold returns a 'Left' result or if the time window ends.
4787-- Session @timestamp@ in the input stream is an absolute time from some epoch,
4788-- characterizing the time when the input element was generated. To detect
4789-- session window end, a monotonic event time clock is maintained synced with
4790-- the timestamps with a clock resolution of 1 second.
4792-- If the ejection predicate returns 'True', the session with the longest
4793-- lifetime is ejected before inserting a new session.
4796-- classifySessionsOf interval pred = classifySessionsBy 1 interval False pred
4801-- $ S.classifySessionsOf 3 (const (return False)) (fmap Right FL.toList)
4802-- $ S.map (\(ts,(k,a)) -> (k, a, ts))
4805-- $ (,) <$> S.fromList [1,2,3] <*> S.fromList [1,2,3]
4810{-# INLINABLE classifySessionsOf #-}
4812 :: (IsStream t, MonadAsync m, Ord k)
4813 => Double -- ^ time window size
4814 -> (Int -> m Bool) -- ^ predicate to eject sessions on session count
4815 -> Fold m a (Either b b) -- ^ Fold to be applied to session events
4816 -> t m (k, a, AbsTime) -- ^ session key, data, timestamp
4818classifySessionsOf interval =
4819 classifySessionsBy 1 interval False
4821------------------------------------------------------------------------------
4823------------------------------------------------------------------------------
4825-- | Run a side effect before the stream yields its first element.
4828{-# INLINE before #-}
4829before :: (IsStream t, Monad m) => m b -> t m a -> t m a
4830before action xs = D.fromStreamD $ D.before action $ D.toStreamD xs
4832-- | Run a side effect at the end of the stream. The side effect won't run if
4833-- the stream is garbage collected before it reached the end.
4835-- This has slightly better performance than 'after'.
4839{-# INLINE after_ #-}
4840after_ :: (IsStream t, Monad m) => m b -> t m a -> t m a
4841after_ action xs = D.fromStreamD $ D.after_ action $ D.toStreamD xs
4843-- | Run a side effect at the end of the stream or if it is garbage collected
4844-- even before reaching the end.
4849after :: (IsStream t, MonadIO m, MonadBaseControl IO m)
4850 => m b -> t m a -> t m a
4851after action xs = D.fromStreamD $ D.after action $ D.toStreamD xs
4853-- | Run a side effect whenever the stream aborts due to an exception.
4856{-# INLINE onException #-}
4857onException :: (IsStream t, MonadCatch m) => m b -> t m a -> t m a
4858onException action xs = D.fromStreamD $ D.onException action $ D.toStreamD xs
4860-- | Run a side effect at the end of the stream or if it aborts due to an
4861-- exception before it could reach the end. The side effect is not run if the
4862-- stream is garbage collected before reaching the end.
4864-- This has slightly better performance than 'finally'.
4868{-# INLINE finally_ #-}
4869finally_ :: (IsStream t, MonadCatch m) => m b -> t m a -> t m a
4870finally_ action xs = D.fromStreamD $ D.finally_ action $ D.toStreamD xs
4872-- | Run a side effect at the end of the stream, or if it aborts due to an
4873-- exception or if it is garbage collected before it could reach the end.
4877{-# INLINE finally #-}
4878finally :: (IsStream t, MonadAsync m, MonadCatch m) => m b -> t m a -> t m a
4879finally action xs = D.fromStreamD $ D.finally action $ D.toStreamD xs
4881-- | Run the first action before the stream starts and remember its output,
4882-- generate a stream using the output, run the second action using the
4883-- remembered value as an argument whenever the stream ends normally or due to
4884-- an exception. The second action won't run if the stream is garbage collected
4885-- before it could reach the end.
4887-- This has slightly better performance than 'bracket'.
4891{-# INLINE bracket_ #-}
4892bracket_ :: (IsStream t, MonadCatch m)
4893 => m b -> (b -> m c) -> (b -> t m a) -> t m a
4894bracket_ bef aft bet = D.fromStreamD $
4895 D.bracket_ bef aft (toStreamD . bet)
4897-- | Run the first action before the stream starts and remember its output,
4898-- generate a stream using the output, run the second action using the
4899-- remembered value as an argument whenever the stream ends normally, due to
4900-- an exception or if it is garbage collected after a partial lazy evaluation.
4904{-# INLINE bracket #-}
4905bracket :: (IsStream t, MonadAsync m, MonadCatch m)
4906 => m b -> (b -> m c) -> (b -> t m a) -> t m a
4907bracket bef aft bet = D.fromStreamD $
4908 D.bracket bef aft (toStreamD . bet)
4910-- | When evaluating a stream if an exception occurs, stream evaluation aborts
4911-- and the specified exception handler is run with the exception as argument.
4914{-# INLINE handle #-}
4915handle :: (IsStream t, MonadCatch m, Exception e)
4916 => (e -> t m a) -> t m a -> t m a
4918 D.fromStreamD $ D.handle (D.toStreamD . handler) $ D.toStreamD xs
4920------------------------------------------------------------------------------
4921-- Generalize the underlying monad
4922------------------------------------------------------------------------------
4924-- | Transform the inner monad of a stream using a natural transformation.
4929hoist :: (Monad m, Monad n)
4930 => (forall x. m x -> n x) -> SerialT m a -> SerialT n a
4931hoist f xs = fromStreamS $ S.hoist f (toStreamS xs)
4933-- | Generalize the inner monad of the stream from 'Identity' to any monad.
4937{-# INLINE generally #-}
4938generally :: (IsStream t, Monad m) => t Identity a -> t m a
4939generally xs = fromStreamS $ S.hoist (return . runIdentity) (toStreamS xs)
4941------------------------------------------------------------------------------
4942-- Add and remove a monad transformer
4943------------------------------------------------------------------------------
4945-- | Lift the inner monad of a stream using a monad transformer.
4949{-# INLINE liftInner #-}
4950liftInner :: (Monad m, IsStream t, MonadTrans tr, Monad (tr m))
4951 => t m a -> t (tr m) a
4952liftInner xs = fromStreamD $ D.liftInner (toStreamD xs)
4954-- | Evaluate the inner monad of a stream as 'ReaderT'.
4958{-# INLINE runReaderT #-}
4959runReaderT :: (IsStream t, Monad m) => m s -> t (ReaderT s m) a -> t m a
4960runReaderT s xs = fromStreamD $ D.runReaderT s (toStreamD xs)
4962-- | Evaluate the inner monad of a stream as 'StateT'.
4964-- This is supported only for 'SerialT' as concurrent state updation may not be
4969{-# INLINE evalStateT #-}
4970evalStateT :: Monad m => m s -> SerialT (StateT s m) a -> SerialT m a
4971evalStateT s xs = fromStreamD $ D.evalStateT s (toStreamD xs)
4973-- | Run a stateful (StateT) stream transformation using a given state.
4975-- This is supported only for 'SerialT' as concurrent state updation may not be
4980{-# INLINE usingStateT #-}
4984 -> (SerialT (StateT s m) a -> SerialT (StateT s m) a)
4987usingStateT s f xs = evalStateT s $ f $ liftInner xs
4989-- | Evaluate the inner monad of a stream as 'StateT' and emit the resulting
4990-- state and value pair after each step.
4992-- This is supported only for 'SerialT' as concurrent state updation may not be
4997{-# INLINE runStateT #-}
4998runStateT :: Monad m => m s -> SerialT (StateT s m) a -> SerialT m (s, a)
4999runStateT s xs = fromStreamD $ D.runStateT s (toStreamD xs)
5001-- | Run a stream transformation using a given environment.
5005{-# INLINE usingReaderT #-}
5007 :: (Monad m, IsStream t)
5009 -> (t (ReaderT r m) a -> t (ReaderT r m) a)
5012usingReaderT r f xs = runReaderT r $ f $ liftInner xs
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