on eff3255 help sign in
5022 lines 162 kB history raw
1{-# OPTIONS_GHC -Wno-orphans #-}
3#include "inline.hs"
5-- |
6-- Module : Streamly.Internal.Data.Stream.IsStream
7-- Copyright : (c) 2017 Harendra Kumar
8--
9-- License : BSD3
10-- Maintainer : streamly@composewell.com
11-- Stability : experimental
12-- Portability : GHC
13--
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
21 (
22 -- * Construction
23 -- ** Primitives
24 K.nil
25 , K.nilM
26 , K.cons
27 , (K..:)
29 , consM
30 , (|:)
32 -- ** From Values
33 , yield
34 , yieldM
35 , repeat
36 , repeatM
37 , replicate
38 , replicateM
40 -- ** Enumeration
41 , Enumerable (..)
42 , enumerate
43 , enumerateTo
45 -- ** Time Enumeration
46 , times
47 , absTimes
48 , relTimes
49 , durations
50 , ticks
51 , timeout
52 , currentTime
54 -- ** From Generators
55 , unfoldr
56 , unfoldrM
57 , unfold
58 , unfold0
59 , iterate
60 , iterateM
61 , fromIndices
62 , fromIndicesM
64 -- ** From Containers
65 , P.fromList
66 , fromListM
67 , K.fromFoldable
68 , fromFoldableM
69 , fromPrimIORef
70 , fromCallback
72 -- * Elimination
74 -- ** Deconstruction
75 , uncons
76 , tail
77 , init
79 -- ** Folding
80 -- ** Right Folds
81 , foldrM
82 , foldrS
83 , foldrT
84 , foldr
86 -- ** Left Folds
87 , foldl'
88 , foldl1'
89 , foldlM'
91 -- ** Composable Left Folds
92 , fold
93 , parse
94 , parseK
95 , parseD
97 -- ** Concurrent Folds
98 , foldAsync
99 , (|$.)
100 , (|&.)
102 -- ** Full Folds
104 -- -- ** To Summary (Full Folds)
105 , drain
106 , last
107 , length
108 , sum
109 , product
110 , mconcat
112 -- -- ** To Summary (Maybe) (Full Folds)
113 , maximumBy
114 , maximum
115 , minimumBy
116 , minimum
117 , the
119 -- ** Lazy Folds
120 -- -- ** To Containers (Full Folds)
121 , toList
122 , toListRev
123 , toPure
124 , toPureRev
126 -- ** Composable Left Folds
128 , toStream -- XXX rename to write?
129 , toStreamRev -- XXX rename to writeRev?
131 -- ** Partial Folds
133 -- -- ** To Elements (Partial Folds)
134 , drainN
135 , drainWhile
137 -- -- | Folds that extract selected elements of a stream or their properties.
138 , (!!)
139 , head
140 , headElse
141 , findM
142 , find
143 , lookup
144 , findIndex
145 , elemIndex
147 -- -- ** To Boolean (Partial Folds)
148 , null
149 , elem
150 , notElem
151 , all
152 , any
153 , and
154 , or
156 -- ** Multi-Stream folds
157 -- Full equivalence
158 , eqBy
159 , cmpBy
161 -- finding subsequences
162 , isPrefixOf
163 , isSuffixOf
164 , isInfixOf
165 , isSubsequenceOf
167 -- trimming sequences
168 , stripPrefix
169 , stripSuffix
170 -- , stripInfix
171 , dropPrefix
172 , dropInfix
173 , dropSuffix
175 -- * Transformation
176 , transform
178 -- ** Mapping
179 , Serial.map
180 , sequence
181 , mapM
183 -- ** Special Maps
184 , mapM_
185 , trace
186 , trace_
187 , tap
188 , tapOffsetEvery
189 , tapAsync
190 , tapRate
191 , pollCounts
193 -- ** Scanning
194 -- ** Left scans
195 , scanl'
196 , scanlM'
197 , scanlMAfter'
198 , postscanl'
199 , postscanlM'
200 , prescanl'
201 , prescanlM'
202 , scanl1'
203 , scanl1M'
205 -- ** Scan Using Fold
206 , scan
207 , postscan
209 -- XXX Once we have pipes the contravariant transformations can be
210 -- represented by attaching pipes before a transformation.
211 --
212 -- , lscanl'
213 -- , lscanlM'
214 -- , lscanl1'
215 -- , lscanl1M'
216 --
217 -- , lpostscanl'
218 -- , lpostscanlM'
219 -- , lprescanl'
220 -- , lprescanlM'
222 -- ** Concurrent Transformation
223 , D.mkParallel
224 -- Par.mkParallel
225 , applyAsync
226 , (|$)
227 , (|&)
229 -- ** Filtering
231 , filter
232 , filterM
234 -- ** Mapping Filters
235 , mapMaybe
236 , mapMaybeM
238 -- ** Deleting Elements
239 , deleteBy
240 , uniq
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
247 , insertBy
248 , intersperseM
249 , intersperseM_
250 , intersperse
251 , intersperseSuffix
252 , intersperseSuffix_
253 , interspersePrefix_
254 , intersperseSuffixBySpan
255 -- , intersperseBySpan
256 -- , intersperseByIndices -- using an index function/stream
258 -- time domain intersperse
259 -- , intersperseByTime
260 -- , intersperseByEvent
261 , interjectSuffix
262 , delay
263 , delayPost
264 , delayPre
266 -- ** Indexing
267 , indexed
268 , indexedR
269 , timestamped
270 , timeIndexed
271 -- , timestampedR -- timer
273 -- ** Reordering
274 , reverse
275 , reverse'
277 -- ** Parsing
278 , parseMany
279 , parseManyD
280 , parseManyTill
281 , parseIterate
283 -- ** Trimming
284 , take
285 -- , takeGE
286 -- , takeBetween
287 , takeByTime
288 -- , takeEnd
289 , takeWhile
290 , takeWhileM
291 -- , takeWhileEnd
292 , drop
293 , dropByTime
294 -- , dropEnd
295 , dropWhile
296 , dropWhileM
297 -- , dropWhileEnd
298 -- , dropAround
300 -- ** Breaking
302 -- Nary
303 , chunksOf
304 , chunksOf2
305 , arraysOf
306 , intervalsOf
308 -- ** Searching
309 -- -- *** Searching Elements
310 , findIndices
311 , elemIndices
313 -- -- *** Searching Sequences
314 -- , seqIndices -- search a sequence in the stream
316 -- -- *** Searching Multiple Sequences
317 -- , seqIndicesAny -- search any of the given sequence in the stream
319 -- -- -- ** Searching Streams
320 -- -- | Finding a stream within another stream.
322 -- ** Splitting
323 -- | Streams can be sliced into segments in space or in time. We use the
324 -- term @chunk@ to refer to a spatial length of the stream (spatial window)
325 -- and the term @session@ to refer to a length in time (time window).
327 -- -- *** Using Element Separators
328 , splitOn
329 , splitOnSuffix
330 -- , splitOnPrefix
332 -- , splitBy
333 , splitWithSuffix
334 -- , splitByPrefix
335 , wordsBy -- stripAndCompactBy
337 -- -- *** Splitting By Sequences
338 , splitOnSeq
339 , splitOnSuffixSeq
340 -- , splitOnPrefixSeq
342 -- Keeping the delimiters
343 , splitBySeq
344 , splitWithSuffixSeq
345 -- , splitByPrefixSeq
346 -- , wordsBySeq
348 -- Splitting using multiple sequence separators
349 -- , splitOnAnySeq
350 -- , splitOnAnySuffixSeq
351 -- , splitOnAnyPrefixSeq
353 -- -- *** Splitting By Streams
354 -- -- | Splitting a stream using another stream as separator.
356 -- Nested splitting
357 , splitInnerBy
358 , splitInnerBySuffix
360 -- ** Grouping
361 -- In imperative terms, grouped folding can be considered as a nested loop
362 -- where we loop over the stream to group elements and then loop over
363 -- individual groups to fold them to a single value that is yielded in the
364 -- output stream.
366 -- , groupScan
368 , groups
369 , groupsBy
370 , groupsByRolling
372 -- ** Group map
373 , rollingMapM
374 , rollingMap
376 -- * Windowed Classification
378 -- | Split the stream into windows or chunks in space or time. Each window
379 -- can be associated with a key, all events associated with a particular
380 -- key in the window can be folded to a single result. The stream is split
381 -- into windows of specified size, the window can be terminated early if
382 -- the closing flag is specified in the input stream.
383 --
384 -- The term "chunk" is used for a space window and the term "session" is
385 -- used for a time window.
387 -- ** Tumbling Windows
388 -- | A new window starts after the previous window is finished.
390 -- , classifyChunksOf
391 , classifySessionsBy
392 , classifySessionsOf
394 -- ** Keep Alive Windows
395 -- | The window size is extended if an event arrives within the specified
396 -- window size. This can represent sessions with idle or inactive timeout.
398 -- , classifyKeepAliveChunks
399 , classifyKeepAliveSessions
401 {-
402 -- ** Sliding Windows
403 -- | A new window starts after the specified slide from the previous
404 -- window. Therefore windows can overlap.
405 , classifySlidingChunks
406 , classifySlidingSessions
407 -}
408 -- ** Sliding Window Buffers
409 -- , slidingChunkBuffer
410 -- , slidingSessionBuffer
412 -- * Combining Streams
414 -- ** Appending
415 , append
417 -- ** Interleaving
418 , interleave
419 , interleaveMin
420 , interleaveSuffix
421 , interleaveInfix
423 , Serial.wSerialFst
424 , Serial.wSerialMin
426 -- ** Scheduling
427 , roundrobin
429 -- ** Parallel
430 , Par.parallelFst
431 , Par.parallelMin
433 -- ** Merging
435 -- , merge
436 , mergeBy
437 , mergeByM
438 , mergeAsyncBy
439 , mergeAsyncByM
441 -- ** Zipping
442 , Z.zipWith
443 , Z.zipWithM
444 , Z.zipAsyncWith
445 , Z.zipAsyncWithM
447 -- ** Folding Containers of Streams
448 , foldWith
449 , foldMapWith
450 , forEachWith
452 -- Flattening Nested Streams
453 -- ** Folding Streams of Streams
454 , concat
455 , concatM
456 , concatMap
457 , concatMapM
458 -- XXX add stateful concatMapWith?
459 , concatMapWith
460 -- , bindWith
462 -- ** Flattening Using Unfolds
463 , concatUnfold
464 , concatUnfoldInterleave
465 , concatUnfoldRoundrobin
467 -- ** Feedback Loops
468 , concatMapIterateWith
469 , concatMapTreeWith
470 , concatMapLoopWith
471 , concatMapTreeYieldLeavesWith
472 , K.mfix
474 -- ** Inserting Streams in Streams
475 , gintercalate
476 , gintercalateSuffix
477 , intercalate
478 , intercalateSuffix
479 , interpose
480 , interposeSuffix
481 -- , interposeBy
483 -- * Exceptions
484 , before
485 , after_
486 , after
487 , bracket_
488 , bracket
489 , onException
490 , finally_
491 , finally
492 , handle
494 -- * Generalize Inner Monad
495 , hoist
496 , generally
498 -- * Transform Inner Monad
499 , liftInner
500 , usingReaderT
501 , runReaderT
502 , evalStateT
503 , usingStateT
504 , runStateT
506 -- * Diagnostics
507 , inspectMode
509 -- * Deprecated
510 , K.once
511 , each
512 , scanx
513 , foldx
514 , foldxM
515 , foldr1
516 , runStream
517 , runN
518 , runWhile
519 , fromHandle
520 , toHandle
521 )
522where
524import Control.Concurrent (threadDelay)
525import Control.Exception (Exception, assert)
526import Control.Monad (void)
527import Control.Monad.Catch (MonadCatch, MonadThrow)
528import Control.Monad.IO.Class (MonadIO(..))
529import Control.Monad.Trans.Reader (ReaderT)
530import Control.Monad.Trans.State.Strict (StateT)
531import Control.Monad.Trans.Class (MonadTrans(..))
532import Control.Monad.Trans.Control (MonadBaseControl)
533import Data.Functor.Identity (Identity (..))
534import Data.Kind (Type)
535import Data.Heap (Entry(..))
536import Data.Maybe (isJust, fromJust, isNothing)
537import Data.Void (Void)
538import Foreign.Storable (Storable)
539import Streamly.Internal.Data.Stream.Enumeration
540 (Enumerable(..), enumerate, enumerateTo)
541import Streamly.Internal.Data.Fold.Types (Fold (..), Fold2 (..))
542import Streamly.Internal.Data.Parser (Parser (..))
543import Streamly.Internal.Data.Unfold.Types (Unfold)
544import Streamly.Internal.Memory.Array.Types (Array, writeNUnsafe)
545import Streamly.Internal.Data.SVar (MonadAsync, defState, Rate)
546import Streamly.Internal.Data.Stream.Combinators (inspectMode, maxYields)
547import Streamly.Internal.Data.Stream.Prelude
548 (fromStreamS, toStreamS, foldWith, foldMapWith, forEachWith)
549import Streamly.Internal.Data.Stream.StreamD (fromStreamD, toStreamD)
550import Streamly.Internal.Data.Stream.StreamK (IsStream((|:), consM))
551import Streamly.Internal.Data.Stream.Serial (SerialT, WSerialT)
552import Streamly.Internal.Data.Stream.Zip (ZipSerialM)
553import Streamly.Internal.Data.Pipe.Types (Pipe (..))
554import Streamly.Internal.Data.Time.Units
555 ( AbsTime, MilliSecond64(..), addToAbsTime, toRelTime
556 , toAbsTime, TimeUnit64, RelTime64, addToAbsTime64)
557import Streamly.Internal.Data.IORef.Prim (Prim, IORef)
558import Streamly.Internal.Data.Tuple.Strict (Tuple'(..))
560import qualified Streamly.Internal.Memory.Array as A
561import qualified Streamly.Data.Fold as FL
562import qualified Streamly.Internal.Data.Fold.Types as FL
563import qualified Streamly.Internal.Data.Stream.Prelude as P
564import qualified Streamly.Internal.Data.Stream.StreamK as K
565import qualified Streamly.Internal.Data.Stream.StreamD as D
566import qualified Streamly.Internal.Data.Stream.Serial as Serial
567import qualified Streamly.Internal.Data.Stream.Parallel as Par
568import qualified Streamly.Internal.Data.Stream.Zip as Z
569import qualified Streamly.Internal.Data.Parser.ParserK.Types as PRK
570import qualified Streamly.Internal.Data.Parser.ParserD as PRD
571import qualified Data.Heap as H
572import qualified Data.Map.Strict as Map
573import qualified Prelude
574import qualified System.IO as IO
575#ifdef USE_STREAMK_ONLY
576import qualified Streamly.Internal.Data.Stream.StreamK as S
577#else
578import qualified Streamly.Internal.Data.Stream.StreamD as S
579#endif
581import Prelude hiding
582 ( filter, drop, dropWhile, take, takeWhile, zipWith, foldr
583 , foldl, map, mapM, mapM_, sequence, all, any, sum, product, elem
584 , notElem, maximum, minimum, head, last, tail, length, null
585 , reverse, iterate, init, and, or, lookup, foldr1, (!!)
586 , scanl, scanl1, replicate, concatMap, span, splitAt, break
587 , repeat, concat, mconcat)
589------------------------------------------------------------------------------
590-- Deconstruction
591------------------------------------------------------------------------------
593-- | Decompose a stream into its head and tail. If the stream is empty, returns
594-- 'Nothing'. If the stream is non-empty, returns @Just (a, ma)@, where @a@ is
595-- the head of the stream and @ma@ its tail.
596--
597-- This is a brute force primitive. Avoid using it as long as possible, use it
598-- when no other combinator can do the job. This can be used to do pretty much
599-- anything in an imperative manner, as it just breaks down the stream into
600-- individual elements and we can loop over them as we deem fit. For example,
601-- this can be used to convert a streamly stream into other stream types.
602--
603-- @since 0.1.0
604{-# INLINE uncons #-}
605uncons :: (IsStream t, Monad m) => SerialT m a -> m (Maybe (a, t m a))
606uncons m = K.uncons (K.adapt m)
608------------------------------------------------------------------------------
609-- Generation by Unfolding
610------------------------------------------------------------------------------
612-- |
613-- @
614-- unfoldr step s =
615-- case step s of
616-- Nothing -> 'K.nil'
617-- Just (a, b) -> a \`cons` unfoldr step b
618-- @
619--
620-- Build a stream by unfolding a /pure/ step function @step@ starting from a
621-- seed @s@. The step function returns the next element in the stream and the
622-- next seed value. When it is done it returns 'Nothing' and the stream ends.
623-- For example,
624--
625-- @
626-- let f b =
627-- if b > 3
628-- then Nothing
629-- else Just (b, b + 1)
630-- in toList $ unfoldr f 0
631-- @
632-- @
633-- [0,1,2,3]
634-- @
635--
636-- @since 0.1.0
637{-# INLINE_EARLY unfoldr #-}
638unfoldr :: (Monad m, IsStream t) => (b -> Maybe (a, b)) -> b -> t m a
639unfoldr step seed = fromStreamS (S.unfoldr step seed)
640{-# RULES "unfoldr fallback to StreamK" [1]
641 forall a b. S.toStreamK (S.unfoldr a b) = K.unfoldr a b #-}
643-- | Build a stream by unfolding a /monadic/ step function starting from a
644-- seed. The step function returns the next element in the stream and the next
645-- seed value. When it is done it returns 'Nothing' and the stream ends. For
646-- example,
647--
648-- @
649-- let f b =
650-- if b > 3
651-- then return Nothing
652-- else print b >> return (Just (b, b + 1))
653-- in drain $ unfoldrM f 0
654-- @
655-- @
656-- 0
657-- 1
658-- 2
659-- 3
660-- @
661-- When run concurrently, the next unfold step can run concurrently with the
662-- processing of the output of the previous step. Note that more than one step
663-- cannot run concurrently as the next step depends on the output of the
664-- previous step.
665--
666-- @
667-- (asyncly $ S.unfoldrM (\\n -> liftIO (threadDelay 1000000) >> return (Just (n, n + 1))) 0)
668-- & S.foldlM' (\\_ a -> threadDelay 1000000 >> print a) ()
669-- @
670--
671-- /Concurrent/
672--
673-- /Since: 0.1.0/
674{-# INLINE_EARLY unfoldrM #-}
675unfoldrM :: (IsStream t, MonadAsync m) => (b -> m (Maybe (a, b))) -> b -> t m a
676unfoldrM = K.unfoldrM
678{-# RULES "unfoldrM serial" unfoldrM = unfoldrMSerial #-}
679{-# INLINE_EARLY unfoldrMSerial #-}
680unfoldrMSerial :: MonadAsync m => (b -> m (Maybe (a, b))) -> b -> SerialT m a
681unfoldrMSerial = Serial.unfoldrM
683{-# RULES "unfoldrM wSerial" unfoldrM = unfoldrMWSerial #-}
684{-# INLINE_EARLY unfoldrMWSerial #-}
685unfoldrMWSerial :: MonadAsync m => (b -> m (Maybe (a, b))) -> b -> WSerialT m a
686unfoldrMWSerial = Serial.unfoldrM
688{-# RULES "unfoldrM zipSerial" unfoldrM = unfoldrMZipSerial #-}
689{-# INLINE_EARLY unfoldrMZipSerial #-}
690unfoldrMZipSerial :: MonadAsync m => (b -> m (Maybe (a, b))) -> b -> ZipSerialM m a
691unfoldrMZipSerial = Serial.unfoldrM
693-- | Convert an 'Unfold' into a stream by supplying it an input seed.
694--
695-- >>> unfold (UF.replicateM 10) (putStrLn "hello")
696--
697-- /Since: 0.7.0/
698{-# INLINE unfold #-}
699unfold :: (IsStream t, Monad m) => Unfold m a b -> a -> t m b
700unfold unf x = fromStreamD $ D.unfold unf x
702-- | Convert an 'Unfold' with a closed input end into a stream.
703--
704-- /Internal/
705{-# INLINE unfold0 #-}
706unfold0 :: (IsStream t, Monad m) => Unfold m Void b -> t m b
707unfold0 unf = unfold unf (error "unfold0: unexpected void evaluation")
709------------------------------------------------------------------------------
710-- Specialized Generation
711------------------------------------------------------------------------------
713-- Faster than yieldM because there is no bind.
714--
715-- |
716-- @
717-- yield a = a \`cons` nil
718-- @
719--
720-- Create a singleton stream from a pure value.
721--
722-- The following holds in monadic streams, but not in Zip streams:
723--
724-- @
725-- yield = pure
726-- yield = yieldM . pure
727-- @
728--
729-- In Zip applicative streams 'yield' is not the same as 'pure' because in that
730-- case 'pure' is equivalent to 'repeat' instead. 'yield' and 'pure' are
731-- equally efficient, in other cases 'yield' may be slightly more efficient
732-- than the other equivalent definitions.
733--
734-- @since 0.4.0
735{-# INLINE yield #-}
736yield :: IsStream t => a -> t m a
737yield = K.yield
739-- |
740-- @
741-- yieldM m = m \`consM` nil
742-- @
743--
744-- Create a singleton stream from a monadic action.
745--
746-- @
747-- > toList $ yieldM getLine
748-- hello
749-- ["hello"]
750-- @
751--
752-- @since 0.4.0
753{-# INLINE yieldM #-}
754yieldM :: (Monad m, IsStream t) => m a -> t m a
755yieldM = K.yieldM
757-- |
758-- @
759-- fromIndices f = let g i = f i \`cons` g (i + 1) in g 0
760-- @
761--
762-- Generate an infinite stream, whose values are the output of a function @f@
763-- applied on the corresponding index. Index starts at 0.
764--
765-- @
766-- > S.toList $ S.take 5 $ S.fromIndices id
767-- [0,1,2,3,4]
768-- @
769--
770-- @since 0.6.0
771{-# INLINE fromIndices #-}
772fromIndices :: (IsStream t, Monad m) => (Int -> a) -> t m a
773fromIndices = fromStreamS . S.fromIndices
775--
776-- |
777-- @
778-- fromIndicesM f = let g i = f i \`consM` g (i + 1) in g 0
779-- @
780--
781-- Generate an infinite stream, whose values are the output of a monadic
782-- function @f@ applied on the corresponding index. Index starts at 0.
783--
784-- /Concurrent/
785--
786-- @since 0.6.0
787{-# INLINE_EARLY fromIndicesM #-}
788fromIndicesM :: (IsStream t, MonadAsync m) => (Int -> m a) -> t m a
789fromIndicesM = K.fromIndicesM
791{-# RULES "fromIndicesM serial" fromIndicesM = fromIndicesMSerial #-}
792{-# INLINE fromIndicesMSerial #-}
793fromIndicesMSerial :: MonadAsync m => (Int -> m a) -> SerialT m a
794fromIndicesMSerial = fromStreamS . S.fromIndicesM
796-- |
797-- @
798-- replicateM = take n . repeatM
799-- @
800--
801-- Generate a stream by performing a monadic action @n@ times. Same as:
802--
803-- @
804-- drain $ serially $ S.replicateM 10 $ (threadDelay 1000000 >> print 1)
805-- drain $ asyncly $ S.replicateM 10 $ (threadDelay 1000000 >> print 1)
806-- @
807--
808-- /Concurrent/
809--
810-- @since 0.1.1
811{-# INLINE_EARLY replicateM #-}
812replicateM :: (IsStream t, MonadAsync m) => Int -> m a -> t m a
813replicateM = K.replicateM
815{-# RULES "replicateM serial" replicateM = replicateMSerial #-}
816{-# INLINE replicateMSerial #-}
817replicateMSerial :: MonadAsync m => Int -> m a -> SerialT m a
818replicateMSerial n = fromStreamS . S.replicateM n
820-- |
821-- @
822-- replicate = take n . repeat
823-- @
824--
825-- Generate a stream of length @n@ by repeating a value @n@ times.
826--
827-- @since 0.6.0
828{-# INLINE_NORMAL replicate #-}
829replicate :: (IsStream t, Monad m) => Int -> a -> t m a
830replicate n = fromStreamS . S.replicate n
832-- |
833-- Generate an infinite stream by repeating a pure value.
834--
835-- @since 0.4.0
836{-# INLINE_NORMAL repeat #-}
837repeat :: (IsStream t, Monad m) => a -> t m a
838repeat = fromStreamS . S.repeat
840-- |
841-- @
842-- repeatM = fix . consM
843-- repeatM = cycle1 . yieldM
844-- @
845--
846-- Generate a stream by repeatedly executing a monadic action forever.
847--
848-- @
849-- drain $ serially $ S.take 10 $ S.repeatM $ (threadDelay 1000000 >> print 1)
850-- drain $ asyncly $ S.take 10 $ S.repeatM $ (threadDelay 1000000 >> print 1)
851-- @
852--
853-- /Concurrent, infinite (do not use with 'parallely')/
854--
855-- @since 0.2.0
856{-# INLINE_EARLY repeatM #-}
857repeatM :: (IsStream t, MonadAsync m) => m a -> t m a
858repeatM = K.repeatM
860{-# RULES "repeatM serial" repeatM = repeatMSerial #-}
861{-# INLINE repeatMSerial #-}
862repeatMSerial :: MonadAsync m => m a -> SerialT m a
863repeatMSerial = fromStreamS . S.repeatM
865-- |
866-- @
867-- iterate f x = x \`cons` iterate f x
868-- @
869--
870-- Generate an infinite stream with @x@ as the first element and each
871-- successive element derived by applying the function @f@ on the previous
872-- element.
873--
874-- @
875-- > S.toList $ S.take 5 $ S.iterate (+1) 1
876-- [1,2,3,4,5]
877-- @
878--
879-- @since 0.1.2
880{-# INLINE_NORMAL iterate #-}
881iterate :: (IsStream t, Monad m) => (a -> a) -> a -> t m a
882iterate step = fromStreamS . S.iterate step
884-- |
885-- @
886-- iterateM f m = m >>= \a -> return a \`consM` iterateM f (f a)
887-- @
888--
889-- Generate an infinite stream with the first element generated by the action
890-- @m@ and each successive element derived by applying the monadic function
891-- @f@ on the previous element.
892--
893-- When run concurrently, the next iteration can run concurrently with the
894-- processing of the previous iteration. Note that more than one iteration
895-- cannot run concurrently as the next iteration depends on the output of the
896-- previous iteration.
897--
898-- @
899-- drain $ serially $ S.take 10 $ S.iterateM
900-- (\\x -> threadDelay 1000000 >> print x >> return (x + 1)) (return 0)
901--
902-- drain $ asyncly $ S.take 10 $ S.iterateM
903-- (\\x -> threadDelay 1000000 >> print x >> return (x + 1)) (return 0)
904-- @
905--
906-- /Concurrent/
907--
908-- /Since: 0.7.0 (signature change)/
909--
910-- /Since: 0.1.2/
911{-# INLINE_EARLY iterateM #-}
912iterateM :: (IsStream t, MonadAsync m) => (a -> m a) -> m a -> t m a
913iterateM = K.iterateM
915{-# RULES "iterateM serial" iterateM = iterateMSerial #-}
916{-# INLINE iterateMSerial #-}
917iterateMSerial :: MonadAsync m => (a -> m a) -> m a -> SerialT m a
918iterateMSerial step = fromStreamS . S.iterateM step
920------------------------------------------------------------------------------
921-- Conversions
922------------------------------------------------------------------------------
924-- |
925-- @
926-- fromListM = 'Prelude.foldr' 'K.consM' 'K.nil'
927-- @
928--
929-- Construct a stream from a list of monadic actions. This is more efficient
930-- than 'fromFoldableM' for serial streams.
931--
932-- @since 0.4.0
933{-# INLINE_EARLY fromListM #-}
934fromListM :: (MonadAsync m, IsStream t) => [m a] -> t m a
935fromListM = fromStreamD . D.fromListM
936{-# RULES "fromListM fallback to StreamK" [1]
937 forall a. D.toStreamK (D.fromListM a) = fromFoldableM a #-}
939-- |
940-- @
941-- fromFoldableM = 'Prelude.foldr' 'consM' 'K.nil'
942-- @
943--
944-- Construct a stream from a 'Foldable' containing monadic actions.
945--
946-- @
947-- drain $ serially $ S.fromFoldableM $ replicateM 10 (threadDelay 1000000 >> print 1)
948-- drain $ asyncly $ S.fromFoldableM $ replicateM 10 (threadDelay 1000000 >> print 1)
949-- @
950--
951-- /Concurrent (do not use with 'parallely' on infinite containers)/
952--
953-- @since 0.3.0
954{-# INLINE fromFoldableM #-}
955fromFoldableM :: (IsStream t, MonadAsync m, Foldable f) => f (m a) -> t m a
956fromFoldableM = Prelude.foldr consM K.nil
958-- | Same as 'fromFoldable'.
959--
960-- @since 0.1.0
961{-# DEPRECATED each "Please use fromFoldable instead." #-}
962{-# INLINE each #-}
963each :: (IsStream t, Foldable f) => f a -> t m a
964each = K.fromFoldable
966-- | Read lines from an IO Handle into a stream of Strings.
967--
968-- @since 0.1.0
969{-# DEPRECATED fromHandle
970 "Please use Streamly.FileSystem.Handle module (see the changelog)" #-}
971fromHandle :: (IsStream t, MonadIO m) => IO.Handle -> t m String
972fromHandle h = go
973 where
974 go = K.mkStream $ \_ yld _ stp -> do
975 eof <- liftIO $ IO.hIsEOF h
976 if eof
977 then stp
978 else do
979 str <- liftIO $ IO.hGetLine h
980 yld str go
982-- | Construct a stream by reading a 'Prim' 'IORef' repeatedly.
983--
984-- /Internal/
985--
986{-# INLINE fromPrimIORef #-}
987fromPrimIORef :: (IsStream t, MonadIO m, Prim a) => IORef a -> t m a
988fromPrimIORef = fromStreamD . D.fromPrimIORef
990-- | Takes a callback setter function and provides it with a callback. The
991-- callback when invoked adds a value at the tail of the stream. Returns a
992-- stream of values generated by the callback.
993--
994-- /Internal/
995--
996{-# INLINE fromCallback #-}
997fromCallback :: MonadAsync m => ((a -> m ()) -> m ()) -> SerialT m a
998fromCallback setCallback = concatM $ do
999 (callback, stream) <- D.newCallbackStream
1000 setCallback callback
1001 return stream
1003------------------------------------------------------------------------------
1004-- Time related
1005------------------------------------------------------------------------------
1007-- | @timesWith g@ returns a stream of time value tuples. The first component
1008-- of the tuple is an absolute time reference (epoch) denoting the start of the
1009-- stream and the second component is a time relative to the reference.
1011-- The argument @g@ specifies the granularity of the relative time in seconds.
1012-- A lower granularity clock gives higher precision but is more expensive in
1013-- terms of CPU usage. Any granularity lower than 1 ms is treated as 1 ms.
1015-- @
1016-- >>> S.mapM_ (\x -> print x >> threadDelay 1000000) $ S.timesWith 0.01
1017-- > (AbsTime (TimeSpec {sec = 2496295, nsec = 536223000}),RelTime64 (NanoSecond64 0))
1018-- > (AbsTime (TimeSpec {sec = 2496295, nsec = 536223000}),RelTime64 (NanoSecond64 1002028000))
1019-- > (AbsTime (TimeSpec {sec = 2496295, nsec = 536223000}),RelTime64 (NanoSecond64 1996656000))
1020-- @
1022-- Note: This API is not safe on 32-bit machines.
1024-- /Internal/
1026{-# INLINE timesWith #-}
1027timesWith :: (IsStream t, MonadAsync m) => Double -> t m (AbsTime, RelTime64)
1028timesWith g = fromStreamD $ D.times g
1030-- | @times@ returns a stream of time value tuples with clock of 10 ms
1031-- granularity. The first component of the tuple is an absolute time reference
1032-- (epoch) denoting the start of the stream and the second component is a time
1033-- relative to the reference.
1035-- @
1036-- >>> S.mapM_ (\x -> print x >> threadDelay 1000000) $ S.times
1037-- > (AbsTime (TimeSpec {sec = 2496295, nsec = 536223000}),RelTime64 (NanoSecond64 0))
1038-- > (AbsTime (TimeSpec {sec = 2496295, nsec = 536223000}),RelTime64 (NanoSecond64 1002028000))
1039-- > (AbsTime (TimeSpec {sec = 2496295, nsec = 536223000}),RelTime64 (NanoSecond64 1996656000))
1040-- @
1042-- Note: This API is not safe on 32-bit machines.
1044-- /Internal/
1046{-# INLINE times #-}
1047times :: (IsStream t, MonadAsync m) => t m (AbsTime, RelTime64)
1048times = timesWith 0.01
1050-- | @absTimesWith g@ returns a stream of absolute timestamps using a clock of
1051-- granularity @g@ specified in seconds. A low granularity clock is more
1052-- expensive in terms of CPU usage. Any granularity lower than 1 ms is treated
1053-- as 1 ms.
1055-- @
1056-- >>> S.mapM_ print $ S.delayPre 1 $ S.absTimesWith 0.01
1057-- @
1059-- Note: This API is not safe on 32-bit machines.
1061-- /Internal/
1063{-# INLINE absTimesWith #-}
1064absTimesWith :: (IsStream t, MonadAsync m, Functor (t m))
1065 => Double -> t m AbsTime
1066absTimesWith = fmap (uncurry addToAbsTime64) . timesWith
1068-- | @absTimes@ returns a stream of absolute timestamps using a clock of 10 ms
1069-- granularity.
1071-- @
1072-- >>> S.mapM_ print $ S.delayPre 1 $ S.absTimes
1073-- @
1075-- Note: This API is not safe on 32-bit machines.
1077-- /Internal/
1079{-# INLINE absTimes #-}
1080absTimes :: (IsStream t, MonadAsync m, Functor (t m)) => t m AbsTime
1081absTimes = fmap (uncurry addToAbsTime64) times
1083{-# DEPRECATED currentTime "Please use absTimes instead" #-}
1084{-# INLINE currentTime #-}
1085currentTime :: (IsStream t, MonadAsync m, Functor (t m))
1086 => Double -> t m AbsTime
1087currentTime = absTimesWith
1089-- | @relTimesWith g@ returns a stream of relative time values starting from 0,
1090-- using a clock of granularity @g@ specified in seconds. A low granularity
1091-- clock is more expensive in terms of CPU usage. Any granularity lower than 1
1092-- ms is treated as 1 ms.
1094-- @
1095-- >>> S.mapM_ print $ S.delayPre 1 $ S.relTimesWith 0.01
1096-- > RelTime64 (NanoSecond64 0)
1097-- > RelTime64 (NanoSecond64 91139000)
1098-- > RelTime64 (NanoSecond64 204052000)
1099-- @
1101-- Note: This API is not safe on 32-bit machines.
1103-- /Internal/
1105{-# INLINE relTimesWith #-}
1106relTimesWith :: (IsStream t, MonadAsync m, Functor (t m))
1107 => Double -> t m RelTime64
1108relTimesWith = fmap snd . timesWith
1110-- | @relTimes@ returns a stream of relative time values starting from 0,
1111-- using a clock of granularity 10 ms.
1113-- @
1114-- >>> S.mapM_ print $ S.delayPre 1 $ S.relTimes
1115-- @
1117-- Note: This API is not safe on 32-bit machines.
1119-- /Internal/
1121{-# INLINE relTimes #-}
1122relTimes :: (IsStream t, MonadAsync m, Functor (t m)) => t m RelTime64
1123relTimes = fmap snd times
1125-- | @durations g@ returns a stream of relative time values measuring the time
1126-- elapsed since the immediate predecessor element of the stream was generated.
1127-- The first element of the stream is always 0. @durations@ uses a clock of
1128-- granularity @g@ specified in seconds. A low granularity clock is more
1129-- expensive in terms of CPU usage. The minimum granularity is 1 millisecond.
1130-- Durations lower than 1 ms will be 0.
1132-- Note: This API is not safe on 32-bit machines.
1134-- /Unimplemented/
1136{-# INLINE durations #-}
1137durations :: -- (IsStream t, MonadAsync m) =>
1138 Double -> t m RelTime64
1139durations = undefined
1141-- | Generate ticks at the specified rate. The rate is adaptive, the tick
1142-- generation speed can be increased or decreased at different times to achieve
1143-- the specified rate. The specific behavior for different styles of 'Rate'
1144-- specifications is documented under 'Rate'. The effective maximum rate
1145-- achieved by a stream is governed by the processor speed.
1147-- /Unimplemented/
1149{-# INLINE ticks #-}
1150ticks :: -- (IsStream t, MonadAsync m) =>
1151 Rate -> t m ()
1152ticks = undefined
1154-- | Generate a singleton event at or after the specified absolute time. Note
1155-- that this is different from a threadDelay, a threadDelay starts from the
1156-- time when the action is evaluated, whereas if we use AbsTime based timeout
1157-- it will immediately expire if the action is evaluated too late.
1159-- /Unimplemented/
1161{-# INLINE timeout #-}
1162timeout :: -- (IsStream t, MonadAsync m) =>
1163 AbsTime -> t m ()
1164timeout = undefined
1166------------------------------------------------------------------------------
1167-- Elimination by Folding
1168------------------------------------------------------------------------------
1170-- | Right associative/lazy pull fold. @foldrM build final stream@ constructs
1171-- an output structure using the step function @build@. @build@ is invoked with
1172-- the next input element and the remaining (lazy) tail of the output
1173-- structure. It builds a lazy output expression using the two. When the "tail
1174-- structure" in the output expression is evaluated it calls @build@ again thus
1175-- lazily consuming the input @stream@ until either the output expression built
1176-- by @build@ is free of the "tail" or the input is exhausted in which case
1177-- @final@ is used as the terminating case for the output structure. For more
1178-- details see the description in the previous section.
1180-- Example, determine if any element is 'odd' in a stream:
1182-- >>> S.foldrM (\x xs -> if odd x then return True else xs) (return False) $ S.fromList (2:4:5:undefined)
1183-- > True
1185-- /Since: 0.7.0 (signature changed)/
1187-- /Since: 0.2.0 (signature changed)/
1189-- /Since: 0.1.0/
1190{-# INLINE foldrM #-}
1191foldrM :: Monad m => (a -> m b -> m b) -> m b -> SerialT m a -> m b
1192foldrM = P.foldrM
1194-- | Right fold to a streaming monad.
1196-- > foldrS S.cons S.nil === id
1198-- 'foldrS' can be used to perform stateless stream to stream transformations
1199-- like map and filter in general. It can be coupled with a scan to perform
1200-- stateful transformations. However, note that the custom map and filter
1201-- routines can be much more efficient than this due to better stream fusion.
1203-- >>> S.toList $ S.foldrS S.cons S.nil $ S.fromList [1..5]
1204-- > [1,2,3,4,5]
1206-- Find if any element in the stream is 'True':
1208-- >>> 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)
1209-- > [True]
1211-- Map (+2) on odd elements and filter out the even elements:
1213-- >>> 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)
1214-- > [3,5,7]
1216-- 'foldrM' can also be represented in terms of 'foldrS', however, the former
1217-- is much more efficient:
1219-- > foldrM f z s = runIdentityT $ foldrS (\x xs -> lift $ f x (runIdentityT xs)) (lift z) s
1221-- /Internal/
1222{-# INLINE foldrS #-}
1223foldrS :: IsStream t => (a -> t m b -> t m b) -> t m b -> t m a -> t m b
1224foldrS = K.foldrS
1226-- | Right fold to a transformer monad. This is the most general right fold
1227-- function. 'foldrS' is a special case of 'foldrT', however 'foldrS'
1228-- implementation can be more efficient:
1230-- > foldrS = foldrT
1231-- > foldrM f z s = runIdentityT $ foldrT (\x xs -> lift $ f x (runIdentityT xs)) (lift z) s
1233-- 'foldrT' can be used to translate streamly streams to other transformer
1234-- monads e.g. to a different streaming type.
1236-- /Internal/
1237{-# INLINE foldrT #-}
1238foldrT :: (IsStream t, Monad m, Monad (s m), MonadTrans s)
1239 => (a -> s m b -> s m b) -> s m b -> t m a -> s m b
1240foldrT f z s = S.foldrT f z (toStreamS s)
1242-- | Right fold, lazy for lazy monads and pure streams, and strict for strict
1243-- monads.
1245-- Please avoid using this routine in strict monads like IO unless you need a
1246-- strict right fold. This is provided only for use in lazy monads (e.g.
1247-- Identity) or pure streams. Note that with this signature it is not possible
1248-- to implement a lazy foldr when the monad @m@ is strict. In that case it
1249-- would be strict in its accumulator and therefore would necessarily consume
1250-- all its input.
1252-- @since 0.1.0
1253{-# INLINE foldr #-}
1254foldr :: Monad m => (a -> b -> b) -> b -> SerialT m a -> m b
1255foldr = P.foldr
1257-- XXX This seems to be of limited use as it cannot be used to construct
1258-- recursive structures and for reduction foldl1' is better.
1260-- | Lazy right fold for non-empty streams, using first element as the starting
1261-- value. Returns 'Nothing' if the stream is empty.
1263-- @since 0.5.0
1264{-# INLINE foldr1 #-}
1265{-# DEPRECATED foldr1 "Use foldrM instead." #-}
1266foldr1 :: Monad m => (a -> a -> a) -> SerialT m a -> m (Maybe a)
1267foldr1 f m = S.foldr1 f (toStreamS m)
1269-- | Strict left fold with an extraction function. Like the standard strict
1270-- left fold, but applies a user supplied extraction function (the third
1271-- argument) to the folded value at the end. This is designed to work with the
1272-- @foldl@ library. The suffix @x@ is a mnemonic for extraction.
1274-- @since 0.2.0
1275{-# DEPRECATED foldx "Please use foldl' followed by fmap instead." #-}
1276{-# INLINE foldx #-}
1277foldx :: Monad m => (x -> a -> x) -> x -> (x -> b) -> SerialT m a -> m b
1278foldx = P.foldlx'
1280-- | Left associative/strict push fold. @foldl' reduce initial stream@ invokes
1281-- @reduce@ with the accumulator and the next input in the input stream, using
1282-- @initial@ as the initial value of the current value of the accumulator. When
1283-- the input is exhausted the current value of the accumulator is returned.
1284-- Make sure to use a strict data structure for accumulator to not build
1285-- unnecessary lazy expressions unless that's what you want. See the previous
1286-- section for more details.
1288-- @since 0.2.0
1289{-# INLINE foldl' #-}
1290foldl' :: Monad m => (b -> a -> b) -> b -> SerialT m a -> m b
1291foldl' = P.foldl'
1293-- | Strict left fold, for non-empty streams, using first element as the
1294-- starting value. Returns 'Nothing' if the stream is empty.
1296-- @since 0.5.0
1297{-# INLINE foldl1' #-}
1298foldl1' :: Monad m => (a -> a -> a) -> SerialT m a -> m (Maybe a)
1299foldl1' step m = do
1300 r <- uncons m
1301 case r of
1302 Nothing -> return Nothing
1303 Just (h, t) -> do
1304 res <- foldl' step h t
1305 return $ Just res
1307-- | Like 'foldx', but with a monadic step function.
1309-- @since 0.2.0
1310{-# DEPRECATED foldxM "Please use foldlM' followed by fmap instead." #-}
1311{-# INLINE foldxM #-}
1312foldxM :: Monad m => (x -> a -> m x) -> m x -> (x -> m b) -> SerialT m a -> m b
1313foldxM = P.foldlMx'
1315-- | Like 'foldl'' but with a monadic step function.
1317-- @since 0.2.0
1318{-# INLINE foldlM' #-}
1319foldlM' :: Monad m => (b -> a -> m b) -> m b -> SerialT m a -> m b
1320foldlM' step begin m = S.foldlM' step begin $ toStreamS m
1322------------------------------------------------------------------------------
1323-- Running a Fold
1324------------------------------------------------------------------------------
1326-- | Fold a stream using the supplied left fold.
1328-- >>> S.fold FL.sum (S.enumerateFromTo 1 100)
1329-- 5050
1331-- @since 0.7.0
1332{-# INLINE fold #-}
1333fold :: Monad m => Fold m a b -> SerialT m a -> m b
1334fold = P.runFold
1336------------------------------------------------------------------------------
1337-- Running a sink
1338------------------------------------------------------------------------------
1341-- | Drain a stream to a 'Sink'.
1342{-# INLINE runSink #-}
1343runSink :: Monad m => Sink m a -> SerialT m a -> m ()
1344runSink = fold . toFold
1347------------------------------------------------------------------------------
1348-- Running a Parser
1349------------------------------------------------------------------------------
1351-- | Parse a stream using the supplied 'Parser'.
1353-- /Internal/
1355{-# INLINE_NORMAL parseD #-}
1356parseD :: MonadThrow m => PRD.Parser m a b -> SerialT m a -> m b
1357parseD (PRD.Parser step initial extract) = P.parselMx' step initial extract
1359{-# INLINE parseK #-}
1360parseK :: MonadThrow m => PRK.Parser m a b -> SerialT m a -> m b
1361parseK = parse
1363-- | Parse a stream using the supplied 'Parser'.
1365-- /Internal/
1367{-# INLINE [3] parse #-}
1368parse :: MonadThrow m => Parser m a b -> SerialT m a -> m b
1369parse = parseD . PRK.fromParserK
1371------------------------------------------------------------------------------
1372-- Specialized folds
1373------------------------------------------------------------------------------
1375-- |
1376-- > drain = mapM_ (\_ -> return ())
1378-- Run a stream, discarding the results. By default it interprets the stream
1379-- as 'SerialT', to run other types of streams use the type adapting
1380-- combinators for example @drain . 'asyncly'@.
1382-- @since 0.7.0
1383{-# INLINE drain #-}
1384drain :: Monad m => SerialT m a -> m ()
1385drain = P.drain
1387-- | Run a stream, discarding the results. By default it interprets the stream
1388-- as 'SerialT', to run other types of streams use the type adapting
1389-- combinators for example @runStream . 'asyncly'@.
1391-- @since 0.2.0
1392{-# DEPRECATED runStream "Please use \"drain\" instead" #-}
1393{-# INLINE runStream #-}
1394runStream :: Monad m => SerialT m a -> m ()
1395runStream = drain
1397-- |
1398-- > drainN n = drain . take n
1400-- Run maximum up to @n@ iterations of a stream.
1402-- @since 0.7.0
1403{-# INLINE drainN #-}
1404drainN :: Monad m => Int -> SerialT m a -> m ()
1405drainN n = drain . take n
1407-- |
1408-- > runN n = runStream . take n
1410-- Run maximum up to @n@ iterations of a stream.
1412-- @since 0.6.0
1413{-# DEPRECATED runN "Please use \"drainN\" instead" #-}
1414{-# INLINE runN #-}
1415runN :: Monad m => Int -> SerialT m a -> m ()
1416runN = drainN
1418-- |
1419-- > drainWhile p = drain . takeWhile p
1421-- Run a stream as long as the predicate holds true.
1423-- @since 0.7.0
1424{-# INLINE drainWhile #-}
1425drainWhile :: Monad m => (a -> Bool) -> SerialT m a -> m ()
1426drainWhile p = drain . takeWhile p
1428-- |
1429-- > runWhile p = runStream . takeWhile p
1431-- Run a stream as long as the predicate holds true.
1433-- @since 0.6.0
1434{-# DEPRECATED runWhile "Please use \"drainWhile\" instead" #-}
1435{-# INLINE runWhile #-}
1436runWhile :: Monad m => (a -> Bool) -> SerialT m a -> m ()
1437runWhile = drainWhile
1439-- | Determine whether the stream is empty.
1441-- @since 0.1.1
1442{-# INLINE null #-}
1443null :: Monad m => SerialT m a -> m Bool
1444null = S.null . toStreamS
1446-- | Extract the first element of the stream, if any.
1448-- > head = (!! 0)
1450-- @since 0.1.0
1451{-# INLINE head #-}
1452head :: Monad m => SerialT m a -> m (Maybe a)
1453head = S.head . toStreamS
1455-- | Extract the first element of the stream, if any, otherwise use the
1456-- supplied default value. It can help avoid one branch in high performance
1457-- code.
1459-- /Internal/
1460{-# INLINE headElse #-}
1461headElse :: Monad m => a -> SerialT m a -> m a
1462headElse x = D.headElse x . toStreamD
1464-- |
1465-- > tail = fmap (fmap snd) . uncons
1467-- Extract all but the first element of the stream, if any.
1469-- @since 0.1.1
1470{-# INLINE tail #-}
1471tail :: (IsStream t, Monad m) => SerialT m a -> m (Maybe (t m a))
1472tail m = K.tail (K.adapt m)
1474-- | Extract all but the last element of the stream, if any.
1476-- @since 0.5.0
1477{-# INLINE init #-}
1478init :: (IsStream t, Monad m) => SerialT m a -> m (Maybe (t m a))
1479init m = K.init (K.adapt m)
1481-- | Extract the last element of the stream, if any.
1483-- > last xs = xs !! (length xs - 1)
1485-- @since 0.1.1
1486{-# INLINE last #-}
1487last :: Monad m => SerialT m a -> m (Maybe a)
1488last m = S.last $ toStreamS m
1490-- | Determine whether an element is present in the stream.
1492-- @since 0.1.0
1493{-# INLINE elem #-}
1494elem :: (Monad m, Eq a) => a -> SerialT m a -> m Bool
1495elem e m = S.elem e (toStreamS m)
1497-- | Determine whether an element is not present in the stream.
1499-- @since 0.1.0
1500{-# INLINE notElem #-}
1501notElem :: (Monad m, Eq a) => a -> SerialT m a -> m Bool
1502notElem e m = S.notElem e (toStreamS m)
1504-- | Determine the length of the stream.
1506-- @since 0.1.0
1507{-# INLINE length #-}
1508length :: Monad m => SerialT m a -> m Int
1509length = foldl' (\n _ -> n + 1) 0
1511-- | Determine whether all elements of a stream satisfy a predicate.
1513-- @since 0.1.0
1514{-# INLINE all #-}
1515all :: Monad m => (a -> Bool) -> SerialT m a -> m Bool
1516all p m = S.all p (toStreamS m)
1518-- | Determine whether any of the elements of a stream satisfy a predicate.
1520-- @since 0.1.0
1521{-# INLINE any #-}
1522any :: Monad m => (a -> Bool) -> SerialT m a -> m Bool
1523any p m = S.any p (toStreamS m)
1525-- | Determines if all elements of a boolean stream are True.
1527-- @since 0.5.0
1528{-# INLINE and #-}
1529and :: Monad m => SerialT m Bool -> m Bool
1530and = all (==True)
1532-- | Determines whether at least one element of a boolean stream is True.
1534-- @since 0.5.0
1535{-# INLINE or #-}
1536or :: Monad m => SerialT m Bool -> m Bool
1537or = any (==True)
1539-- | Determine the sum of all elements of a stream of numbers. Returns @0@ when
1540-- the stream is empty. Note that this is not numerically stable for floating
1541-- point numbers.
1543-- @since 0.1.0
1544{-# INLINE sum #-}
1545sum :: (Monad m, Num a) => SerialT m a -> m a
1546sum = foldl' (+) 0
1548-- | Determine the product of all elements of a stream of numbers. Returns @1@
1549-- when the stream is empty.
1551-- @since 0.1.1
1552{-# INLINE product #-}
1553product :: (Monad m, Num a) => SerialT m a -> m a
1554product = foldl' (*) 1
1556-- | Fold a stream of monoid elements by appending them.
1558-- /Internal/
1559{-# INLINE mconcat #-}
1560mconcat :: (Monad m, Monoid a) => SerialT m a -> m a
1561mconcat = foldr mappend mempty
1563-- |
1564-- @
1565-- minimum = 'minimumBy' compare
1566-- @
1568-- Determine the minimum element in a stream.
1570-- @since 0.1.0
1571{-# INLINE minimum #-}
1572minimum :: (Monad m, Ord a) => SerialT m a -> m (Maybe a)
1573minimum m = S.minimum (toStreamS m)
1575-- | Determine the minimum element in a stream using the supplied comparison
1576-- function.
1578-- @since 0.6.0
1579{-# INLINE minimumBy #-}
1580minimumBy :: Monad m => (a -> a -> Ordering) -> SerialT m a -> m (Maybe a)
1581minimumBy cmp m = S.minimumBy cmp (toStreamS m)
1583-- |
1584-- @
1585-- maximum = 'maximumBy' compare
1586-- @
1588-- Determine the maximum element in a stream.
1590-- @since 0.1.0
1591{-# INLINE maximum #-}
1592maximum :: (Monad m, Ord a) => SerialT m a -> m (Maybe a)
1593maximum = P.maximum
1595-- | Determine the maximum element in a stream using the supplied comparison
1596-- function.
1598-- @since 0.6.0
1599{-# INLINE maximumBy #-}
1600maximumBy :: Monad m => (a -> a -> Ordering) -> SerialT m a -> m (Maybe a)
1601maximumBy cmp m = S.maximumBy cmp (toStreamS m)
1603-- | Lookup the element at the given index.
1605-- @since 0.6.0
1606{-# INLINE (!!) #-}
1607(!!) :: Monad m => SerialT m a -> Int -> m (Maybe a)
1608m !! i = toStreamS m S.!! i
1610-- | In a stream of (key-value) pairs @(a, b)@, return the value @b@ of the
1611-- first pair where the key equals the given value @a@.
1613-- > lookup = snd <$> find ((==) . fst)
1615-- @since 0.5.0
1616{-# INLINE lookup #-}
1617lookup :: (Monad m, Eq a) => a -> SerialT m (a, b) -> m (Maybe b)
1618lookup a m = S.lookup a (toStreamS m)
1620-- | Like 'findM' but with a non-monadic predicate.
1622-- > find p = findM (return . p)
1624-- @since 0.5.0
1625{-# INLINE find #-}
1626find :: Monad m => (a -> Bool) -> SerialT m a -> m (Maybe a)
1627find p m = S.find p (toStreamS m)
1629-- | Returns the first element that satisfies the given predicate.
1631-- @since 0.6.0
1632{-# INLINE findM #-}
1633findM :: Monad m => (a -> m Bool) -> SerialT m a -> m (Maybe a)
1634findM p m = S.findM p (toStreamS m)
1636-- | Find all the indices where the element in the stream satisfies the given
1637-- predicate.
1639-- @since 0.5.0
1640{-# INLINE findIndices #-}
1641findIndices :: (IsStream t, Monad m) => (a -> Bool) -> t m a -> t m Int
1642findIndices p m = fromStreamS $ S.findIndices p (toStreamS m)
1644-- | Returns the first index that satisfies the given predicate.
1646-- @since 0.5.0
1647{-# INLINE findIndex #-}
1648findIndex :: Monad m => (a -> Bool) -> SerialT m a -> m (Maybe Int)
1649findIndex p = head . findIndices p
1651-- | Find all the indices where the value of the element in the stream is equal
1652-- to the given value.
1654-- @since 0.5.0
1655{-# INLINE elemIndices #-}
1656elemIndices :: (IsStream t, Eq a, Monad m) => a -> t m a -> t m Int
1657elemIndices a = findIndices (==a)
1659-- | Returns the first index where a given value is found in the stream.
1661-- > elemIndex a = findIndex (== a)
1663-- @since 0.5.0
1664{-# INLINE elemIndex #-}
1665elemIndex :: (Monad m, Eq a) => a -> SerialT m a -> m (Maybe Int)
1666elemIndex a = findIndex (== a)
1668------------------------------------------------------------------------------
1669-- Substreams
1670------------------------------------------------------------------------------
1672-- | Returns 'True' if the first stream is the same as or a prefix of the
1673-- second. A stream is a prefix of itself.
1675-- @
1676-- > S.isPrefixOf (S.fromList "hello") (S.fromList "hello" :: SerialT IO Char)
1677-- True
1678-- @
1680-- @since 0.6.0
1681{-# INLINE isPrefixOf #-}
1682isPrefixOf :: (Eq a, IsStream t, Monad m) => t m a -> t m a -> m Bool
1683isPrefixOf m1 m2 = D.isPrefixOf (toStreamD m1) (toStreamD m2)
1685-- Note: isPrefixOf uses the prefix stream only once. In contrast, isSuffixOf
1686-- may use the suffix stream many times. To run in optimal memory we do not
1687-- want to buffer the suffix stream in memory therefore we need an ability to
1688-- clone (or consume it multiple times) the suffix stream without any side
1689-- effects so that multiple potential suffix matches can proceed in parallel
1690-- without buffering the suffix stream. For example, we may create the suffix
1691-- stream from a file handle, however, if we evaluate the stream multiple
1692-- times, once for each match, we will need a different file handle each time
1693-- which may exhaust the file descriptors. Instead, we want to share the same
1694-- underlying file descriptor, use pread on it to generate the stream and clone
1695-- the stream for each match. Therefore the suffix stream should be built in
1696-- such a way that it can be consumed multiple times without any problems.
1698-- XXX Can be implemented with better space/time complexity.
1699-- Space: @O(n)@ worst case where @n@ is the length of the suffix.
1701-- | Returns 'True' if the first stream is a suffix of the second. A stream is
1702-- considered a suffix of itself.
1704-- @
1705-- > S.isSuffixOf (S.fromList "hello") (S.fromList "hello" :: SerialT IO Char)
1706-- True
1707-- @
1709-- Space: @O(n)@, buffers entire input stream and the suffix.
1711-- /Internal/
1713-- /Suboptimal/ - Help wanted.
1715{-# INLINE isSuffixOf #-}
1716isSuffixOf :: (Monad m, Eq a) => SerialT m a -> SerialT m a -> m Bool
1717isSuffixOf suffix stream = reverse suffix `isPrefixOf` reverse stream
1719-- | Returns 'True' if the first stream is an infix of the second. A stream is
1720-- considered an infix of itself.
1722-- @
1723-- > S.isInfixOf (S.fromList "hello") (S.fromList "hello" :: SerialT IO Char)
1724-- True
1725-- @
1727-- Space: @O(n)@ worst case where @n@ is the length of the infix.
1729-- /Internal/
1731-- /Requires 'Storable' constraint/ - Help wanted.
1733{-# INLINE isInfixOf #-}
1734isInfixOf :: (MonadIO m, Eq a, Enum a, Storable a)
1735 => SerialT m a -> SerialT m a -> m Bool
1736isInfixOf infx stream = do
1737 arr <- fold A.write infx
1738 -- XXX can use breakOnSeq instead (when available)
1739 r <- null $ drop 1 $ splitOnSeq arr FL.drain stream
1740 return (not r)
1742-- | Returns 'True' if all the elements of the first stream occur, in order, in
1743-- the second stream. The elements do not have to occur consecutively. A stream
1744-- is a subsequence of itself.
1746-- @
1747-- > S.isSubsequenceOf (S.fromList "hlo") (S.fromList "hello" :: SerialT IO Char)
1748-- True
1749-- @
1751-- @since 0.6.0
1752{-# INLINE isSubsequenceOf #-}
1753isSubsequenceOf :: (Eq a, IsStream t, Monad m) => t m a -> t m a -> m Bool
1754isSubsequenceOf m1 m2 = D.isSubsequenceOf (toStreamD m1) (toStreamD m2)
1756-- | Strip prefix if present and tell whether it was stripped or not. Returns
1757-- 'Nothing' if the stream does not start with the given prefix, stripped
1758-- stream otherwise. Returns @Just nil@ when the prefix is the same as the
1759-- stream.
1761-- Space: @O(1)@
1763-- @since 0.6.0
1764{-# INLINE stripPrefix #-}
1765stripPrefix
1766 :: (Eq a, IsStream t, Monad m)
1767 => t m a -> t m a -> m (Maybe (t m a))
1768stripPrefix m1 m2 = fmap fromStreamD <$>
1769 D.stripPrefix (toStreamD m1) (toStreamD m2)
1771-- Note: If we want to return a Maybe value to know whether the
1772-- suffix/infix was present or not along with the stripped stream then
1773-- we need to buffer the whole input stream.
1775-- | Drops the given suffix from a stream. Returns 'Nothing' if the stream does
1776-- not end with the given suffix. Returns @Just nil@ when the suffix is the
1777-- same as the stream.
1779-- It may be more efficient to convert the stream to an Array and use
1780-- stripSuffix on that especially if the elements have a Storable or Prim
1781-- instance.
1783-- Space: @O(n)@, buffers the entire input stream as well as the suffix
1785-- /Internal/
1786{-# INLINE stripSuffix #-}
1787stripSuffix
1788 :: (Monad m, Eq a)
1789 => SerialT m a -> SerialT m a -> m (Maybe (SerialT m a))
1790stripSuffix m1 m2 = fmap reverse <$> stripPrefix (reverse m1) (reverse m2)
1792-- | Drop prefix from the input stream if present.
1794-- Space: @O(1)@
1796-- /Unimplemented/ - Help wanted.
1797{-# INLINE dropPrefix #-}
1798dropPrefix ::
1799 -- (Eq a, IsStream t, Monad m) =>
1800 t m a -> t m a -> t m a
1801dropPrefix = error "Not implemented yet!"
1803-- | Drop all matching infix from the input stream if present. Infix stream
1804-- may be consumed multiple times.
1806-- Space: @O(n)@ where n is the length of the infix.
1808-- /Unimplemented/ - Help wanted.
1809{-# INLINE dropInfix #-}
1810dropInfix ::
1811 -- (Eq a, IsStream t, Monad m) =>
1812 t m a -> t m a -> t m a
1813dropInfix = error "Not implemented yet!"
1815-- | Drop suffix from the input stream if present. Suffix stream may be
1816-- consumed multiple times.
1818-- Space: @O(n)@ where n is the length of the suffix.
1820-- /Unimplemented/ - Help wanted.
1821{-# INLINE dropSuffix #-}
1822dropSuffix ::
1823 -- (Eq a, IsStream t, Monad m) =>
1824 t m a -> t m a -> t m a
1825dropSuffix = error "Not implemented yet!"
1827------------------------------------------------------------------------------
1828-- Map and Fold
1829------------------------------------------------------------------------------
1831-- XXX this can utilize parallel mapping if we implement it as drain . mapM
1832-- |
1833-- > mapM_ = drain . mapM
1835-- Apply a monadic action to each element of the stream and discard the output
1836-- of the action. This is not really a pure transformation operation but a
1837-- transformation followed by fold.
1839-- @since 0.1.0
1840{-# INLINE mapM_ #-}
1841mapM_ :: Monad m => (a -> m b) -> SerialT m a -> m ()
1842mapM_ f m = S.mapM_ f $ toStreamS m
1844------------------------------------------------------------------------------
1845-- Conversions
1846------------------------------------------------------------------------------
1848-- |
1849-- @
1850-- toList = S.foldr (:) []
1851-- @
1853-- Convert a stream into a list in the underlying monad. The list can be
1854-- consumed lazily in a lazy monad (e.g. 'Identity'). In a strict monad (e.g.
1855-- IO) the whole list is generated and buffered before it can be consumed.
1857-- /Warning!/ working on large lists accumulated as buffers in memory could be
1858-- very inefficient, consider using "Streamly.Array" instead.
1860-- @since 0.1.0
1861{-# INLINE toList #-}
1862toList :: Monad m => SerialT m a -> m [a]
1863toList = P.toList
1865-- |
1866-- @
1867-- toListRev = S.foldl' (flip (:)) []
1868-- @
1870-- Convert a stream into a list in reverse order in the underlying monad.
1872-- /Warning!/ working on large lists accumulated as buffers in memory could be
1873-- very inefficient, consider using "Streamly.Array" instead.
1875-- /Internal/
1876{-# INLINE toListRev #-}
1877toListRev :: Monad m => SerialT m a -> m [a]
1878toListRev = D.toListRev . toStreamD
1880-- |
1881-- @
1882-- toHandle h = S.mapM_ $ hPutStrLn h
1883-- @
1885-- Write a stream of Strings to an IO Handle.
1887-- @since 0.1.0
1888{-# DEPRECATED toHandle
1889 "Please use Streamly.FileSystem.Handle module (see the changelog)" #-}
1890toHandle :: MonadIO m => IO.Handle -> SerialT m String -> m ()
1891toHandle h = go
1892 where
1893 go m1 =
1894 let stop = return ()
1895 single a = liftIO (IO.hPutStrLn h a)
1896 yieldk a r = liftIO (IO.hPutStrLn h a) >> go r
1897 in K.foldStream defState yieldk single stop m1
1899-- XXX rename these to write/writeRev to make the naming consistent with folds
1900-- in other modules.
1902-- | A fold that buffers its input to a pure stream.
1904-- /Warning!/ working on large streams accumulated as buffers in memory could
1905-- be very inefficient, consider using "Streamly.Array" instead.
1907-- /Internal/
1908{-# INLINE toStream #-}
1909toStream :: Monad m => Fold m a (SerialT Identity a)
1910toStream = Fold (\f x -> return $ f . (x `K.cons`))
1911 (return id)
1912 (return . ($ K.nil))
1914-- This is more efficient than 'toStream'. toStream is exactly the same as
1915-- reversing the stream after toStreamRev.
1917-- | Buffers the input stream to a pure stream in the reverse order of the
1918-- input.
1920-- /Warning!/ working on large streams accumulated as buffers in memory could
1921-- be very inefficient, consider using "Streamly.Array" instead.
1923-- /Internal/
1925-- xn : ... : x2 : x1 : []
1926{-# INLINABLE toStreamRev #-}
1927toStreamRev :: Monad m => Fold m a (SerialT Identity a)
1928toStreamRev = Fold (\xs x -> return $ x `K.cons` xs) (return K.nil) return
1930-- | Convert a stream to a pure stream.
1932-- @
1933-- toPure = foldr cons nil
1934-- @
1936-- /Internal/
1938{-# INLINE toPure #-}
1939toPure :: Monad m => SerialT m a -> m (SerialT Identity a)
1940toPure = foldr K.cons K.nil
1942-- | Convert a stream to a pure stream in reverse order.
1944-- @
1945-- toPureRev = foldl' (flip cons) nil
1946-- @
1948-- /Internal/
1950{-# INLINE toPureRev #-}
1951toPureRev :: Monad m => SerialT m a -> m (SerialT Identity a)
1952toPureRev = foldl' (flip K.cons) K.nil
1954------------------------------------------------------------------------------
1955-- Concurrent Application
1956------------------------------------------------------------------------------
1958infixr 0 |$
1959infixr 0 |$.
1961infixl 1 |&
1962infixl 1 |&.
1964-- | Parallel transform application operator; applies a stream transformation
1965-- function @t m a -> t m b@ to a stream @t m a@ concurrently; the input stream
1966-- is evaluated asynchronously in an independent thread yielding elements to a
1967-- buffer and the transformation function runs in another thread consuming the
1968-- input from the buffer. '|$' is just like regular function application
1969-- operator '$' except that it is concurrent.
1971-- If you read the signature as @(t m a -> t m b) -> (t m a -> t m b)@ you can
1972-- look at it as a transformation that converts a transform function to a
1973-- buffered concurrent transform function.
1975-- The following code prints a value every second even though each stage adds a
1976-- 1 second delay.
1979-- @
1980-- drain $
1981-- S.mapM (\\x -> threadDelay 1000000 >> print x)
1982-- |$ S.repeatM (threadDelay 1000000 >> return 1)
1983-- @
1985-- /Concurrent/
1987-- @since 0.3.0
1988{-# INLINE (|$) #-}
1989(|$) :: (IsStream t, MonadAsync m) => (t m a -> t m b) -> (t m a -> t m b)
1990-- (|$) f = f . Async.mkAsync
1991(|$) f = f . D.mkParallel
1993-- | Same as '|$'.
1995-- /Internal/
1997{-# INLINE applyAsync #-}
1998applyAsync :: (IsStream t, MonadAsync m)
1999 => (t m a -> t m b) -> (t m a -> t m b)
2000applyAsync = (|$)
2002-- | Parallel reverse function application operator for streams; just like the
2003-- regular reverse function application operator '&' except that it is
2004-- concurrent.
2006-- @
2007-- drain $
2008-- S.repeatM (threadDelay 1000000 >> return 1)
2009-- |& S.mapM (\\x -> threadDelay 1000000 >> print x)
2010-- @
2012-- /Concurrent/
2014-- @since 0.3.0
2015{-# INLINE (|&) #-}
2016(|&) :: (IsStream t, MonadAsync m) => t m a -> (t m a -> t m b) -> t m b
2017x |& f = f |$ x
2019-- | Parallel fold application operator; applies a fold function @t m a -> m b@
2020-- to a stream @t m a@ concurrently; The the input stream is evaluated
2021-- asynchronously in an independent thread yielding elements to a buffer and
2022-- the folding action runs in another thread consuming the input from the
2023-- buffer.
2025-- If you read the signature as @(t m a -> m b) -> (t m a -> m b)@ you can look
2026-- at it as a transformation that converts a fold function to a buffered
2027-- concurrent fold function.
2029-- The @.@ at the end of the operator is a mnemonic for termination of the
2030-- stream.
2032-- @
2033-- S.foldlM' (\\_ a -> threadDelay 1000000 >> print a) ()
2034-- |$. S.repeatM (threadDelay 1000000 >> return 1)
2035-- @
2037-- /Concurrent/
2039-- @since 0.3.0
2040{-# INLINE (|$.) #-}
2041(|$.) :: (IsStream t, MonadAsync m) => (t m a -> m b) -> (t m a -> m b)
2042-- (|$.) f = f . Async.mkAsync
2043(|$.) f = f . D.mkParallel
2045-- | Same as '|$.'.
2047-- /Internal/
2049{-# INLINE foldAsync #-}
2050foldAsync :: (IsStream t, MonadAsync m) => (t m a -> m b) -> (t m a -> m b)
2051foldAsync = (|$.)
2053-- | Parallel reverse function application operator for applying a run or fold
2054-- functions to a stream. Just like '|$.' except that the operands are reversed.
2056-- @
2057-- S.repeatM (threadDelay 1000000 >> return 1)
2058-- |&. S.foldlM' (\\_ a -> threadDelay 1000000 >> print a) ()
2059-- @
2061-- /Concurrent/
2063-- @since 0.3.0
2064{-# INLINE (|&.) #-}
2065(|&.) :: (IsStream t, MonadAsync m) => t m a -> (t m a -> m b) -> m b
2066x |&. f = f |$. x
2068------------------------------------------------------------------------------
2069-- General Transformation
2070------------------------------------------------------------------------------
2072-- | Use a 'Pipe' to transform a stream.
2074-- /Internal/
2076{-# INLINE transform #-}
2077transform :: (IsStream t, Monad m) => Pipe m a b -> t m a -> t m b
2078transform pipe xs = fromStreamD $ D.transform pipe (toStreamD xs)
2080------------------------------------------------------------------------------
2081-- Transformation by Folding (Scans)
2082------------------------------------------------------------------------------
2084-- XXX It may be useful to have a version of scan where we can keep the
2085-- accumulator independent of the value emitted. So that we do not necessarily
2086-- have to keep a value in the accumulator which we are not using. We can pass
2087-- an extraction function that will take the accumulator and the current value
2088-- of the element and emit the next value in the stream. That will also make it
2089-- possible to modify the accumulator after using it. In fact, the step function
2090-- can return new accumulator and the value to be emitted. The signature would
2091-- be more like mapAccumL. Or we can change the signature of scanx to
2092-- accommodate this.
2094-- | Strict left scan with an extraction function. Like 'scanl'', but applies a
2095-- user supplied extraction function (the third argument) at each step. This is
2096-- designed to work with the @foldl@ library. The suffix @x@ is a mnemonic for
2097-- extraction.
2099-- /Since: 0.7.0 (Monad m constraint)/
2101-- /Since 0.2.0/
2102{-# DEPRECATED scanx "Please use scanl followed by map instead." #-}
2103{-# INLINE scanx #-}
2104scanx :: (IsStream t, Monad m) => (x -> a -> x) -> x -> (x -> b) -> t m a -> t m b
2105scanx = P.scanlx'
2107-- XXX this needs to be concurrent
2108-- XXX because of the use of D.cons for appending, scanlM' has quadratic
2109-- complexity when iterated over a stream. We should use StreamK style scanlM'
2110-- for linear performance on iteration.
2112-- | Like 'scanl'' but with a monadic fold function.
2114-- @since 0.4.0
2115{-# INLINE scanlM' #-}
2116scanlM' :: (IsStream t, Monad m) => (b -> a -> m b) -> b -> t m a -> t m b
2117scanlM' step begin m = fromStreamD $ D.scanlM' step begin $ toStreamD m
2119-- | @scanlMAfter' accumulate initial done stream@ is like 'scanlM'' except
2120-- that it provides an additional @done@ function to be applied on the
2121-- accumulator when the stream stops. The result of @done@ is also emitted in
2122-- the stream.
2124-- This function can be used to allocate a resource in the beginning of the
2125-- scan and release it when the stream ends or to flush the internal state of
2126-- the scan at the end.
2128-- /Internal/
2130{-# INLINE scanlMAfter' #-}
2131scanlMAfter' :: (IsStream t, Monad m)
2132 => (b -> a -> m b) -> m b -> (b -> m b) -> t m a -> t m b
2133scanlMAfter' step initial done stream =
2134 fromStreamD $ D.scanlMAfter' step initial done $ toStreamD stream
2136-- XXX because of the use of D.cons for appending, scanl' has quadratic
2137-- complexity when iterated over a stream. We should use StreamK style scanlM'
2138-- for linear performance on iteration.
2140-- | Strict left scan. Like 'map', 'scanl'' too is a one to one transformation,
2141-- however it adds an extra element.
2143-- @
2144-- > S.toList $ S.scanl' (+) 0 $ fromList [1,2,3,4]
2145-- [0,1,3,6,10]
2146-- @
2148-- @
2149-- > S.toList $ S.scanl' (flip (:)) [] $ S.fromList [1,2,3,4]
2150-- [[],[1],[2,1],[3,2,1],[4,3,2,1]]
2151-- @
2153-- The output of 'scanl'' is the initial value of the accumulator followed by
2154-- all the intermediate steps and the final result of 'foldl''.
2156-- By streaming the accumulated state after each fold step, we can share the
2157-- state across multiple stages of stream composition. Each stage can modify or
2158-- extend the state, do some processing with it and emit it for the next stage,
2159-- thus modularizing the stream processing. This can be useful in
2160-- stateful or event-driven programming.
2162-- Consider the following monolithic example, computing the sum and the product
2163-- of the elements in a stream in one go using a @foldl'@:
2165-- @
2166-- > S.foldl' (\\(s, p) x -> (s + x, p * x)) (0,1) $ S.fromList \[1,2,3,4]
2167-- (10,24)
2168-- @
2170-- Using @scanl'@ we can make it modular by computing the sum in the first
2171-- stage and passing it down to the next stage for computing the product:
2173-- @
2174-- > S.foldl' (\\(_, p) (s, x) -> (s, p * x)) (0,1)
2175-- $ S.scanl' (\\(s, _) x -> (s + x, x)) (0,1)
2176-- $ S.fromList \[1,2,3,4]
2177-- (10,24)
2178-- @
2180-- IMPORTANT: 'scanl'' evaluates the accumulator to WHNF. To avoid building
2181-- lazy expressions inside the accumulator, it is recommended that a strict
2182-- data structure is used for accumulator.
2184-- @since 0.2.0
2185{-# INLINE scanl' #-}
2186scanl' :: (IsStream t, Monad m) => (b -> a -> b) -> b -> t m a -> t m b
2187scanl' step z m = fromStreamS $ S.scanl' step z $ toStreamS m
2189-- | Like 'scanl'' but does not stream the initial value of the accumulator.
2191-- > postscanl' f z xs = S.drop 1 $ S.scanl' f z xs
2193-- @since 0.7.0
2194{-# INLINE postscanl' #-}
2195postscanl' :: (IsStream t, Monad m) => (b -> a -> b) -> b -> t m a -> t m b
2196postscanl' step z m = fromStreamD $ D.postscanl' step z $ toStreamD m
2198-- XXX this needs to be concurrent
2199-- | Like 'postscanl'' but with a monadic step function.
2201-- @since 0.7.0
2202{-# INLINE postscanlM' #-}
2203postscanlM' :: (IsStream t, Monad m) => (b -> a -> m b) -> b -> t m a -> t m b
2204postscanlM' step z m = fromStreamD $ D.postscanlM' step z $ toStreamD m
2206-- XXX prescanl does not sound very useful, enable only if there is a
2207-- compelling use case.
2209-- | Like scanl' but does not stream the final value of the accumulator.
2211-- /Internal/
2212{-# INLINE prescanl' #-}
2213prescanl' :: (IsStream t, Monad m) => (b -> a -> b) -> b -> t m a -> t m b
2214prescanl' step z m = fromStreamD $ D.prescanl' step z $ toStreamD m
2216-- XXX this needs to be concurrent
2217-- | Like postscanl' but with a monadic step function.
2219-- /Internal/
2220{-# INLINE prescanlM' #-}
2221prescanlM' :: (IsStream t, Monad m) => (b -> a -> m b) -> m b -> t m a -> t m b
2222prescanlM' step z m = fromStreamD $ D.prescanlM' step z $ toStreamD m
2224-- XXX this needs to be concurrent
2225-- | Like 'scanl1'' but with a monadic step function.
2227-- @since 0.6.0
2228{-# INLINE scanl1M' #-}
2229scanl1M' :: (IsStream t, Monad m) => (a -> a -> m a) -> t m a -> t m a
2230scanl1M' step m = fromStreamD $ D.scanl1M' step $ toStreamD m
2232-- | Like 'scanl'' but for a non-empty stream. The first element of the stream
2233-- is used as the initial value of the accumulator. Does nothing if the stream
2234-- is empty.
2236-- @
2237-- > S.toList $ S.scanl1 (+) $ fromList [1,2,3,4]
2238-- [1,3,6,10]
2239-- @
2241-- @since 0.6.0
2242{-# INLINE scanl1' #-}
2243scanl1' :: (IsStream t, Monad m) => (a -> a -> a) -> t m a -> t m a
2244scanl1' step m = fromStreamD $ D.scanl1' step $ toStreamD m
2246------------------------------------------------------------------------------
2247-- Scanning with a Fold
2248------------------------------------------------------------------------------
2250-- | Scan a stream using the given monadic fold.
2252-- @since 0.7.0
2253{-# INLINE scan #-}
2254scan :: (IsStream t, Monad m) => Fold m a b -> t m a -> t m b
2255scan (Fold step begin done) = P.scanlMx' step begin done
2257-- | Postscan a stream using the given monadic fold.
2259-- @since 0.7.0
2260{-# INLINE postscan #-}
2261postscan :: (IsStream t, Monad m) => Fold m a b -> t m a -> t m b
2262postscan (Fold step begin done) = P.postscanlMx' step begin done
2264------------------------------------------------------------------------------
2265-- Stateful Transformations
2266------------------------------------------------------------------------------
2268-- XXX this is not a one-to-one map so calling it map may not be right.
2269-- We can perhaps call it zipWithTail or rollWith.
2271-- | Apply a function on every two successive elements of a stream. If the
2272-- stream consists of a single element the output is an empty stream.
2274-- This is the stream equivalent of the list idiom @zipWith f xs (tail xs)@.
2276-- /Internal/
2278{-# INLINE rollingMap #-}
2279rollingMap :: (IsStream t, Monad m) => (a -> a -> b) -> t m a -> t m b
2280rollingMap f m = fromStreamD $ D.rollingMap f $ toStreamD m
2282-- | Like 'rollingMap' but with an effectful map function.
2284-- /Internal/
2286{-# INLINE rollingMapM #-}
2287rollingMapM :: (IsStream t, Monad m) => (a -> a -> m b) -> t m a -> t m b
2288rollingMapM f m = fromStreamD $ D.rollingMapM f $ toStreamD m
2290------------------------------------------------------------------------------
2291-- Transformation by Filtering
2292------------------------------------------------------------------------------
2294-- | Include only those elements that pass a predicate.
2296-- @since 0.1.0
2297{-# INLINE filter #-}
2298#if __GLASGOW_HASKELL__ != 802
2299-- GHC 8.2.2 crashes with this code, when used with "stack"
2300filter :: (IsStream t, Monad m) => (a -> Bool) -> t m a -> t m a
2301filter p m = fromStreamS $ S.filter p $ toStreamS m
2302#else
2303filter :: IsStream t => (a -> Bool) -> t m a -> t m a
2304filter = K.filter
2305#endif
2307-- | Same as 'filter' but with a monadic predicate.
2309-- @since 0.4.0
2310{-# INLINE filterM #-}
2311filterM :: (IsStream t, Monad m) => (a -> m Bool) -> t m a -> t m a
2312filterM p m = fromStreamD $ D.filterM p $ toStreamD m
2314-- | Drop repeated elements that are adjacent to each other.
2316-- @since 0.6.0
2317{-# INLINE uniq #-}
2318uniq :: (Eq a, IsStream t, Monad m) => t m a -> t m a
2319uniq = fromStreamD . D.uniq . toStreamD
2321-- | Ensures that all the elements of the stream are identical and then returns
2322-- that unique element.
2324-- @since 0.6.0
2325{-# INLINE the #-}
2326the :: (Eq a, Monad m) => SerialT m a -> m (Maybe a)
2327the m = S.the (toStreamS m)
2329-- | Take first 'n' elements from the stream and discard the rest.
2331-- @since 0.1.0
2332{-# INLINE take #-}
2333take :: (IsStream t, Monad m) => Int -> t m a -> t m a
2334take n m = fromStreamS $ S.take n $ toStreamS
2335 (maxYields (Just (fromIntegral n)) m)
2337-- | End the stream as soon as the predicate fails on an element.
2339-- @since 0.1.0
2340{-# INLINE takeWhile #-}
2341takeWhile :: (IsStream t, Monad m) => (a -> Bool) -> t m a -> t m a
2342takeWhile p m = fromStreamS $ S.takeWhile p $ toStreamS m
2344-- | Same as 'takeWhile' but with a monadic predicate.
2346-- @since 0.4.0
2347{-# INLINE takeWhileM #-}
2348takeWhileM :: (IsStream t, Monad m) => (a -> m Bool) -> t m a -> t m a
2349takeWhileM p m = fromStreamD $ D.takeWhileM p $ toStreamD m
2351-- | @takeByTime duration@ yields stream elements upto specified time
2352-- @duration@. The duration starts when the stream is evaluated for the first
2353-- time, before the first element is yielded. The time duration is checked
2354-- before generating each element, if the duration has expired the stream
2355-- stops.
2357-- The total time taken in executing the stream is guaranteed to be /at least/
2358-- @duration@, however, because the duration is checked before generating an
2359-- element, the upper bound is indeterminate and depends on the time taken in
2360-- generating and processing the last element.
2362-- No element is yielded if the duration is zero. At least one element is
2363-- yielded if the duration is non-zero.
2365-- /Internal/
2367{-# INLINE takeByTime #-}
2368takeByTime ::(MonadIO m, IsStream t, TimeUnit64 d) => d -> t m a -> t m a
2369takeByTime d = fromStreamD . D.takeByTime d . toStreamD
2371-- | Discard first 'n' elements from the stream and take the rest.
2373-- @since 0.1.0
2374{-# INLINE drop #-}
2375drop :: (IsStream t, Monad m) => Int -> t m a -> t m a
2376drop n m = fromStreamS $ S.drop n $ toStreamS m
2378-- | Drop elements in the stream as long as the predicate succeeds and then
2379-- take the rest of the stream.
2381-- @since 0.1.0
2382{-# INLINE dropWhile #-}
2383dropWhile :: (IsStream t, Monad m) => (a -> Bool) -> t m a -> t m a
2384dropWhile p m = fromStreamS $ S.dropWhile p $ toStreamS m
2386-- | Same as 'dropWhile' but with a monadic predicate.
2388-- @since 0.4.0
2389{-# INLINE dropWhileM #-}
2390dropWhileM :: (IsStream t, Monad m) => (a -> m Bool) -> t m a -> t m a
2391dropWhileM p m = fromStreamD $ D.dropWhileM p $ toStreamD m
2393-- | @dropByTime duration@ drops stream elements until specified @duration@ has
2394-- passed. The duration begins when the stream is evaluated for the first
2395-- time. The time duration is checked /after/ generating a stream element, the
2396-- element is yielded if the duration has expired otherwise it is dropped.
2398-- The time elapsed before starting to generate the first element is /at most/
2399-- @duration@, however, because the duration expiry is checked after the
2400-- element is generated, the lower bound is indeterminate and depends on the
2401-- time taken in generating an element.
2403-- All elements are yielded if the duration is zero.
2405-- /Internal/
2407{-# INLINE dropByTime #-}
2408dropByTime ::(MonadIO m, IsStream t, TimeUnit64 d) => d -> t m a -> t m a
2409dropByTime d = fromStreamD . D.dropByTime d . toStreamD
2411------------------------------------------------------------------------------
2412-- Transformation by Mapping
2413------------------------------------------------------------------------------
2415-- |
2416-- @
2417-- mapM f = sequence . map f
2418-- @
2420-- Apply a monadic function to each element of the stream and replace it with
2421-- the output of the resulting action.
2423-- @
2424-- > drain $ S.mapM putStr $ S.fromList ["a", "b", "c"]
2425-- abc
2427-- drain $ S.replicateM 10 (return 1)
2428-- & (serially . S.mapM (\\x -> threadDelay 1000000 >> print x))
2430-- drain $ S.replicateM 10 (return 1)
2431-- & (asyncly . S.mapM (\\x -> threadDelay 1000000 >> print x))
2432-- @
2434-- /Concurrent (do not use with 'parallely' on infinite streams)/
2436-- @since 0.1.0
2437{-# INLINE_EARLY mapM #-}
2438mapM :: (IsStream t, MonadAsync m) => (a -> m b) -> t m a -> t m b
2439mapM = K.mapM
2441{-# RULES "mapM serial" mapM = mapMSerial #-}
2442{-# INLINE mapMSerial #-}
2443mapMSerial :: Monad m => (a -> m b) -> SerialT m a -> SerialT m b
2444mapMSerial = Serial.mapM
2446-- |
2447-- @
2448-- sequence = mapM id
2449-- @
2451-- Replace the elements of a stream of monadic actions with the outputs of
2452-- those actions.
2454-- @
2455-- > drain $ S.sequence $ S.fromList [putStr "a", putStr "b", putStrLn "c"]
2456-- abc
2458-- drain $ S.replicateM 10 (return $ threadDelay 1000000 >> print 1)
2459-- & (serially . S.sequence)
2461-- drain $ S.replicateM 10 (return $ threadDelay 1000000 >> print 1)
2462-- & (asyncly . S.sequence)
2463-- @
2465-- /Concurrent (do not use with 'parallely' on infinite streams)/
2467-- @since 0.1.0
2468{-# INLINE sequence #-}
2469sequence :: (IsStream t, MonadAsync m) => t m (m a) -> t m a
2470sequence m = fromStreamS $ S.sequence (toStreamS m)
2472------------------------------------------------------------------------------
2473-- Transformation by Map and Filter
2474------------------------------------------------------------------------------
2476-- | Map a 'Maybe' returning function to a stream, filter out the 'Nothing'
2477-- elements, and return a stream of values extracted from 'Just'.
2479-- Equivalent to:
2481-- @
2482-- mapMaybe f = S.map 'fromJust' . S.filter 'isJust' . S.map f
2483-- @
2485-- @since 0.3.0
2486{-# INLINE mapMaybe #-}
2487mapMaybe :: (IsStream t, Monad m) => (a -> Maybe b) -> t m a -> t m b
2488mapMaybe f m = fromStreamS $ S.mapMaybe f $ toStreamS m
2490-- | Like 'mapMaybe' but maps a monadic function.
2492-- Equivalent to:
2494-- @
2495-- mapMaybeM f = S.map 'fromJust' . S.filter 'isJust' . S.mapM f
2496-- @
2498-- /Concurrent (do not use with 'parallely' on infinite streams)/
2500-- @since 0.3.0
2501{-# INLINE_EARLY mapMaybeM #-}
2502mapMaybeM :: (IsStream t, MonadAsync m, Functor (t m))
2503 => (a -> m (Maybe b)) -> t m a -> t m b
2504mapMaybeM f = fmap fromJust . filter isJust . K.mapM f
2506{-# RULES "mapMaybeM serial" mapMaybeM = mapMaybeMSerial #-}
2507{-# INLINE mapMaybeMSerial #-}
2508mapMaybeMSerial :: Monad m => (a -> m (Maybe b)) -> SerialT m a -> SerialT m b
2509mapMaybeMSerial f m = fromStreamD $ D.mapMaybeM f $ toStreamD m
2511------------------------------------------------------------------------------
2512-- Transformation by Reordering
2513------------------------------------------------------------------------------
2515-- XXX Use a compact region list to temporarily store the list, in both reverse
2516-- as well as in reverse'.
2518-- /Note:/ 'reverse'' is much faster than this, use that when performance
2519-- matters.
2521-- > reverse = S.foldlT (flip S.cons) S.nil
2523-- | Returns the elements of the stream in reverse order. The stream must be
2524-- finite. Note that this necessarily buffers the entire stream in memory.
2526-- /Since 0.7.0 (Monad m constraint)/
2528-- /Since: 0.1.1/
2529{-# INLINE reverse #-}
2530reverse :: (IsStream t, Monad m) => t m a -> t m a
2531reverse s = fromStreamS $ S.reverse $ toStreamS s
2533-- | Like 'reverse' but several times faster, requires a 'Storable' instance.
2535-- /Internal/
2536{-# INLINE reverse' #-}
2537reverse' :: (IsStream t, MonadIO m, Storable a) => t m a -> t m a
2538reverse' s = fromStreamD $ D.reverse' $ toStreamD s
2540------------------------------------------------------------------------------
2541-- Transformation by Inserting
2542------------------------------------------------------------------------------
2544-- intersperseM = intersperseBySpan 1
2546-- | Insert an effect and its output before consuming an element of a stream
2547-- except the first one.
2549-- @
2550-- >>> S.toList $ S.trace putChar $ S.intersperseM (putChar '.' >> return ',') $ S.fromList "hello"
2551-- > h.,e.,l.,l.,o"h,e,l,l,o"
2552-- @
2554-- @since 0.5.0
2555{-# INLINE intersperseM #-}
2556intersperseM :: (IsStream t, MonadAsync m) => m a -> t m a -> t m a
2557intersperseM m = fromStreamS . S.intersperseM m . toStreamS
2559-- | Insert a side effect before consuming an element of a stream except the
2560-- first one.
2562-- @
2563-- >>> S.drain $ S.trace putChar $ S.intersperseM_ (putChar '.') $ S.fromList "hello"
2564-- > h.e.l.l.o
2565-- @
2567-- /Internal/
2568{-# INLINE intersperseM_ #-}
2569intersperseM_ :: (IsStream t, Monad m) => m b -> t m a -> t m a
2570intersperseM_ m = fromStreamD . D.intersperseM_ m . toStreamD
2572-- | Insert a pure value between successive elements of a stream.
2574-- @
2575-- > S.toList $ S.intersperse ',' $ S.fromList "hello"
2576-- "h,e,l,l,o"
2577-- @
2579-- @since 0.7.0
2580{-# INLINE intersperse #-}
2581intersperse :: (IsStream t, MonadAsync m) => a -> t m a -> t m a
2582intersperse a = fromStreamS . S.intersperse a . toStreamS
2584-- | Insert an effect and its output after consuming an element of a stream.
2586-- @
2587-- >>> S.toList $ S.trace putChar $ S.intersperseSuffix (putChar '.' >> return ',') $ S.fromList "hello"
2588-- > h.,e.,l.,l.,o.,"h,e,l,l,o,"
2589-- @
2591-- /Internal/
2592{-# INLINE intersperseSuffix #-}
2593intersperseSuffix :: (IsStream t, MonadAsync m) => m a -> t m a -> t m a
2594intersperseSuffix m = fromStreamD . D.intersperseSuffix m . toStreamD
2596-- | Insert a side effect after consuming an element of a stream.
2598-- @
2599-- > S.mapM_ putChar $ S.intersperseSuffix_ (threadDelay 1000000) $ S.fromList "hello"
2600-- @
2602-- /Internal/
2604{-# INLINE intersperseSuffix_ #-}
2605intersperseSuffix_ :: (IsStream t, Monad m) => m b -> t m a -> t m a
2606intersperseSuffix_ m = fromStreamD . D.intersperseSuffix_ m . toStreamD
2608-- | Insert a side effect before consuming an element of a stream.
2610-- @
2611-- >>> S.toList $ S.trace putChar $ S.interspersePrefix_ (putChar '.' >> return ',') $ S.fromList "hello"
2612-- > .h.e.l.l.o"hello"
2613-- @
2615-- See also: 'trace_'
2617-- /Concurrent/
2619-- /Internal/
2621{-# INLINE interspersePrefix_ #-}
2622interspersePrefix_ :: (IsStream t, MonadAsync m) => m b -> t m a -> t m a
2623interspersePrefix_ m = mapM (\x -> void m >> return x)
2625-- Note: delay must be serial.
2627-- | Introduce a delay of specified seconds before consuming an element of the
2628-- stream except the first one.
2630-- @
2631-- >>> S.mapM_ print $ S.timestamped $ S.delay 1 $ S.enumerateFromTo 1 3
2632-- > (AbsTime (TimeSpec {sec = 2502706, nsec = 751137000}),1)
2633-- > (AbsTime (TimeSpec {sec = 2502707, nsec = 743535000}),2)
2634-- > (AbsTime (TimeSpec {sec = 2502708, nsec = 749758000}),3)
2635-- @
2637-- /Internal/
2639{-# INLINE delay #-}
2640delay :: (IsStream t, MonadIO m) => Double -> t m a -> t m a
2641delay n = intersperseM_ $ liftIO $ threadDelay $ round $ n * 1000000
2643-- Note: delay must be serial.
2645-- | Introduce a delay of specified seconds after consuming an element of a
2646-- stream.
2648-- @
2649-- >>> S.mapM_ print $ S.timestamped $ S.delayPost 1 $ S.enumerateFromTo 1 3
2650-- > (AbsTime (TimeSpec {sec = 2502826, nsec = 119030000}),1)
2651-- > (AbsTime (TimeSpec {sec = 2502827, nsec = 111393000}),2)
2652-- > (AbsTime (TimeSpec {sec = 2502828, nsec = 112221000}),3)
2653-- @
2655-- /Internal/
2657{-# INLINE delayPost #-}
2658delayPost :: (IsStream t, MonadIO m) => Double -> t m a -> t m a
2659delayPost n = intersperseSuffix_ $ liftIO $ threadDelay $ round $ n * 1000000
2661-- Note: delay must be serial, that's why 'trace_' is used.
2663-- | Introduce a delay of specified seconds before consuming an element of a
2664-- stream.
2666-- @
2667-- >>> S.mapM_ print $ S.timestamped $ S.delayPre 1 $ S.enumerateFromTo 1 3
2668-- > (AbsTime (TimeSpec {sec = 2502207, nsec = 533177000}),1)
2669-- > (AbsTime (TimeSpec {sec = 2502208, nsec = 530859000}),2)
2670-- > (AbsTime (TimeSpec {sec = 2502209, nsec = 531619000}),3)
2671-- @
2673-- /Internal/
2675{-# INLINE delayPre #-}
2676delayPre :: (IsStream t, MonadIO m) => Double -> t m a -> t m a
2677delayPre n = trace_ $ liftIO $ threadDelay $ round $ n * 1000000
2679-- | Like 'intersperseSuffix' but intersperses an effectful action into the
2680-- input stream after every @n@ elements and after the last element.
2682-- @
2683-- > S.toList $ S.intersperseSuffixBySpan 2 (return ',') $ S.fromList "hello"
2684-- "he,ll,o,"
2685-- @
2687-- /Internal/
2689{-# INLINE intersperseSuffixBySpan #-}
2690intersperseSuffixBySpan :: (IsStream t, MonadAsync m)
2691 => Int -> m a -> t m a -> t m a
2692intersperseSuffixBySpan n eff =
2693 fromStreamD . D.intersperseSuffixBySpan n eff . toStreamD
2696-- | Intersperse a monadic action into the input stream after every @n@
2697-- elements.
2699-- @
2700-- > S.toList $ S.intersperseBySpan 2 (return ',') $ S.fromList "hello"
2701-- "he,ll,o"
2702-- @
2704-- @since 0.7.0
2705{-# INLINE intersperseBySpan #-}
2706intersperseBySpan :: IsStream t => Int -> m a -> t m a -> t m a
2707intersperseBySpan _n _f _xs = undefined
2710-- | Intersperse a monadic action into the input stream after every @n@
2711-- seconds.
2713-- @
2714-- > S.drain $ S.interjectSuffix 1 (putChar ',') $ S.mapM (\\x -> threadDelay 1000000 >> putChar x) $ S.fromList "hello"
2715-- "h,e,l,l,o"
2716-- @
2718-- /Internal/
2719{-# INLINE interjectSuffix #-}
2720interjectSuffix
2721 :: (IsStream t, MonadAsync m)
2722 => Double -> m a -> t m a -> t m a
2723interjectSuffix n f xs = xs `Par.parallelFst` repeatM timed
2724 where timed = liftIO (threadDelay (round $ n * 1000000)) >> f
2726-- | @insertBy cmp elem stream@ inserts @elem@ before the first element in
2727-- @stream@ that is less than @elem@ when compared using @cmp@.
2729-- @
2730-- insertBy cmp x = 'mergeBy' cmp ('yield' x)
2731-- @
2733-- @
2734-- > S.toList $ S.insertBy compare 2 $ S.fromList [1,3,5]
2735-- [1,2,3,5]
2736-- @
2738-- @since 0.6.0
2739{-# INLINE insertBy #-}
2740insertBy ::
2741 (IsStream t, Monad m) => (a -> a -> Ordering) -> a -> t m a -> t m a
2742insertBy cmp x m = fromStreamS $ S.insertBy cmp x (toStreamS m)
2744------------------------------------------------------------------------------
2745-- Deleting
2746------------------------------------------------------------------------------
2748-- | Deletes the first occurrence of the element in the stream that satisfies
2749-- the given equality predicate.
2751-- @
2752-- > S.toList $ S.deleteBy (==) 3 $ S.fromList [1,3,3,5]
2753-- [1,3,5]
2754-- @
2756-- @since 0.6.0
2757{-# INLINE deleteBy #-}
2758deleteBy :: (IsStream t, Monad m) => (a -> a -> Bool) -> a -> t m a -> t m a
2759deleteBy cmp x m = fromStreamS $ S.deleteBy cmp x (toStreamS m)
2761------------------------------------------------------------------------------
2762-- Zipping
2763------------------------------------------------------------------------------
2765-- |
2766-- > indexed = S.postscanl' (\(i, _) x -> (i + 1, x)) (-1,undefined)
2767-- > indexed = S.zipWith (,) (S.enumerateFrom 0)
2769-- Pair each element in a stream with its index, starting from index 0.
2771-- @
2772-- > S.toList $ S.indexed $ S.fromList "hello"
2773-- [(0,'h'),(1,'e'),(2,'l'),(3,'l'),(4,'o')]
2774-- @
2776-- @since 0.6.0
2777{-# INLINE indexed #-}
2778indexed :: (IsStream t, Monad m) => t m a -> t m (Int, a)
2779indexed = fromStreamD . D.indexed . toStreamD
2781-- |
2782-- > indexedR n = S.postscanl' (\(i, _) x -> (i - 1, x)) (n + 1,undefined)
2783-- > indexedR n = S.zipWith (,) (S.enumerateFromThen n (n - 1))
2785-- Pair each element in a stream with its index, starting from the
2786-- given index @n@ and counting down.
2788-- @
2789-- > S.toList $ S.indexedR 10 $ S.fromList "hello"
2790-- [(10,'h'),(9,'e'),(8,'l'),(7,'l'),(6,'o')]
2791-- @
2793-- @since 0.6.0
2794{-# INLINE indexedR #-}
2795indexedR :: (IsStream t, Monad m) => Int -> t m a -> t m (Int, a)
2796indexedR n = fromStreamD . D.indexedR n . toStreamD
2798-- Note: The timestamp stream must be the second stream in the zip so that the
2799-- timestamp is generated after generating the stream element and not before.
2800-- If we do not do that then the following example will generate the same
2801-- timestamp for first two elements:
2803-- S.mapM_ print $ S.timestamped $ S.delay $ S.enumerateFromTo 1 3
2805-- | Pair each element in a stream with an absolute timestamp, using a clock of
2806-- specified granularity. The timestamp is generated just before the element
2807-- is consumed.
2809-- @
2810-- >>> S.mapM_ print $ S.timestampWith 0.01 $ S.delay 1 $ S.enumerateFromTo 1 3
2811-- @
2813-- /Internal/
2815{-# INLINE timestampWith #-}
2816timestampWith :: (IsStream t, MonadAsync m, Functor (t m))
2817 => Double -> t m a -> t m (AbsTime, a)
2818timestampWith g stream = Z.zipWith (flip (,)) stream (absTimesWith g)
2820-- TBD: check performance vs a custom implementation without using zipWith.
2822-- | Pair each element in a stream with an absolute timestamp, using a clock of
2823-- 10 ms granularity. The timestamp is generated just before the element is
2824-- consumed.
2826-- @
2827-- >>> S.mapM_ print $ S.timestamped $ S.delay 1 $ S.enumerateFromTo 1 3
2828-- (AbsTime (TimeSpec {sec = 2460689, nsec = 641121000}),1)
2829-- (AbsTime (TimeSpec {sec = 2460690, nsec = 639334000}),2)
2830-- (AbsTime (TimeSpec {sec = 2460691, nsec = 644479000}),3)
2831-- @
2833-- /Internal/
2835{-# INLINE timestamped #-}
2836timestamped :: (IsStream t, MonadAsync m, Functor (t m))
2837 => t m a -> t m (AbsTime, a)
2838timestamped = timestampWith 0.01
2840-- | Pair each element in a stream with relative times starting from 0, using a
2841-- clock with the specified granularity. The time is measured just before the
2842-- element is consumed.
2844-- @
2845-- >>> S.mapM_ print $ S.timeIndexWith 0.01 $ S.delay 1 $ S.enumerateFromTo 1 3
2846-- @
2848-- /Internal/
2850{-# INLINE timeIndexWith #-}
2851timeIndexWith :: (IsStream t, MonadAsync m, Functor (t m))
2852 => Double -> t m a -> t m (RelTime64, a)
2853timeIndexWith g stream = Z.zipWith (flip (,)) stream (relTimesWith g)
2855-- | Pair each element in a stream with relative times starting from 0, using a
2856-- 10 ms granularity clock. The time is measured just before the element is
2857-- consumed.
2859-- @
2860-- >>> S.mapM_ print $ S.timeIndexed $ S.delay 1 $ S.enumerateFromTo 1 3
2861-- (RelTime64 (NanoSecond64 0),1)
2862-- (RelTime64 (NanoSecond64 996239000),2)
2863-- (RelTime64 (NanoSecond64 1996712000),3)
2864-- @
2866-- /Internal/
2868{-# INLINE timeIndexed #-}
2869timeIndexed :: (IsStream t, MonadAsync m, Functor (t m))
2870 => t m a -> t m (RelTime64, a)
2871timeIndexed = timeIndexWith 0.01
2873------------------------------------------------------------------------------
2874-- Comparison
2875------------------------------------------------------------------------------
2877-- | Compare two streams for equality using an equality function.
2879-- @since 0.6.0
2880{-# INLINABLE eqBy #-}
2881eqBy :: (IsStream t, Monad m) => (a -> b -> Bool) -> t m a -> t m b -> m Bool
2882eqBy = P.eqBy
2884-- | Compare two streams lexicographically using a comparison function.
2886-- @since 0.6.0
2887{-# INLINABLE cmpBy #-}
2888cmpBy
2889 :: (IsStream t, Monad m)
2890 => (a -> b -> Ordering) -> t m a -> t m b -> m Ordering
2891cmpBy = P.cmpBy
2893------------------------------------------------------------------------------
2894-- Merge
2895------------------------------------------------------------------------------
2897-- | Merge two streams using a comparison function. The head elements of both
2898-- the streams are compared and the smaller of the two elements is emitted, if
2899-- both elements are equal then the element from the first stream is used
2900-- first.
2902-- If the streams are sorted in ascending order, the resulting stream would
2903-- also remain sorted in ascending order.
2905-- @
2906-- > S.toList $ S.mergeBy compare (S.fromList [1,3,5]) (S.fromList [2,4,6,8])
2907-- [1,2,3,4,5,6,8]
2908-- @
2910-- @since 0.6.0
2911{-# INLINABLE mergeBy #-}
2912mergeBy ::
2913 (IsStream t, Monad m) => (a -> a -> Ordering) -> t m a -> t m a -> t m a
2914mergeBy f m1 m2 = fromStreamS $ S.mergeBy f (toStreamS m1) (toStreamS m2)
2916-- | Like 'mergeBy' but with a monadic comparison function.
2918-- Merge two streams randomly:
2920-- @
2921-- > randomly _ _ = randomIO >>= \x -> return $ if x then LT else GT
2922-- > S.toList $ S.mergeByM randomly (S.fromList [1,1,1,1]) (S.fromList [2,2,2,2])
2923-- [2,1,2,2,2,1,1,1]
2924-- @
2926-- Merge two streams in a proportion of 2:1:
2928-- @
2929-- proportionately m n = do
2930-- ref <- newIORef $ cycle $ concat [replicate m LT, replicate n GT]
2931-- return $ \\_ _ -> do
2932-- r <- readIORef ref
2933-- writeIORef ref $ tail r
2934-- return $ head r
2936-- main = do
2937-- f <- proportionately 2 1
2938-- xs <- S.toList $ S.mergeByM f (S.fromList [1,1,1,1,1,1]) (S.fromList [2,2,2])
2939-- print xs
2940-- @
2941-- @
2942-- [1,1,2,1,1,2,1,1,2]
2943-- @
2945-- @since 0.6.0
2946{-# INLINABLE mergeByM #-}
2947mergeByM
2948 :: (IsStream t, Monad m)
2949 => (a -> a -> m Ordering) -> t m a -> t m a -> t m a
2950mergeByM f m1 m2 = fromStreamS $ S.mergeByM f (toStreamS m1) (toStreamS m2)
2953-- | Like 'mergeByM' but stops merging as soon as any of the two streams stops.
2954{-# INLINABLE mergeEndByAny #-}
2955mergeEndByAny
2956 :: (IsStream t, Monad m)
2957 => (a -> a -> m Ordering) -> t m a -> t m a -> t m a
2958mergeEndByAny f m1 m2 = fromStreamD $
2959 D.mergeEndByAny f (toStreamD m1) (toStreamD m2)
2961-- Like 'mergeByM' but stops merging as soon as the first stream stops.
2962{-# INLINABLE mergeEndByFirst #-}
2963mergeEndByFirst
2964 :: (IsStream t, Monad m)
2965 => (a -> a -> m Ordering) -> t m a -> t m a -> t m a
2966mergeEndByFirst f m1 m2 = fromStreamS $
2967 D.mergeEndByFirst f (toStreamD m1) (toStreamD m2)
2970-- Holding this back for now, we may want to use the name "merge" differently
2972-- | Same as @'mergeBy' 'compare'@.
2974-- @
2975-- > S.toList $ S.merge (S.fromList [1,3,5]) (S.fromList [2,4,6,8])
2976-- [1,2,3,4,5,6,8]
2977-- @
2979-- @since 0.6.0
2980{-# INLINABLE merge #-}
2981merge ::
2982 (IsStream t, Monad m, Ord a) => t m a -> t m a -> t m a
2983merge = mergeBy compare
2986-- | Like 'mergeBy' but merges concurrently (i.e. both the elements being
2987-- merged are generated concurrently).
2989-- @since 0.6.0
2990{-# INLINE mergeAsyncBy #-}
2991mergeAsyncBy :: (IsStream t, MonadAsync m)
2992 => (a -> a -> Ordering) -> t m a -> t m a -> t m a
2993mergeAsyncBy f = mergeAsyncByM (\a b -> return $ f a b)
2995-- | Like 'mergeByM' but merges concurrently (i.e. both the elements being
2996-- merged are generated concurrently).
2998-- @since 0.6.0
2999{-# INLINE mergeAsyncByM #-}
3000mergeAsyncByM :: (IsStream t, MonadAsync m)
3001 => (a -> a -> m Ordering) -> t m a -> t m a -> t m a
3002mergeAsyncByM f m1 m2 = fromStreamD $
3003 D.mergeByM f (D.mkParallelD $ toStreamD m1) (D.mkParallelD $ toStreamD m2)
3005------------------------------------------------------------------------------
3006-- Nesting
3007------------------------------------------------------------------------------
3009-- | @concatMapWith merge map stream@ is a two dimensional looping combinator.
3010-- The first argument specifies a merge or concat function that is used to
3011-- merge the streams generated by applying the second argument i.e. the @map@
3012-- function to each element of the input stream. The concat function could be
3013-- 'serial', 'parallel', 'async', 'ahead' or any other zip or merge function
3014-- and the second argument could be any stream generation function using a
3015-- seed.
3017-- /Compare 'foldMapWith'/
3019-- @since 0.7.0
3020{-# INLINE concatMapWith #-}
3021concatMapWith
3022 :: IsStream t
3023 => (t m b -> t m b -> t m b)
3024 -> (a -> t m b)
3025 -> t m a
3026 -> t m b
3027concatMapWith = K.concatMapBy
3029-- | Map a stream producing function on each element of the stream and then
3030-- flatten the results into a single stream.
3032-- @
3033-- concatMap = 'concatMapWith' 'Serial.serial'
3034-- concatMap f = 'concatMapM' (return . f)
3035-- concatMap f = 'concatUnfold' (UF.lmap f UF.fromStream)
3036-- @
3038-- @since 0.6.0
3039{-# INLINE concatMap #-}
3040concatMap ::(IsStream t, Monad m) => (a -> t m b) -> t m a -> t m b
3041concatMap f m = fromStreamD $ D.concatMap (toStreamD . f) (toStreamD m)
3043-- | Flatten a stream of streams to a single stream.
3045-- @
3046-- concat = concatMap id
3047-- @
3049-- /Internal/
3050{-# INLINE concat #-}
3051concat :: (IsStream t, Monad m) => t m (t m a) -> t m a
3052concat = concatMap id
3054-- | Append the outputs of two streams, yielding all the elements from the
3055-- first stream and then yielding all the elements from the second stream.
3057-- IMPORTANT NOTE: This could be 100x faster than @serial/<>@ for appending a
3058-- few (say 100) streams because it can fuse via stream fusion. However, it
3059-- does not scale for a large number of streams (say 1000s) and becomes
3060-- qudartically slow. Therefore use this for custom appending of a few streams
3061-- but use 'concatMap' or 'concatMapWith serial' for appending @n@ streams or
3062-- infinite containers of streams.
3064-- /Internal/
3065{-# INLINE append #-}
3066append ::(IsStream t, Monad m) => t m b -> t m b -> t m b
3067append m1 m2 = fromStreamD $ D.append (toStreamD m1) (toStreamD m2)
3069-- XXX Same as 'wSerial'. We should perhaps rename wSerial to interleave.
3070-- XXX Document the interleaving behavior of side effects in all the
3071-- interleaving combinators.
3072-- XXX Write time-domain equivalents of these. In the time domain we can
3073-- interleave two streams such that the value of second stream is always taken
3074-- from its last value even if no new value is being yielded, like
3075-- zipWithLatest. It would be something like interleaveWithLatest.
3077-- | Interleaves the outputs of two streams, yielding elements from each stream
3078-- alternately, starting from the first stream. If any of the streams finishes
3079-- early the other stream continues alone until it too finishes.
3081-- >>> :set -XOverloadedStrings
3082-- >>> interleave "ab" ",,,," :: SerialT Identity Char
3083-- fromList "a,b,,,"
3084-- >>> interleave "abcd" ",," :: SerialT Identity Char
3085-- fromList "a,b,cd"
3087-- 'interleave' is dual to 'interleaveMin', it can be called @interleaveMax@.
3089-- Do not use at scale in concatMapWith.
3091-- /Internal/
3092{-# INLINE interleave #-}
3093interleave ::(IsStream t, Monad m) => t m b -> t m b -> t m b
3094interleave m1 m2 = fromStreamD $ D.interleave (toStreamD m1) (toStreamD m2)
3096-- | Interleaves the outputs of two streams, yielding elements from each stream
3097-- alternately, starting from the first stream. As soon as the first stream
3098-- finishes, the output stops, discarding the remaining part of the second
3099-- stream. In this case, the last element in the resulting stream would be from
3100-- the second stream. If the second stream finishes early then the first stream
3101-- still continues to yield elements until it finishes.
3103-- >>> :set -XOverloadedStrings
3104-- >>> interleaveSuffix "abc" ",,,," :: SerialT Identity Char
3105-- fromList "a,b,c,"
3106-- >>> interleaveSuffix "abc" "," :: SerialT Identity Char
3107-- fromList "a,bc"
3109-- 'interleaveSuffix' is a dual of 'interleaveInfix'.
3111-- Do not use at scale in concatMapWith.
3113-- /Internal/
3114{-# INLINE interleaveSuffix #-}
3115interleaveSuffix ::(IsStream t, Monad m) => t m b -> t m b -> t m b
3116interleaveSuffix m1 m2 =
3117 fromStreamD $ D.interleaveSuffix (toStreamD m1) (toStreamD m2)
3119-- | Interleaves the outputs of two streams, yielding elements from each stream
3120-- alternately, starting from the first stream and ending at the first stream.
3121-- If the second stream is longer than the first, elements from the second
3122-- stream are infixed with elements from the first stream. If the first stream
3123-- is longer then it continues yielding elements even after the second stream
3124-- has finished.
3126-- >>> :set -XOverloadedStrings
3127-- >>> interleaveInfix "abc" ",,,," :: SerialT Identity Char
3128-- fromList "a,b,c"
3129-- >>> interleaveInfix "abc" "," :: SerialT Identity Char
3130-- fromList "a,bc"
3132-- 'interleaveInfix' is a dual of 'interleaveSuffix'.
3134-- Do not use at scale in concatMapWith.
3136-- /Internal/
3137{-# INLINE interleaveInfix #-}
3138interleaveInfix ::(IsStream t, Monad m) => t m b -> t m b -> t m b
3139interleaveInfix m1 m2 =
3140 fromStreamD $ D.interleaveInfix (toStreamD m1) (toStreamD m2)
3142-- | Interleaves the outputs of two streams, yielding elements from each stream
3143-- alternately, starting from the first stream. The output stops as soon as any
3144-- of the two streams finishes, discarding the remaining part of the other
3145-- stream. The last element of the resulting stream would be from the longer
3146-- stream.
3148-- >>> :set -XOverloadedStrings
3149-- >>> interleaveMin "ab" ",,,," :: SerialT Identity Char
3150-- fromList "a,b,"
3151-- >>> interleaveMin "abcd" ",," :: SerialT Identity Char
3152-- fromList "a,b,c"
3154-- 'interleaveMin' is dual to 'interleave'.
3156-- Do not use at scale in concatMapWith.
3158-- /Internal/
3159{-# INLINE interleaveMin #-}
3160interleaveMin ::(IsStream t, Monad m) => t m b -> t m b -> t m b
3161interleaveMin m1 m2 = fromStreamD $ D.interleaveMin (toStreamD m1) (toStreamD m2)
3163-- | Schedule the execution of two streams in a fair round-robin manner,
3164-- executing each stream once, alternately. Execution of a stream may not
3165-- necessarily result in an output, a stream may chose to @Skip@ producing an
3166-- element until later giving the other stream a chance to run. Therefore, this
3167-- combinator fairly interleaves the execution of two streams rather than
3168-- fairly interleaving the output of the two streams. This can be useful in
3169-- co-operative multitasking without using explicit threads. This can be used
3170-- as an alternative to `async`.
3172-- Do not use at scale in concatMapWith.
3174-- /Internal/
3175{-# INLINE roundrobin #-}
3176roundrobin ::(IsStream t, Monad m) => t m b -> t m b -> t m b
3177roundrobin m1 m2 = fromStreamD $ D.roundRobin (toStreamD m1) (toStreamD m2)
3179-- | Map a stream producing monadic function on each element of the stream
3180-- and then flatten the results into a single stream. Since the stream
3181-- generation function is monadic, unlike 'concatMap', it can produce an
3182-- effect at the beginning of each iteration of the inner loop.
3184-- @since 0.6.0
3185{-# INLINE concatMapM #-}
3186concatMapM :: (IsStream t, Monad m) => (a -> m (t m b)) -> t m a -> t m b
3187concatMapM f m = fromStreamD $ D.concatMapM (fmap toStreamD . f) (toStreamD m)
3189-- | Given a stream value in the underlying monad, lift and join the underlying
3190-- monad with the stream monad.
3192-- Compare with 'concat' and 'sequence'.
3194-- /Internal/
3196{-# INLINE concatM #-}
3197concatM :: (IsStream t, Monad m) => m (t m a) -> t m a
3198concatM generator = concatMapM (\() -> generator) (yield ())
3200-- | Like 'concatMap' but uses an 'Unfold' for stream generation. Unlike
3201-- 'concatMap' this can fuse the 'Unfold' code with the inner loop and
3202-- therefore provide many times better performance.
3204-- @since 0.7.0
3205{-# INLINE concatUnfold #-}
3206concatUnfold ::(IsStream t, Monad m) => Unfold m a b -> t m a -> t m b
3207concatUnfold u m = fromStreamD $ D.concatMapU u (toStreamD m)
3209-- | Like 'concatUnfold' but interleaves the streams in the same way as
3210-- 'interleave' behaves instead of appending them.
3212-- /Internal/
3213{-# INLINE concatUnfoldInterleave #-}
3214concatUnfoldInterleave ::(IsStream t, Monad m)
3215 => Unfold m a b -> t m a -> t m b
3216concatUnfoldInterleave u m =
3217 fromStreamD $ D.concatUnfoldInterleave u (toStreamD m)
3219-- | Like 'concatUnfold' but executes the streams in the same way as
3220-- 'roundrobin'.
3222-- /Internal/
3223{-# INLINE concatUnfoldRoundrobin #-}
3224concatUnfoldRoundrobin ::(IsStream t, Monad m)
3225 => Unfold m a b -> t m a -> t m b
3226concatUnfoldRoundrobin u m =
3227 fromStreamD $ D.concatUnfoldRoundrobin u (toStreamD m)
3229-- XXX we can swap the order of arguments to gintercalate so that the
3230-- definition of concatUnfold becomes simpler? The first stream should be
3231-- infixed inside the second one. However, if we change the order in
3232-- "interleave" as well similarly, then that will make it a bit unintuitive.
3234-- > concatUnfold unf str =
3235-- > gintercalate unf str (UF.nilM (\_ -> return ())) (repeat ())
3237-- | 'interleaveInfix' followed by unfold and concat.
3239-- /Internal/
3240{-# INLINE gintercalate #-}
3241gintercalate
3242 :: (IsStream t, Monad m)
3243 => Unfold m a c -> t m a -> Unfold m b c -> t m b -> t m c
3244gintercalate unf1 str1 unf2 str2 =
3245 D.fromStreamD $ D.gintercalate
3246 unf1 (D.toStreamD str1)
3247 unf2 (D.toStreamD str2)
3249-- XXX The order of arguments in "intercalate" is consistent with the list
3250-- intercalate but inconsistent with gintercalate and other stream interleaving
3251-- combinators. We can change the order of the arguments in other combinators
3252-- but then 'interleave' combinator may become a bit unintuitive because we
3253-- will be starting with the second stream.
3255-- > intercalate seed unf str = gintercalate unf str unf (repeatM seed)
3256-- > intercalate a unf str = concatUnfold unf $ intersperse a str
3258-- | 'intersperse' followed by unfold and concat.
3260-- > unwords = intercalate " " UF.fromList
3262-- >>> intercalate " " UF.fromList ["abc", "def", "ghi"]
3263-- > "abc def ghi"
3265-- /Internal/
3266{-# INLINE intercalate #-}
3267intercalate :: (IsStream t, Monad m)
3268 => b -> Unfold m b c -> t m b -> t m c
3269intercalate seed unf str = D.fromStreamD $
3270 D.concatMapU unf $ D.intersperse seed (toStreamD str)
3272-- > interpose x unf str = gintercalate unf str UF.identity (repeat x)
3274-- | Unfold the elements of a stream, intersperse the given element between the
3275-- unfolded streams and then concat them into a single stream.
3277-- > unwords = S.interpose ' '
3279-- /Internal/
3280{-# INLINE interpose #-}
3281interpose :: (IsStream t, Monad m)
3282 => c -> Unfold m b c -> t m b -> t m c
3283interpose x unf str =
3284 D.fromStreamD $ D.interpose (return x) unf (D.toStreamD str)
3286-- | 'interleaveSuffix' followed by unfold and concat.
3288-- /Internal/
3289{-# INLINE gintercalateSuffix #-}
3290gintercalateSuffix
3291 :: (IsStream t, Monad m)
3292 => Unfold m a c -> t m a -> Unfold m b c -> t m b -> t m c
3293gintercalateSuffix unf1 str1 unf2 str2 =
3294 D.fromStreamD $ D.gintercalateSuffix
3295 unf1 (D.toStreamD str1)
3296 unf2 (D.toStreamD str2)
3298-- > intercalateSuffix seed unf str = gintercalateSuffix unf str unf (repeatM seed)
3299-- > intercalateSuffix a unf str = concatUnfold unf $ intersperseSuffix a str
3301-- | 'intersperseSuffix' followed by unfold and concat.
3303-- > unlines = intercalateSuffix "\n" UF.fromList
3305-- >>> intercalate "\n" UF.fromList ["abc", "def", "ghi"]
3306-- > "abc\ndef\nghi\n"
3308-- /Internal/
3309{-# INLINE intercalateSuffix #-}
3310intercalateSuffix :: (IsStream t, Monad m)
3311 => b -> Unfold m b c -> t m b -> t m c
3312intercalateSuffix seed unf str = fromStreamD $ D.concatMapU unf
3313 $ D.intersperseSuffix (return seed) (D.toStreamD str)
3315-- interposeSuffix x unf str = gintercalateSuffix unf str UF.identity (repeat x)
3317-- | Unfold the elements of a stream, append the given element after each
3318-- unfolded stream and then concat them into a single stream.
3320-- > unlines = S.interposeSuffix '\n'
3322-- /Internal/
3323{-# INLINE interposeSuffix #-}
3324interposeSuffix :: (IsStream t, Monad m)
3325 => c -> Unfold m b c -> t m b -> t m c
3326interposeSuffix x unf str =
3327 D.fromStreamD $ D.interposeSuffix (return x) unf (D.toStreamD str)
3329------------------------------------------------------------------------------
3330-- Flattening Trees
3331------------------------------------------------------------------------------
3333-- | Like 'iterateM' but using a stream generator function.
3335-- /Internal/
3337{-# INLINE concatMapIterateWith #-}
3338concatMapIterateWith
3339 :: IsStream t
3340 => (t m a -> t m a -> t m a)
3341 -> (a -> t m a)
3342 -> t m a
3343 -> t m a
3344concatMapIterateWith combine f = concatMapWith combine go
3345 where
3346 go x = yield x `combine` concatMapWith combine go (f x)
3348-- concatMapIterateLeftsWith
3350-- | Traverse a forest with recursive tree structures whose non-leaf nodes are
3351-- of type @a@ and leaf nodes are of type @b@, flattening all the trees into
3352-- streams and combining the streams into a single stream consisting of both
3353-- leaf and non-leaf nodes.
3355-- 'concatMapTreeWith' is a generalization of 'concatMap', using a recursive
3356-- feedback loop to append the non-leaf nodes back to the input stream enabling
3357-- recursive traversal. 'concatMap' flattens a single level nesting whereas
3358-- 'concatMapTreeWith' flattens a recursively nested structure.
3360-- Traversing a directory tree recursively is a canonical use case of
3361-- 'concatMapTreeWith'.
3363-- @
3364-- concatMapTreeWith combine f xs = concatMapIterateWith combine g xs
3365-- where
3366-- g (Left tree) = f tree
3367-- g (Right leaf) = nil
3368-- @
3370-- /Internal/
3372{-# INLINE concatMapTreeWith #-}
3373concatMapTreeWith
3374 :: IsStream t
3375 => (t m (Either a b) -> t m (Either a b) -> t m (Either a b))
3376 -> (a -> t m (Either a b))
3377 -> t m (Either a b) -- Should be t m a?
3378 -> t m (Either a b)
3379concatMapTreeWith combine f = concatMapWith combine go
3380 where
3381 go (Left tree) = yield (Left tree) `combine` concatMapWith combine go (f tree)
3382 go (Right leaf) = yield $ Right leaf
3385-- | Like concatMapTreeWith but produces only stream of leaf elements.
3386-- On an either stream, iterate lefts but yield only rights.
3388-- concatMapEitherYieldRightsWith combine f xs =
3389-- catRights $ concatMapTreeWith combine f xs
3391{-# INLINE concatMapEitherYieldRightsWith #-}
3392concatMapEitherYieldRightsWith :: (IsStream t, MonadAsync m)
3393 => _ -> (a -> t m (Either a b)) -> t m (Either a b) -> t m b
3394concatMapEitherYieldRightsWith combine f xs = undefined
3398{-# INLINE concatUnfoldTree #-}
3399concatUnfoldTree :: (IsStream t, MonadAsync m)
3400 => Unfold m a (Either a b) -> t m (Either a b) -> t m (Either a b)
3401concatUnfoldTree unf xs = undefined
3404------------------------------------------------------------------------------
3405-- Feedback loop
3406------------------------------------------------------------------------------
3408-- We can perhaps even implement the SVar using this. The stream we are mapping
3409-- on is the work queue. When evaluated it results in either a leaf element to
3410-- yield or a tail stream to queue back to the work queue.
3412-- | Flatten a stream with a feedback loop back into the input.
3414-- For example, exceptions generated by the output stream can be fed back to
3415-- the input to take any corrective action. The corrective action may be to
3416-- retry the action or do nothing or log the errors. For the retry case we need
3417-- a feedback loop.
3419-- /Internal/
3421{-# INLINE concatMapLoopWith #-}
3422concatMapLoopWith
3423 :: (IsStream t, MonadAsync m)
3424 => (forall x. t m x -> t m x -> t m x)
3425 -> (a -> t m (Either b c))
3426 -> (b -> t m a) -- ^ feedback function to feed @b@ back into input
3427 -> t m a
3428 -> t m c
3429concatMapLoopWith combine f fb xs =
3430 concatMapWith combine go $ concatMapWith combine f xs
3431 where
3432 go (Left b) = concatMapLoopWith combine f fb $ fb b
3433 go (Right c) = yield c
3435-- | Concat a stream of trees, generating only leaves.
3437-- Compare with 'concatMapTreeWith'. While the latter returns all nodes in the
3438-- tree, this one returns only the leaves.
3440-- Traversing a directory tree recursively and yielding on the files is a
3441-- canonical use case of 'concatMapTreeYieldLeavesWith'.
3443-- @
3444-- concatMapTreeYieldLeavesWith combine f = concatMapLoopWith combine f yield
3445-- @
3447-- /Internal/
3449{-# INLINE concatMapTreeYieldLeavesWith #-}
3450concatMapTreeYieldLeavesWith
3451 :: (IsStream t, MonadAsync m)
3452 => (forall x. t m x -> t m x -> t m x)
3453 -> (a -> t m (Either a b))
3454 -> t m a
3455 -> t m b
3456concatMapTreeYieldLeavesWith combine f = concatMapLoopWith combine f yield
3458------------------------------------------------------------------------------
3459-- Parsing
3460------------------------------------------------------------------------------
3462-- Splitting operations that take a predicate and a Fold can be
3463-- expressed using parseMany. Operations like chunksOf, intervalsOf, split*,
3464-- can be expressed using parseMany when used with an appropriate Parser.
3466-- XXX We need takeGE/takeBetween to implement "some" using "many".
3468-- | Apply a 'Parser' repeatedly on a stream and emit the parsed values in the
3469-- output stream.
3471-- This is the streaming equivalent of the 'Streamly.Internal.Data.Parser.many'
3472-- parse combinator.
3474-- >>> S.toList $ S.parseMany (PR.take 2 $ PR.fromFold FL.sum) $ S.fromList [1..10]
3475-- > [3,7,11,15,19]
3477-- >>> S.toList $ S.parseMany (PR.line FL.toList) $ S.fromList "hello\nworld"
3478-- > ["hello\n","world"]
3480-- /Internal
3482{-# INLINE parseMany #-}
3483parseMany
3484 :: (IsStream t, MonadThrow m)
3485 => Parser m a b
3486 -> t m a
3487 -> t m b
3488parseMany p m =
3489 D.fromStreamD $ D.parseMany (PRK.fromParserK p) (D.toStreamD m)
3491{-# INLINE parseManyD #-}
3492parseManyD
3493 :: (IsStream t, MonadThrow m)
3494 => PRD.Parser m a b
3495 -> t m a
3496 -> t m b
3497parseManyD p m =
3498 D.fromStreamD $ D.parseMany p (D.toStreamD m)
3500-- | @parseManyTill collect test stream@ tries the parser @test@ on the input,
3501-- if @test@ fails it backtracks and tries @collect@, after @collect@ succeeds
3502-- @test@ is tried again and so on. The parser stops when @test@ succeeds. The
3503-- output of @test@ is discarded and the output of @collect@ is emitted in the
3504-- output stream. The parser fails if @collect@ fails.
3506-- /Unimplemented/
3508{-# INLINE parseManyTill #-}
3509parseManyTill ::
3510 -- (IsStream t, MonadThrow m) =>
3511 Parser m a b
3512 -> Parser m a x
3513 -> t m a
3514 -> t m b
3515parseManyTill = undefined
3517-- | Iterate a parser generating function on a stream. The initial value @b@ is
3518-- used to generate the first parser, the parser is applied on the stream and
3519-- the result is used to generate the next parser and so on.
3521-- >>> S.toList $ S.map getSum $ S.parseIterate (\b -> PR.take 2 (FL.mconcatTo b)) 0 $ S.map Sum $ S.fromList [1..10]
3522-- > [3,10,21,36,55,55]
3524-- This is the streaming equivalent of monad like sequenced application of
3525-- parsers where next parser is dependent on the previous parser.
3527-- /Internal/
3529{-# INLINE parseIterate #-}
3530parseIterate
3531 :: (IsStream t, MonadThrow m)
3532 => (b -> Parser m a b)
3533 -> b
3534 -> t m a
3535 -> t m b
3536parseIterate f i m = D.fromStreamD $
3537 D.parseIterate (PRK.fromParserK . f) i (D.toStreamD m)
3539------------------------------------------------------------------------------
3540-- Grouping/Splitting
3541------------------------------------------------------------------------------
3543------------------------------------------------------------------------------
3544-- Grouping without looking at elements
3545------------------------------------------------------------------------------
3547------------------------------------------------------------------------------
3548-- Binary APIs
3549------------------------------------------------------------------------------
3552------------------------------------------------------------------------------
3553-- N-ary APIs
3554------------------------------------------------------------------------------
3556------------------------------------------------------------------------------
3557-- Generalized grouping
3558------------------------------------------------------------------------------
3560-- This combinator is the most general grouping combinator and can be used to
3561-- implement all other grouping combinators.
3563-- XXX check if this can implement the splitOn combinator i.e. we can slide in
3564-- new elements, slide out old elements and incrementally compute the hash.
3565-- Also, can we implement the windowed classification combinators using this?
3567-- In fact this is a parse. Instead of using a special return value in the fold
3568-- we are using a mapping function.
3570-- Note that 'scanl'' (usually followed by a map to extract the desired value
3571-- from the accumulator) can be used to realize many implementations e.g. a
3572-- sliding window implementation. A scan followed by a mapMaybe is also a good
3573-- pattern to express many problems where we want to emit a filtered output and
3574-- not emit an output on every input.
3576-- Passing on of the initial accumulator value to the next fold is equivalent
3577-- to returning the leftover concept.
3580-- | @groupScan splitter fold stream@ folds the input stream using @fold@.
3581-- @splitter@ is applied on the accumulator of the fold every time an item is
3582-- consumed by the fold. The fold continues until @splitter@ returns a 'Just'
3583-- value. A 'Just' result from the @splitter@ specifies a result to be emitted
3584-- in the output stream and the initial value of the accumulator for the next
3585-- group's fold. This allows us to control whether to start fresh for the next
3586-- fold or to continue from the previous fold's output.
3588{-# INLINE groupScan #-}
3589groupScan
3590 :: (IsStream t, Monad m)
3591 => (x -> m (Maybe (b, x))) -> Fold m a x -> t m a -> t m b
3592groupScan split fold m = undefined
3595-- | Group the input stream into groups of @n@ elements each and then fold each
3596-- group using the provided fold function.
3598-- >> S.toList $ S.chunksOf 2 FL.sum (S.enumerateFromTo 1 10)
3599-- > [3,7,11,15,19]
3601-- This can be considered as an n-fold version of 'ltake' where we apply
3602-- 'ltake' repeatedly on the leftover stream until the stream exhausts.
3604-- @since 0.7.0
3605{-# INLINE chunksOf #-}
3606chunksOf
3607 :: (IsStream t, Monad m)
3608 => Int -> Fold m a b -> t m a -> t m b
3609chunksOf n f m = D.fromStreamD $ D.groupsOf n f (D.toStreamD m)
3611-- |
3613-- /Internal/
3614{-# INLINE chunksOf2 #-}
3615chunksOf2
3616 :: (IsStream t, Monad m)
3617 => Int -> m c -> Fold2 m c a b -> t m a -> t m b
3618chunksOf2 n action f m = D.fromStreamD $ D.groupsOf2 n action f (D.toStreamD m)
3620-- | @arraysOf n stream@ groups the elements in the input stream into arrays of
3621-- @n@ elements each.
3623-- Same as the following but may be more efficient:
3625-- > arraysOf n = S.chunksOf n (A.writeN n)
3627-- /Internal/
3628{-# INLINE arraysOf #-}
3629arraysOf :: (IsStream t, MonadIO m, Storable a)
3630 => Int -> t m a -> t m (Array a)
3631arraysOf n = chunksOf n (writeNUnsafe n)
3633-- XXX we can implement this by repeatedly applying the 'lrunFor' fold.
3634-- XXX add this example after fixing the serial stream rate control
3635-- >>> S.toList $ S.take 5 $ intervalsOf 1 FL.sum $ constRate 2 $ S.enumerateFrom 1
3636-- > [3,7,11,15,19]
3638-- | Group the input stream into windows of @n@ second each and then fold each
3639-- group using the provided fold function.
3641-- @since 0.7.0
3642{-# INLINE intervalsOf #-}
3643intervalsOf
3644 :: (IsStream t, MonadAsync m)
3645 => Double -> Fold m a b -> t m a -> t m b
3646intervalsOf n f xs =
3647 splitWithSuffix isNothing (FL.lcatMaybes f)
3648 (interjectSuffix n (return Nothing) (Serial.map Just xs))
3650------------------------------------------------------------------------------
3651-- N-ary APIs
3652------------------------------------------------------------------------------
3654-- | @groupsBy cmp f $ S.fromList [a,b,c,...]@ assigns the element @a@ to the
3655-- first group, if @b \`cmp` a@ is 'True' then @b@ is also assigned to the same
3656-- group. If @c \`cmp` a@ is 'True' then @c@ is also assigned to the same
3657-- group and so on. When the comparison fails a new group is started. Each
3658-- group is folded using the fold @f@ and the result of the fold is emitted in
3659-- the output stream.
3661-- >>> S.toList $ S.groupsBy (>) FL.toList $ S.fromList [1,3,7,0,2,5]
3662-- > [[1,3,7],[0,2,5]]
3664-- @since 0.7.0
3665{-# INLINE groupsBy #-}
3666groupsBy
3667 :: (IsStream t, Monad m)
3668 => (a -> a -> Bool)
3669 -> Fold m a b
3670 -> t m a
3671 -> t m b
3672groupsBy cmp f m = D.fromStreamD $ D.groupsBy cmp f (D.toStreamD m)
3674-- | Unlike @groupsBy@ this function performs a rolling comparison of two
3675-- successive elements in the input stream. @groupsByRolling cmp f $ S.fromList
3676-- [a,b,c,...]@ assigns the element @a@ to the first group, if @a \`cmp` b@ is
3677-- 'True' then @b@ is also assigned to the same group. If @b \`cmp` c@ is
3678-- 'True' then @c@ is also assigned to the same group and so on. When the
3679-- comparison fails a new group is started. Each group is folded using the fold
3680-- @f@.
3682-- >>> S.toList $ S.groupsByRolling (\a b -> a + 1 == b) FL.toList $ S.fromList [1,2,3,7,8,9]
3683-- > [[1,2,3],[7,8,9]]
3685-- @since 0.7.0
3686{-# INLINE groupsByRolling #-}
3687groupsByRolling
3688 :: (IsStream t, Monad m)
3689 => (a -> a -> Bool)
3690 -> Fold m a b
3691 -> t m a
3692 -> t m b
3693groupsByRolling cmp f m = D.fromStreamD $ D.groupsRollingBy cmp f (D.toStreamD m)
3695-- |
3696-- > groups = groupsBy (==)
3697-- > groups = groupsByRolling (==)
3699-- Groups contiguous spans of equal elements together in individual groups.
3701-- >>> S.toList $ S.groups FL.toList $ S.fromList [1,1,2,2]
3702-- > [[1,1],[2,2]]
3704-- @since 0.7.0
3705groups :: (IsStream t, Monad m, Eq a) => Fold m a b -> t m a -> t m b
3706groups = groupsBy (==)
3708------------------------------------------------------------------------------
3709-- N-ary split on a predicate
3710------------------------------------------------------------------------------
3712-- TODO: Use a Splitter configuration similar to the "split" package to make it
3713-- possible to express all splitting combinations. In general, we can have
3714-- infix/suffix/prefix/condensing of separators, dropping both leading/trailing
3715-- separators. We can have a single split operation taking the splitter config
3716-- as argument.
3718-- | Split on an infixed separator element, dropping the separator. Splits the
3719-- stream on separator elements determined by the supplied predicate, separator
3720-- is considered as infixed between two segments, if one side of the separator
3721-- is missing then it is parsed as an empty stream. The supplied 'Fold' is
3722-- applied on the split segments. With '-' representing non-separator elements
3723-- and '.' as separator, 'splitOn' splits as follows:
3725-- @
3726-- "--.--" => "--" "--"
3727-- "--." => "--" ""
3728-- ".--" => "" "--"
3729-- @
3731-- @splitOn (== x)@ is an inverse of @intercalate (S.yield x)@
3733-- Let's use the following definition for illustration:
3735-- > splitOn' p xs = S.toList $ S.splitOn p (FL.toList) (S.fromList xs)
3737-- >>> splitOn' (== '.') ""
3738-- [""]
3740-- >>> splitOn' (== '.') "."
3741-- ["",""]
3743-- >>> splitOn' (== '.') ".a"
3744-- > ["","a"]
3746-- >>> splitOn' (== '.') "a."
3747-- > ["a",""]
3749-- >>> splitOn' (== '.') "a.b"
3750-- > ["a","b"]
3752-- >>> splitOn' (== '.') "a..b"
3753-- > ["a","","b"]
3755-- @since 0.7.0
3757-- This can be considered as an n-fold version of 'breakOn' where we apply
3758-- 'breakOn' successively on the input stream, dropping the first element
3759-- of the second segment after each break.
3761{-# INLINE splitOn #-}
3762splitOn
3763 :: (IsStream t, Monad m)
3764 => (a -> Bool) -> Fold m a b -> t m a -> t m b
3765splitOn predicate f m =
3766 D.fromStreamD $ D.splitBy predicate f (D.toStreamD m)
3768-- | Like 'splitOn' but the separator is considered as suffixed to the segments
3769-- in the stream. A missing suffix at the end is allowed. A separator at the
3770-- beginning is parsed as empty segment. With '-' representing elements and
3771-- '.' as separator, 'splitOnSuffix' splits as follows:
3773-- @
3774-- "--.--." => "--" "--"
3775-- "--.--" => "--" "--"
3776-- ".--." => "" "--"
3777-- @
3779-- > splitOnSuffix' p xs = S.toList $ S.splitSuffixBy p (FL.toList) (S.fromList xs)
3781-- >>> splitOnSuffix' (== '.') ""
3782-- []
3784-- >>> splitOnSuffix' (== '.') "."
3785-- [""]
3787-- >>> splitOnSuffix' (== '.') "a"
3788-- ["a"]
3790-- >>> splitOnSuffix' (== '.') ".a"
3791-- > ["","a"]
3793-- >>> splitOnSuffix' (== '.') "a."
3794-- > ["a"]
3796-- >>> splitOnSuffix' (== '.') "a.b"
3797-- > ["a","b"]
3799-- >>> splitOnSuffix' (== '.') "a.b."
3800-- > ["a","b"]
3802-- >>> splitOnSuffix' (== '.') "a..b.."
3803-- > ["a","","b",""]
3805-- > lines = splitOnSuffix (== '\n')
3807-- @since 0.7.0
3809-- This can be considered as an n-fold version of 'breakPost' where we apply
3810-- 'breakPost' successively on the input stream, dropping the first element
3811-- of the second segment after each break.
3813{-# INLINE splitOnSuffix #-}
3814splitOnSuffix
3815 :: (IsStream t, Monad m)
3816 => (a -> Bool) -> Fold m a b -> t m a -> t m b
3817splitOnSuffix predicate f m =
3818 D.fromStreamD $ D.splitSuffixBy predicate f (D.toStreamD m)
3820-- | Like 'splitOn' after stripping leading, trailing, and repeated separators.
3821-- Therefore, @".a..b."@ with '.' as the separator would be parsed as
3822-- @["a","b"]@. In other words, its like parsing words from whitespace
3823-- separated text.
3825-- > wordsBy' p xs = S.toList $ S.wordsBy p (FL.toList) (S.fromList xs)
3827-- >>> wordsBy' (== ',') ""
3828-- > []
3830-- >>> wordsBy' (== ',') ","
3831-- > []
3833-- >>> wordsBy' (== ',') ",a,,b,"
3834-- > ["a","b"]
3836-- > words = wordsBy isSpace
3838-- @since 0.7.0
3840-- It is equivalent to splitting in any of the infix/prefix/suffix styles
3841-- followed by removal of empty segments.
3842{-# INLINE wordsBy #-}
3843wordsBy
3844 :: (IsStream t, Monad m)
3845 => (a -> Bool) -> Fold m a b -> t m a -> t m b
3846wordsBy predicate f m =
3847 D.fromStreamD $ D.wordsBy predicate f (D.toStreamD m)
3849-- | Like 'splitOnSuffix' but keeps the suffix attached to the resulting
3850-- splits.
3852-- > splitWithSuffix' p xs = S.toList $ S.splitWithSuffix p (FL.toList) (S.fromList xs)
3854-- >>> splitWithSuffix' (== '.') ""
3855-- []
3857-- >>> splitWithSuffix' (== '.') "."
3858-- ["."]
3860-- >>> splitWithSuffix' (== '.') "a"
3861-- ["a"]
3863-- >>> splitWithSuffix' (== '.') ".a"
3864-- > [".","a"]
3866-- >>> splitWithSuffix' (== '.') "a."
3867-- > ["a."]
3869-- >>> splitWithSuffix' (== '.') "a.b"
3870-- > ["a.","b"]
3872-- >>> splitWithSuffix' (== '.') "a.b."
3873-- > ["a.","b."]
3875-- >>> splitWithSuffix' (== '.') "a..b.."
3876-- > ["a.",".","b.","."]
3878-- @since 0.7.0
3880-- This can be considered as an n-fold version of 'breakPost' where we apply
3881-- 'breakPost' successively on the input stream.
3883{-# INLINE splitWithSuffix #-}
3884splitWithSuffix
3885 :: (IsStream t, Monad m)
3886 => (a -> Bool) -> Fold m a b -> t m a -> t m b
3887splitWithSuffix predicate f m =
3888 D.fromStreamD $ D.splitSuffixBy' predicate f (D.toStreamD m)
3890------------------------------------------------------------------------------
3891-- Split on a delimiter sequence
3892------------------------------------------------------------------------------
3894-- Int list examples for splitOn:
3896-- >>> splitList [] [1,2,3,3,4]
3897-- > [[1],[2],[3],[3],[4]]
3899-- >>> splitList [5] [1,2,3,3,4]
3900-- > [[1,2,3,3,4]]
3902-- >>> splitList [1] [1,2,3,3,4]
3903-- > [[],[2,3,3,4]]
3905-- >>> splitList [4] [1,2,3,3,4]
3906-- > [[1,2,3,3],[]]
3908-- >>> splitList [2] [1,2,3,3,4]
3909-- > [[1],[3,3,4]]
3911-- >>> splitList [3] [1,2,3,3,4]
3912-- > [[1,2],[],[4]]
3914-- >>> splitList [3,3] [1,2,3,3,4]
3915-- > [[1,2],[4]]
3917-- >>> splitList [1,2,3,3,4] [1,2,3,3,4]
3918-- > [[],[]]
3920-- | Like 'splitOn' but the separator is a sequence of elements instead of a
3921-- single element.
3923-- For illustration, let's define a function that operates on pure lists:
3925-- @
3926-- splitOnSeq' pat xs = S.toList $ S.splitOnSeq (A.fromList pat) (FL.toList) (S.fromList xs)
3927-- @
3929-- >>> splitOnSeq' "" "hello"
3930-- > ["h","e","l","l","o"]
3932-- >>> splitOnSeq' "hello" ""
3933-- > [""]
3935-- >>> splitOnSeq' "hello" "hello"
3936-- > ["",""]
3938-- >>> splitOnSeq' "x" "hello"
3939-- > ["hello"]
3941-- >>> splitOnSeq' "h" "hello"
3942-- > ["","ello"]
3944-- >>> splitOnSeq' "o" "hello"
3945-- > ["hell",""]
3947-- >>> splitOnSeq' "e" "hello"
3948-- > ["h","llo"]
3950-- >>> splitOnSeq' "l" "hello"
3951-- > ["he","","o"]
3953-- >>> splitOnSeq' "ll" "hello"
3954-- > ["he","o"]
3956-- 'splitOnSeq' is an inverse of 'intercalate'. The following law always holds:
3958-- > intercalate . splitOn == id
3960-- The following law holds when the separator is non-empty and contains none of
3961-- the elements present in the input lists:
3963-- > splitOn . intercalate == id
3965-- /Internal/
3967-- XXX We can use a polymorphic vector implemented by Array# to represent the
3968-- sequence, that way we can avoid the Storable constraint. If we still need
3969-- Storable Array for performance, we can use a separate splitOnArray API for
3970-- that. We can also have an API where the sequence itself is a lazy stream, so
3971-- that we can search files in files for example.
3972{-# INLINE splitOnSeq #-}
3973splitOnSeq
3974 :: (IsStream t, MonadIO m, Storable a, Enum a, Eq a)
3975 => Array a -> Fold m a b -> t m a -> t m b
3976splitOnSeq patt f m = D.fromStreamD $ D.splitOn patt f (D.toStreamD m)
3979-- This can be implemented easily using Rabin Karp
3980-- | Split on any one of the given patterns.
3981{-# INLINE splitOnAny #-}
3982splitOnAny
3983 :: (IsStream t, Monad m, Storable a, Integral a)
3984 => [Array a] -> Fold m a b -> t m a -> t m b
3985splitOnAny subseq f m = undefined -- D.fromStreamD $ D.splitOnAny f subseq (D.toStreamD m)
3988-- | Like 'splitSuffixBy' but the separator is a sequence of elements, instead
3989-- of a predicate for a single element.
3991-- > splitSuffixOn_ pat xs = S.toList $ S.splitSuffixOn (A.fromList pat) (FL.toList) (S.fromList xs)
3993-- >>> splitSuffixOn_ "." ""
3994-- [""]
3996-- >>> splitSuffixOn_ "." "."
3997-- [""]
3999-- >>> splitSuffixOn_ "." "a"
4000-- ["a"]
4002-- >>> splitSuffixOn_ "." ".a"
4003-- > ["","a"]
4005-- >>> splitSuffixOn_ "." "a."
4006-- > ["a"]
4008-- >>> splitSuffixOn_ "." "a.b"
4009-- > ["a","b"]
4011-- >>> splitSuffixOn_ "." "a.b."
4012-- > ["a","b"]
4014-- >>> splitSuffixOn_ "." "a..b.."
4015-- > ["a","","b",""]
4017-- > lines = splitSuffixOn "\n"
4019-- /Internal/
4020{-# INLINE splitOnSuffixSeq #-}
4021splitOnSuffixSeq
4022 :: (IsStream t, MonadIO m, Storable a, Enum a, Eq a)
4023 => Array a -> Fold m a b -> t m a -> t m b
4024splitOnSuffixSeq patt f m =
4025 D.fromStreamD $ D.splitSuffixOn False patt f (D.toStreamD m)
4028-- | Like 'splitOn' but drops any empty splits.
4030{-# INLINE wordsOn #-}
4031wordsOn
4032 :: (IsStream t, Monad m, Storable a, Eq a)
4033 => Array a -> Fold m a b -> t m a -> t m b
4034wordsOn subseq f m = undefined -- D.fromStreamD $ D.wordsOn f subseq (D.toStreamD m)
4037-- XXX use a non-monadic intersperse to remove the MonadAsync constraint.
4039-- | Like 'splitOnSeq' but splits the separator as well, as an infix token.
4041-- > splitOn'_ pat xs = S.toList $ S.splitOn' (A.fromList pat) (FL.toList) (S.fromList xs)
4043-- >>> splitOn'_ "" "hello"
4044-- > ["h","","e","","l","","l","","o"]
4046-- >>> splitOn'_ "hello" ""
4047-- > [""]
4049-- >>> splitOn'_ "hello" "hello"
4050-- > ["","hello",""]
4052-- >>> splitOn'_ "x" "hello"
4053-- > ["hello"]
4055-- >>> splitOn'_ "h" "hello"
4056-- > ["","h","ello"]
4058-- >>> splitOn'_ "o" "hello"
4059-- > ["hell","o",""]
4061-- >>> splitOn'_ "e" "hello"
4062-- > ["h","e","llo"]
4064-- >>> splitOn'_ "l" "hello"
4065-- > ["he","l","","l","o"]
4067-- >>> splitOn'_ "ll" "hello"
4068-- > ["he","ll","o"]
4070-- /Internal/
4071{-# INLINE splitBySeq #-}
4072splitBySeq
4073 :: (IsStream t, MonadAsync m, Storable a, Enum a, Eq a)
4074 => Array a -> Fold m a b -> t m a -> t m b
4075splitBySeq patt f m =
4076 intersperseM (fold f (A.toStream patt)) $ splitOnSeq patt f m
4078-- | Like 'splitSuffixOn' but keeps the suffix intact in the splits.
4080-- > splitSuffixOn'_ pat xs = S.toList $ FL.splitSuffixOn' (A.fromList pat) (FL.toList) (S.fromList xs)
4082-- >>> splitSuffixOn'_ "." ""
4083-- [""]
4085-- >>> splitSuffixOn'_ "." "."
4086-- ["."]
4088-- >>> splitSuffixOn'_ "." "a"
4089-- ["a"]
4091-- >>> splitSuffixOn'_ "." ".a"
4092-- > [".","a"]
4094-- >>> splitSuffixOn'_ "." "a."
4095-- > ["a."]
4097-- >>> splitSuffixOn'_ "." "a.b"
4098-- > ["a.","b"]
4100-- >>> splitSuffixOn'_ "." "a.b."
4101-- > ["a.","b."]
4103-- >>> splitSuffixOn'_ "." "a..b.."
4104-- > ["a.",".","b.","."]
4106-- /Internal/
4107{-# INLINE splitWithSuffixSeq #-}
4108splitWithSuffixSeq
4109 :: (IsStream t, MonadIO m, Storable a, Enum a, Eq a)
4110 => Array a -> Fold m a b -> t m a -> t m b
4111splitWithSuffixSeq patt f m =
4112 D.fromStreamD $ D.splitSuffixOn True patt f (D.toStreamD m)
4115-- This can be implemented easily using Rabin Karp
4116-- | Split post any one of the given patterns.
4117{-# INLINE splitSuffixOnAny #-}
4118splitSuffixOnAny
4119 :: (IsStream t, Monad m, Storable a, Integral a)
4120 => [Array a] -> Fold m a b -> t m a -> t m b
4121splitSuffixOnAny subseq f m = undefined
4122 -- D.fromStreamD $ D.splitPostAny f subseq (D.toStreamD m)
4125------------------------------------------------------------------------------
4126-- Nested Split
4127------------------------------------------------------------------------------
4129-- | @splitInnerBy splitter joiner stream@ splits the inner containers @f a@ of
4130-- an input stream @t m (f a)@ using the @splitter@ function. Container
4131-- elements @f a@ are collected until a split occurs, then all the elements
4132-- before the split are joined using the @joiner@ function.
4134-- For example, if we have a stream of @Array Word8@, we may want to split the
4135-- stream into arrays representing lines separated by '\n' byte such that the
4136-- resulting stream after a split would be one array for each line.
4138-- CAUTION! This is not a true streaming function as the container size after
4139-- the split and merge may not be bounded.
4141-- /Internal/
4142{-# INLINE splitInnerBy #-}
4143splitInnerBy
4144 :: (IsStream t, Monad m)
4145 => (f a -> m (f a, Maybe (f a))) -- splitter
4146 -> (f a -> f a -> m (f a)) -- joiner
4147 -> t m (f a)
4148 -> t m (f a)
4149splitInnerBy splitter joiner xs =
4150 D.fromStreamD $ D.splitInnerBy splitter joiner $ D.toStreamD xs
4152-- | Like 'splitInnerBy' but splits assuming the separator joins the segment in
4153-- a suffix style.
4155-- /Internal/
4156{-# INLINE splitInnerBySuffix #-}
4157splitInnerBySuffix
4158 :: (IsStream t, Monad m, Eq (f a), Monoid (f a))
4159 => (f a -> m (f a, Maybe (f a))) -- splitter
4160 -> (f a -> f a -> m (f a)) -- joiner
4161 -> t m (f a)
4162 -> t m (f a)
4163splitInnerBySuffix splitter joiner xs =
4164 D.fromStreamD $ D.splitInnerBySuffix splitter joiner $ D.toStreamD xs
4166------------------------------------------------------------------------------
4167-- Reorder in sequence
4168------------------------------------------------------------------------------
4171-- Buffer until the next element in sequence arrives. The function argument
4172-- determines the difference in sequence numbers. This could be useful in
4173-- implementing sequenced streams, for example, TCP reassembly.
4174{-# INLINE reassembleBy #-}
4175reassembleBy
4176 :: (IsStream t, Monad m)
4177 => Fold m a b
4178 -> (a -> a -> Int)
4179 -> t m a
4180 -> t m b
4181reassembleBy = undefined
4184------------------------------------------------------------------------------
4185-- Distributing
4186------------------------------------------------------------------------------
4188-- | Tap the data flowing through a stream into a 'Fold'. For example, you may
4189-- add a tap to log the contents flowing through the stream. The fold is used
4190-- only for effects, its result is discarded.
4192-- @
4193-- Fold m a b
4194-- |
4195-- -----stream m a ---------------stream m a-----
4197-- @
4199-- @
4200-- > S.drain $ S.tap (FL.drainBy print) (S.enumerateFromTo 1 2)
4201-- 1
4202-- 2
4203-- @
4205-- Compare with 'trace'.
4207-- @since 0.7.0
4208{-# INLINE tap #-}
4209tap :: (IsStream t, Monad m) => FL.Fold m a b -> t m a -> t m a
4210tap f xs = D.fromStreamD $ D.tap f (D.toStreamD xs)
4212-- | @tapOffsetEvery offset n@ taps every @n@th element in the stream
4213-- starting at @offset@. @offset@ can be between @0@ and @n - 1@. Offset 0
4214-- means start at the first element in the stream. If the offset is outside
4215-- this range then @offset `mod` n@ is used as offset.
4217-- @
4218-- >>> S.drain $ S.tapOffsetEvery 0 2 (FL.mapM print FL.toList) $ S.enumerateFromTo 0 10
4219-- > [0,2,4,6,8,10]
4220-- @
4222-- /Internal/
4224{-# INLINE tapOffsetEvery #-}
4225tapOffsetEvery :: (IsStream t, Monad m)
4226 => Int -> Int -> FL.Fold m a b -> t m a -> t m a
4227tapOffsetEvery offset n f xs =
4228 D.fromStreamD $ D.tapOffsetEvery offset n f (D.toStreamD xs)
4230-- | Redirect a copy of the stream to a supplied fold and run it concurrently
4231-- in an independent thread. The fold may buffer some elements. The buffer size
4232-- is determined by the prevailing 'maxBuffer' setting.
4234-- @
4235-- Stream m a -> m b
4236-- |
4237-- -----stream m a ---------------stream m a-----
4239-- @
4241-- @
4242-- > S.drain $ S.tapAsync (S.mapM_ print) (S.enumerateFromTo 1 2)
4243-- 1
4244-- 2
4245-- @
4247-- Exceptions from the concurrently running fold are propagated to the current
4248-- computation. Note that, because of buffering in the fold, exceptions may be
4249-- delayed and may not correspond to the current element being processed in the
4250-- parent stream, but we guarantee that before the parent stream stops the tap
4251-- finishes and all exceptions from it are drained.
4254-- Compare with 'tap'.
4256-- /Internal/
4257{-# INLINE tapAsync #-}
4258tapAsync :: (IsStream t, MonadAsync m) => FL.Fold m a b -> t m a -> t m a
4259tapAsync f xs = D.fromStreamD $ D.tapAsync f (D.toStreamD xs)
4261-- | @pollCounts predicate transform fold stream@ counts those elements in the
4262-- stream that pass the @predicate@. The resulting count stream is sent to
4263-- another thread which transforms it using @transform@ and then folds it using
4264-- @fold@. The thread is automatically cleaned up if the stream stops or
4265-- aborts due to exception.
4267-- For example, to print the count of elements processed every second:
4269-- @
4270-- > S.drain $ S.pollCounts (const True) (S.rollingMap (-) . S.delayPost 1) (FL.drainBy print)
4271-- $ S.enumerateFrom 0
4272-- @
4274-- Note: This may not work correctly on 32-bit machines.
4276-- /Internal/
4278{-# INLINE pollCounts #-}
4279pollCounts ::
4280 (IsStream t, MonadAsync m)
4281 => (a -> Bool)
4282 -> (t m Int -> t m Int)
4283 -> Fold m Int b
4284 -> t m a
4285 -> t m a
4286pollCounts predicate transf f xs =
4287 D.fromStreamD
4288 $ D.pollCounts predicate (D.toStreamD . transf . D.fromStreamD) f
4289 $ D.toStreamD xs
4291-- | Calls the supplied function with the number of elements consumed
4292-- every @n@ seconds. The given function is run in a separate thread
4293-- until the end of the stream. In case there is an exception in the
4294-- stream the thread is killed during the next major GC.
4296-- Note: The action is not guaranteed to run if the main thread exits.
4298-- @
4299-- > delay n = threadDelay (round $ n * 1000000) >> return n
4300-- > S.drain $ S.tapRate 2 (\\n -> print $ show n ++ " elements processed") (delay 1 S.|: delay 0.5 S.|: delay 0.5 S.|: S.nil)
4301-- 2 elements processed
4302-- 1 elements processed
4303-- @
4305-- Note: This may not work correctly on 32-bit machines.
4307-- /Internal/
4308{-# INLINE tapRate #-}
4309tapRate ::
4310 (IsStream t, MonadAsync m, MonadCatch m)
4311 => Double
4312 -> (Int -> m b)
4313 -> t m a
4314 -> t m a
4315tapRate n f xs = D.fromStreamD $ D.tapRate n f $ D.toStreamD xs
4317-- | Apply a monadic function to each element flowing through the stream and
4318-- discard the results.
4320-- @
4321-- > S.drain $ S.trace print (S.enumerateFromTo 1 2)
4322-- 1
4323-- 2
4324-- @
4326-- Compare with 'tap'.
4328-- @since 0.7.0
4329{-# INLINE trace #-}
4330trace :: (IsStream t, MonadAsync m) => (a -> m b) -> t m a -> t m a
4331trace f = mapM (\x -> void (f x) >> return x)
4333-- | Perform a side effect before yielding each element of the stream and
4334-- discard the results.
4336-- @
4337-- > S.drain $ S.trace_ (print "got here") (S.enumerateFromTo 1 2)
4338-- "got here"
4339-- "got here"
4340-- @
4342-- See also: 'trace', 'interspersePrefix_'
4344-- /Internal/
4345{-# INLINE trace_ #-}
4346trace_ :: (IsStream t, Monad m) => m b -> t m a -> t m a
4347trace_ eff = Serial.mapM (\x -> eff >> return x)
4349------------------------------------------------------------------------------
4350-- Windowed classification
4351------------------------------------------------------------------------------
4353-- We divide the stream into windows or chunks in space or time and each window
4354-- can be associated with a key, all events associated with a particular key in
4355-- the window can be folded to a single result. The stream can be split into
4356-- windows by size or by using a split predicate on the elements in the stream.
4357-- For example, when we receive a closing flag, we can close the window.
4359-- A "chunk" is a space window and a "session" is a time window. Are there any
4360-- other better short words to describe them. An alternative is to use
4361-- "swindow" and "twindow". Another word for "session" could be "spell".
4363-- TODO: To mark the position in space or time we can have Indexed or
4364-- TimeStamped types. That can make it easy to deal with the position indices
4365-- or timestamps.
4367------------------------------------------------------------------------------
4368-- Keyed Sliding Windows
4369------------------------------------------------------------------------------
4372{-# INLINABLE classifySlidingChunks #-}
4373classifySlidingChunks
4374 :: (IsStream t, MonadAsync m, Ord k)
4375 => Int -- ^ window size
4376 -> Int -- ^ window slide
4377 -> Fold m a b -- ^ Fold to be applied to window events
4378 -> t m (k, a, Bool) -- ^ window key, data, close event
4379 -> t m (k, b)
4380classifySlidingChunks wsize wslide (Fold step initial extract) str
4381 = undefined
4383-- XXX Another variant could be to slide the window on an event, e.g. in TCP we
4384-- slide the send window when an ack is received and we slide the receive
4385-- window when a sequence is complete. Sliding is stateful in case of TCP,
4386-- sliding releases the send buffer or makes data available to the user from
4387-- the receive buffer.
4388{-# INLINABLE classifySlidingSessions #-}
4389classifySlidingSessions
4390 :: (IsStream t, MonadAsync m, Ord k)
4391 => Double -- ^ timer tick in seconds
4392 -> Double -- ^ time window size
4393 -> Double -- ^ window slide
4394 -> Fold m a b -- ^ Fold to be applied to window events
4395 -> t m (k, a, Bool, AbsTime) -- ^ window key, data, close flag, timestamp
4396 -> t m (k, b)
4397classifySlidingSessions tick interval slide (Fold step initial extract) str
4398 = undefined
4401------------------------------------------------------------------------------
4402-- Sliding Window Buffers
4403------------------------------------------------------------------------------
4405-- These buffered versions could be faster than concurrent incremental folds of
4406-- all overlapping windows as in many cases we may not need all the values to
4407-- compute the fold, we can just compute the result using the old value and new
4408-- value. However, we may need the buffer once in a while, for example for
4409-- string search we usually compute the hash incrementally but when the hash
4410-- matches the hash of the pattern we need to compare the whole string.
4412-- XXX we should be able to implement sequence based splitting combinators
4413-- using this combinator.
4416-- | Buffer n elements of the input in a ring buffer. When t new elements are
4417-- collected, slide the window to remove the same number of oldest elements,
4418-- insert the new elements, and apply an incremental fold on the sliding
4419-- window, supplying the outgoing elements, the new ring buffer as arguments.
4420slidingChunkBuffer
4421 :: (IsStream t, Monad m, Ord a, Storable a)
4422 => Int -- window size
4423 -> Int -- window slide
4424 -> Fold m (Ring a, Array a) b
4425 -> t m a
4426 -> t m b
4427slidingChunkBuffer = undefined
4429-- Buffer n seconds worth of stream elements of the input in a radix tree.
4430-- Every t seconds, remove the items that are older than n seconds, and apply
4431-- an incremental fold on the sliding window, supplying the outgoing elements,
4432-- and the new radix tree buffer as arguments.
4433slidingSessionBuffer
4434 :: (IsStream t, Monad m, Ord a, Storable a)
4435 => Int -- window size
4436 -> Int -- tick size
4437 -> Fold m (RTree a, Array a) b
4438 -> t m a
4439 -> t m b
4440slidingSessionBuffer = undefined
4443------------------------------------------------------------------------------
4444-- Keyed Session Windows
4445------------------------------------------------------------------------------
4448-- | Keyed variable size space windows. Close the window if we do not receive a
4449-- window event in the next "spaceout" elements.
4450{-# INLINABLE classifyChunksBy #-}
4451classifyChunksBy
4452 :: (IsStream t, MonadAsync m, Ord k)
4453 => Int -- ^ window spaceout (spread)
4454 -> Bool -- ^ reset the spaceout when a chunk window element is received
4455 -> Fold m a b -- ^ Fold to be applied to chunk window elements
4456 -> t m (k, a, Bool) -- ^ chunk key, data, last element
4457 -> t m (k, b)
4458classifyChunksBy spanout reset (Fold step initial extract) str = undefined
4460-- | Like 'classifyChunksOf' but the chunk size is reset if an element is
4461-- received within the chunk size window. The chunk gets closed only if no
4462-- element is received within the chunk window.
4464{-# INLINABLE classifyKeepAliveChunks #-}
4465classifyKeepAliveChunks
4466 :: (IsStream t, MonadAsync m, Ord k)
4467 => Int -- ^ window spaceout (spread)
4468 -> Fold m a b -- ^ Fold to be applied to chunk window elements
4469 -> t m (k, a, Bool) -- ^ chunk key, data, last element
4470 -> t m (k, b)
4471classifyKeepAliveChunks spanout = classifyChunksBy spanout True
4474data SessionState t m k a b = SessionState
4475 { sessionCurTime :: !AbsTime -- ^ time since last event
4476 , sessionEventTime :: !AbsTime -- ^ time as per last event
4477 , sessionCount :: !Int -- ^ total number sessions in progress
4478 , sessionTimerHeap :: H.Heap (H.Entry AbsTime k) -- ^ heap for timeouts
4479 , sessionKeyValueMap :: Map.Map k a -- ^ Stored sessions for keys
4480 , sessionOutputStream :: t (m :: Type -> Type) (k, b) -- ^ Completed sessions
4483#undef Type
4485-- | @classifySessionsBy tick timeout idle pred f stream@ groups timestamped
4486-- events in an input event stream into sessions based on a session key. Each
4487-- element in the stream is an event consisting of a triple @(session key,
4488-- sesssion data, timestamp)@. @session key@ is a key that uniquely identifies
4489-- the session. All the events belonging to a session are folded using the
4490-- fold @f@ until the fold returns a 'Left' result or a timeout has occurred.
4491-- The session key and the result of the fold are emitted in the output stream
4492-- when the session is purged.
4494-- When @idle@ is 'False', @timeout@ is the maximum lifetime of a session in
4495-- seconds, measured from the @timestamp@ of the first event in that session.
4496-- When @idle@ is 'True' then the timeout is an idle timeout, it is reset after
4497-- every event received in the session.
4499-- @timestamp@ in an event characterizes the time when the input event was
4500-- generated, this is an absolute time measured from some @Epoch@. The notion
4501-- of current time is maintained by a monotonic event time clock using the
4502-- timestamps seen in the input stream. The latest timestamp seen till now is
4503-- used as the base for the current time. When no new events are seen, a timer
4504-- is started with a tick duration specified by @tick@. This timer is used to
4505-- detect session timeouts in the absence of new events.
4507-- The predicate @pred@ is invoked with the current session count, if it
4508-- returns 'True' a session is ejected from the session cache before inserting
4509-- a new session. This could be useful to alert or eject sessions when the
4510-- number of sessions becomes too high.
4512-- /Internal/
4515-- XXX Perhaps we should use an "Event a" type to represent timestamped data.
4516{-# INLINABLE classifySessionsBy #-}
4517classifySessionsBy
4518 :: (IsStream t, MonadAsync m, Ord k)
4519 => Double -- ^ timer tick in seconds
4520 -> Double -- ^ session timeout in seconds
4521 -> Bool -- ^ reset the timeout when an event is received
4522 -> (Int -> m Bool) -- ^ predicate to eject sessions based on session count
4523 -> Fold m a (Either b b) -- ^ Fold to be applied to session events
4524 -> t m (k, a, AbsTime) -- ^ session key, data, timestamp
4525 -> t m (k, b) -- ^ session key, fold result
4526classifySessionsBy tick tmout reset ejectPred
4527 (Fold step initial extract) str =
4528 concatMap sessionOutputStream $
4529 scanlMAfter' sstep (return szero) flush stream
4531 where
4533 timeoutMs = toRelTime (round (tmout * 1000) :: MilliSecond64)
4534 tickMs = toRelTime (round (tick * 1000) :: MilliSecond64)
4535 szero = SessionState
4536 { sessionCurTime = toAbsTime (0 :: MilliSecond64)
4537 , sessionEventTime = toAbsTime (0 :: MilliSecond64)
4538 , sessionCount = 0
4539 , sessionTimerHeap = H.empty
4540 , sessionKeyValueMap = Map.empty
4541 , sessionOutputStream = K.nil
4544 -- We can eject sessions based on the current session count to limit
4545 -- memory consumption. There are two possible strategies:
4546 --
4547 -- 1) Eject old sessions or sessions beyond a certain/lower timeout
4548 -- threshold even before timeout, effectively reduce the timeout.
4549 -- 2) Drop creation of new sessions but keep accepting new events for the
4550 -- old ones.
4551 --
4552 -- We use the first strategy as of now.
4554 -- Got a new stream input element
4555 sstep session@SessionState{..} (Just (key, value, timestamp)) = do
4556 -- XXX we should use a heap in pinned memory to scale it to a large
4557 -- size
4558 --
4559 -- To detect session inactivity we keep a timestamp of the latest event
4560 -- in the Map along with the fold result. When we purge the session
4561 -- from the heap we match the timestamp in the heap with the timestamp
4562 -- in the Map, if the latest timestamp is newer and has not expired we
4563 -- reinsert the key in the heap.
4564 --
4565 -- XXX if the key is an Int, we can also use an IntMap for slightly
4566 -- better performance.
4567 --
4568 let curTime = max sessionEventTime timestamp
4569 accumulate v = do
4570 old <- case v of
4571 Nothing -> initial
4572 Just (Tuple' _ acc) -> return acc
4573 new <- step old value
4574 return $ Tuple' timestamp new
4575 mOld = Map.lookup key sessionKeyValueMap
4577 acc@(Tuple' _ fres) <- accumulate mOld
4578 res <- extract fres
4579 case res of
4580 Left x -> do
4581 -- deleting a key from the heap is expensive, so we never
4582 -- delete a key from heap, we just purge it from the Map and it
4583 -- gets purged from the heap on timeout. We just need an extra
4584 -- lookup in the Map when the key is purged from the heap, that
4585 -- should not be expensive.
4586 --
4587 let (mp, cnt) = case mOld of
4588 Nothing -> (sessionKeyValueMap, sessionCount)
4589 Just _ -> (Map.delete key sessionKeyValueMap
4590 , sessionCount - 1)
4591 return $ session
4592 { sessionCurTime = curTime
4593 , sessionEventTime = curTime
4594 , sessionCount = cnt
4595 , sessionKeyValueMap = mp
4596 , sessionOutputStream = yield (key, x)
4598 Right _ -> do
4599 (hp1, mp1, out1, cnt1) <- do
4600 let vars = (sessionTimerHeap, sessionKeyValueMap,
4601 K.nil, sessionCount)
4602 case mOld of
4603 -- inserting new entry
4604 Nothing -> do
4605 -- Eject a session from heap and map is needed
4606 eject <- ejectPred sessionCount
4607 (hp, mp, out, cnt) <-
4608 if eject
4609 then ejectOne vars
4610 else return vars
4612 -- Insert the new session in heap
4613 let expiry = addToAbsTime timestamp timeoutMs
4614 hp' = H.insert (Entry expiry key) hp
4615 in return (hp', mp, out, cnt + 1)
4616 -- updating old entry
4617 Just _ -> return vars
4619 let mp2 = Map.insert key acc mp1
4620 return $ SessionState
4621 { sessionCurTime = curTime
4622 , sessionEventTime = curTime
4623 , sessionCount = cnt1
4624 , sessionTimerHeap = hp1
4625 , sessionKeyValueMap = mp2
4626 , sessionOutputStream = out1
4629 -- Got a timer tick event
4630 sstep sessionState@SessionState{..} Nothing =
4631 let curTime = addToAbsTime sessionCurTime tickMs
4632 in ejectExpired sessionState curTime
4634 flush session@SessionState{..} = do
4635 (hp', mp', out, count) <-
4636 ejectAll
4637 ( sessionTimerHeap
4638 , sessionKeyValueMap
4639 , K.nil
4640 , sessionCount
4642 return $ session
4643 { sessionCount = count
4644 , sessionTimerHeap = hp'
4645 , sessionKeyValueMap = mp'
4646 , sessionOutputStream = out
4649 fromEither e =
4650 case e of
4651 Left x -> x
4652 Right x -> x
4654 -- delete from map and output the fold accumulator
4655 ejectEntry hp mp out cnt acc key = do
4656 sess <- extract acc
4657 let out1 = (key, fromEither sess) `K.cons` out
4658 let mp1 = Map.delete key mp
4659 return (hp, mp1, out1, cnt - 1)
4661 ejectAll (hp, mp, out, !cnt) = do
4662 let hres = H.uncons hp
4663 case hres of
4664 Just (Entry _ key, hp1) -> do
4665 r <- case Map.lookup key mp of
4666 Nothing -> return (hp1, mp, out, cnt)
4667 Just (Tuple' _ acc) -> ejectEntry hp1 mp out cnt acc key
4668 ejectAll r
4669 Nothing -> do
4670 assert (Map.null mp) (return ())
4671 return (hp, mp, out, cnt)
4673 ejectOne (hp, mp, out, !cnt) = do
4674 let hres = H.uncons hp
4675 case hres of
4676 Just (Entry expiry key, hp1) ->
4677 case Map.lookup key mp of
4678 Nothing -> ejectOne (hp1, mp, out, cnt)
4679 Just (Tuple' latestTS acc) -> do
4680 let expiry1 = addToAbsTime latestTS timeoutMs
4681 if not reset || expiry1 <= expiry
4682 then ejectEntry hp1 mp out cnt acc key
4683 else
4684 -- reset the session timeout and continue
4685 let hp2 = H.insert (Entry expiry1 key) hp1
4686 in ejectOne (hp2, mp, out, cnt)
4687 Nothing -> do
4688 assert (Map.null mp) (return ())
4689 return (hp, mp, out, cnt)
4691 ejectExpired session@SessionState{..} curTime = do
4692 (hp', mp', out, count) <-
4693 ejectLoop sessionTimerHeap sessionKeyValueMap K.nil sessionCount
4694 return $ session
4695 { sessionCurTime = curTime
4696 , sessionCount = count
4697 , sessionTimerHeap = hp'
4698 , sessionKeyValueMap = mp'
4699 , sessionOutputStream = out
4702 where
4704 ejectLoop hp mp out !cnt = do
4705 let hres = H.uncons hp
4706 case hres of
4707 Just (Entry expiry key, hp1) -> do
4708 (eject, force) <-
4709 if curTime >= expiry
4710 then return (True, False)
4711 else do
4712 r <- ejectPred cnt
4713 return (r, r)
4714 if eject
4715 then
4716 case Map.lookup key mp of
4717 Nothing -> ejectLoop hp1 mp out cnt
4718 Just (Tuple' latestTS acc) -> do
4719 let expiry1 = addToAbsTime latestTS timeoutMs
4720 if expiry1 <= curTime || not reset || force
4721 then do
4722 (hp2,mp1,out1,cnt1) <-
4723 ejectEntry hp1 mp out cnt acc key
4724 ejectLoop hp2 mp1 out1 cnt1
4725 else
4726 -- reset the session timeout and continue
4727 let hp2 = H.insert (Entry expiry1 key) hp1
4728 in ejectLoop hp2 mp out cnt
4729 else return (hp, mp, out, cnt)
4730 Nothing -> do
4731 assert (Map.null mp) (return ())
4732 return (hp, mp, out, cnt)
4734 -- merge timer events in the stream
4735 stream = Serial.map Just str `Par.parallelFst` repeatM timer
4736 timer = do
4737 liftIO $ threadDelay (round $ tick * 1000000)
4738 return Nothing
4740-- | Like 'classifySessionsOf' but the session is kept alive if an event is
4741-- received within the session window. The session times out and gets closed
4742-- only if no event is received within the specified session window size.
4744-- If the ejection predicate returns 'True', the session that was idle for
4745-- the longest time is ejected before inserting a new session.
4747-- @
4748-- classifyKeepAliveSessions timeout pred = classifySessionsBy 1 timeout True pred
4749-- @
4751-- /Internal/
4753{-# INLINABLE classifyKeepAliveSessions #-}
4754classifyKeepAliveSessions
4755 :: (IsStream t, MonadAsync m, Ord k)
4756 => Double -- ^ session inactive timeout
4757 -> (Int -> m Bool) -- ^ predicate to eject sessions on session count
4758 -> Fold m a (Either b b) -- ^ Fold to be applied to session payload data
4759 -> t m (k, a, AbsTime) -- ^ session key, data, timestamp
4760 -> t m (k, b)
4761classifyKeepAliveSessions tmout =
4762 classifySessionsBy 1 tmout True
4764------------------------------------------------------------------------------
4765-- Keyed tumbling windows
4766------------------------------------------------------------------------------
4768-- Tumbling windows is a special case of sliding windows where the window slide
4769-- is the same as the window size. Or it can be a special case of session
4770-- windows where the reset flag is set to False.
4772-- XXX instead of using the early termination flag in the stream, we can use an
4773-- early terminating fold instead.
4776-- | Split the stream into fixed size chunks of specified size. Within each
4777-- such chunk fold the elements in buckets identified by the keys. A particular
4778-- bucket fold can be terminated early if a closing flag is encountered in an
4779-- element for that key.
4781-- @since 0.7.0
4782{-# INLINABLE classifyChunksOf #-}
4783classifyChunksOf
4784 :: (IsStream t, MonadAsync m, Ord k)
4785 => Int -- ^ window size
4786 -> Fold m a b -- ^ Fold to be applied to window events
4787 -> t m (k, a, Bool) -- ^ window key, data, close event
4788 -> t m (k, b)
4789classifyChunksOf wsize = classifyChunksBy wsize False
4792-- | Split the stream into fixed size time windows of specified interval in
4793-- seconds. Within each such window, fold the elements in sessions identified
4794-- by the session keys. The fold result is emitted in the output stream if the
4795-- fold returns a 'Left' result or if the time window ends.
4797-- Session @timestamp@ in the input stream is an absolute time from some epoch,
4798-- characterizing the time when the input element was generated. To detect
4799-- session window end, a monotonic event time clock is maintained synced with
4800-- the timestamps with a clock resolution of 1 second.
4802-- If the ejection predicate returns 'True', the session with the longest
4803-- lifetime is ejected before inserting a new session.
4805-- @
4806-- classifySessionsOf interval pred = classifySessionsBy 1 interval False pred
4807-- @
4809-- @
4810-- >>> S.mapM_ print
4811-- $ S.classifySessionsOf 3 (const (return False)) (fmap Right FL.toList)
4812-- $ S.map (\(ts,(k,a)) -> (k, a, ts))
4813-- $ S.timestamped
4814-- $ S.delay 1
4815-- $ (,) <$> S.fromList [1,2,3] <*> S.fromList [1,2,3]
4816-- @
4818-- /Internal/
4820{-# INLINABLE classifySessionsOf #-}
4821classifySessionsOf
4822 :: (IsStream t, MonadAsync m, Ord k)
4823 => Double -- ^ time window size
4824 -> (Int -> m Bool) -- ^ predicate to eject sessions on session count
4825 -> Fold m a (Either b b) -- ^ Fold to be applied to session events
4826 -> t m (k, a, AbsTime) -- ^ session key, data, timestamp
4827 -> t m (k, b)
4828classifySessionsOf interval =
4829 classifySessionsBy 1 interval False
4831------------------------------------------------------------------------------
4832-- Exceptions
4833------------------------------------------------------------------------------
4835-- | Run a side effect before the stream yields its first element.
4837-- @since 0.7.0
4838{-# INLINE before #-}
4839before :: (IsStream t, Monad m) => m b -> t m a -> t m a
4840before action xs = D.fromStreamD $ D.before action $ D.toStreamD xs
4842-- | Run a side effect at the end of the stream. The side effect won't run if
4843-- the stream is garbage collected before it reached the end.
4845-- This has slightly better performance than 'after'.
4847-- /Internal/
4849{-# INLINE after_ #-}
4850after_ :: (IsStream t, Monad m) => m b -> t m a -> t m a
4851after_ action xs = D.fromStreamD $ D.after_ action $ D.toStreamD xs
4853-- | Run a side effect at the end of the stream or if it is garbage collected
4854-- even before reaching the end.
4856-- @since 0.7.0
4858{-# INLINE after #-}
4859after :: (IsStream t, MonadIO m, MonadBaseControl IO m)
4860 => m b -> t m a -> t m a
4861after action xs = D.fromStreamD $ D.after action $ D.toStreamD xs
4863-- | Run a side effect whenever the stream aborts due to an exception.
4865-- @since 0.7.0
4866{-# INLINE onException #-}
4867onException :: (IsStream t, MonadCatch m) => m b -> t m a -> t m a
4868onException action xs = D.fromStreamD $ D.onException action $ D.toStreamD xs
4870-- | Run a side effect at the end of the stream or if it aborts due to an
4871-- exception before it could reach the end. The side effect is not run if the
4872-- stream is garbage collected before reaching the end.
4874-- This has slightly better performance than 'finally'.
4876-- /Internal/
4878{-# INLINE finally_ #-}
4879finally_ :: (IsStream t, MonadCatch m) => m b -> t m a -> t m a
4880finally_ action xs = D.fromStreamD $ D.finally_ action $ D.toStreamD xs
4882-- | Run a side effect at the end of the stream, or if it aborts due to an
4883-- exception or if it is garbage collected before it could reach the end.
4885-- @since 0.7.0
4887{-# INLINE finally #-}
4888finally :: (IsStream t, MonadAsync m, MonadCatch m) => m b -> t m a -> t m a
4889finally action xs = D.fromStreamD $ D.finally action $ D.toStreamD xs
4891-- | Run the first action before the stream starts and remember its output,
4892-- generate a stream using the output, run the second action using the
4893-- remembered value as an argument whenever the stream ends normally or due to
4894-- an exception. The second action won't run if the stream is garbage collected
4895-- before it could reach the end.
4897-- This has slightly better performance than 'bracket'.
4899-- /Internal/
4901{-# INLINE bracket_ #-}
4902bracket_ :: (IsStream t, MonadCatch m)
4903 => m b -> (b -> m c) -> (b -> t m a) -> t m a
4904bracket_ bef aft bet = D.fromStreamD $
4905 D.bracket_ bef aft (toStreamD . bet)
4907-- | Run the first action before the stream starts and remember its output,
4908-- generate a stream using the output, run the second action using the
4909-- remembered value as an argument whenever the stream ends normally, due to
4910-- an exception or if it is garbage collected after a partial lazy evaluation.
4912-- @since 0.7.0
4914{-# INLINE bracket #-}
4915bracket :: (IsStream t, MonadAsync m, MonadCatch m)
4916 => m b -> (b -> m c) -> (b -> t m a) -> t m a
4917bracket bef aft bet = D.fromStreamD $
4918 D.bracket bef aft (toStreamD . bet)
4920-- | When evaluating a stream if an exception occurs, stream evaluation aborts
4921-- and the specified exception handler is run with the exception as argument.
4923-- @since 0.7.0
4924{-# INLINE handle #-}
4925handle :: (IsStream t, MonadCatch m, Exception e)
4926 => (e -> t m a) -> t m a -> t m a
4927handle handler xs =
4928 D.fromStreamD $ D.handle (D.toStreamD . handler) $ D.toStreamD xs
4930------------------------------------------------------------------------------
4931-- Generalize the underlying monad
4932------------------------------------------------------------------------------
4934-- | Transform the inner monad of a stream using a natural transformation.
4936-- / Internal/
4938{-# INLINE hoist #-}
4939hoist :: (Monad m, Monad n)
4940 => (forall x. m x -> n x) -> SerialT m a -> SerialT n a
4941hoist f xs = fromStreamS $ S.hoist f (toStreamS xs)
4943-- | Generalize the inner monad of the stream from 'Identity' to any monad.
4945-- / Internal/
4947{-# INLINE generally #-}
4948generally :: (IsStream t, Monad m) => t Identity a -> t m a
4949generally xs = fromStreamS $ S.hoist (return . runIdentity) (toStreamS xs)
4951------------------------------------------------------------------------------
4952-- Add and remove a monad transformer
4953------------------------------------------------------------------------------
4955-- | Lift the inner monad of a stream using a monad transformer.
4957-- / Internal/
4959{-# INLINE liftInner #-}
4960liftInner :: (Monad m, IsStream t, MonadTrans tr, Monad (tr m))
4961 => t m a -> t (tr m) a
4962liftInner xs = fromStreamD $ D.liftInner (toStreamD xs)
4964-- | Evaluate the inner monad of a stream as 'ReaderT'.
4966-- / Internal/
4968{-# INLINE runReaderT #-}
4969runReaderT :: (IsStream t, Monad m) => m s -> t (ReaderT s m) a -> t m a
4970runReaderT s xs = fromStreamD $ D.runReaderT s (toStreamD xs)
4972-- | Evaluate the inner monad of a stream as 'StateT'.
4974-- This is supported only for 'SerialT' as concurrent state updation may not be
4975-- safe.
4977-- / Internal/
4979{-# INLINE evalStateT #-}
4980evalStateT :: Monad m => m s -> SerialT (StateT s m) a -> SerialT m a
4981evalStateT s xs = fromStreamD $ D.evalStateT s (toStreamD xs)
4983-- | Run a stateful (StateT) stream transformation using a given state.
4985-- This is supported only for 'SerialT' as concurrent state updation may not be
4986-- safe.
4988-- / Internal/
4990{-# INLINE usingStateT #-}
4991usingStateT
4992 :: Monad m
4993 => m s
4994 -> (SerialT (StateT s m) a -> SerialT (StateT s m) a)
4995 -> SerialT m a
4996 -> SerialT m a
4997usingStateT s f xs = evalStateT s $ f $ liftInner xs
4999-- | Evaluate the inner monad of a stream as 'StateT' and emit the resulting
5000-- state and value pair after each step.
5002-- This is supported only for 'SerialT' as concurrent state updation may not be
5003-- safe.
5005-- / Internal/
5007{-# INLINE runStateT #-}
5008runStateT :: Monad m => m s -> SerialT (StateT s m) a -> SerialT m (s, a)
5009runStateT s xs = fromStreamD $ D.runStateT s (toStreamD xs)
5011-- | Run a stream transformation using a given environment.
5013-- / Internal/
5015{-# INLINE usingReaderT #-}
5016usingReaderT
5017 :: (Monad m, IsStream t)
5018 => m r
5019 -> (t (ReaderT r m) a -> t (ReaderT r m) a)
5020 -> t m a
5021 -> t m a
5022usingReaderT r f xs = runReaderT r $ f $ liftInner xs