on 8a3828a help sign in
5016 lines 162 kB history raw
1{-# OPTIONS_GHC -Wno-orphans #-}
3#include "inline.hs"
5-- |
6-- Module : Streamly.Internal.Prelude
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.Prelude
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 , fromPrimVar
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 , parseManyTill
280 , parseIterate
282 -- ** Trimming
283 , take
284 -- , takeGE
285 -- , takeBetween
286 , takeByTime
287 -- , takeEnd
288 , takeWhile
289 , takeWhileM
290 -- , takeWhileEnd
291 , drop
292 , dropByTime
293 -- , dropEnd
294 , dropWhile
295 , dropWhileM
296 -- , dropWhileEnd
297 -- , dropAround
299 -- ** Breaking
301 -- Nary
302 , chunksOf
303 , chunksOf2
304 , arraysOf
305 , intervalsOf
307 -- ** Searching
308 -- -- *** Searching Elements
309 , findIndices
310 , elemIndices
312 -- -- *** Searching Sequences
313 -- , seqIndices -- search a sequence in the stream
315 -- -- *** Searching Multiple Sequences
316 -- , seqIndicesAny -- search any of the given sequence in the stream
318 -- -- -- ** Searching Streams
319 -- -- | Finding a stream within another stream.
321 -- ** Splitting
322 -- | Streams can be sliced into segments in space or in time. We use the
323 -- term @chunk@ to refer to a spatial length of the stream (spatial window)
324 -- and the term @session@ to refer to a length in time (time window).
326 -- -- *** Using Element Separators
327 , splitOn
328 , splitOnSuffix
329 -- , splitOnPrefix
331 -- , splitBy
332 , splitWithSuffix
333 -- , splitByPrefix
334 , wordsBy -- stripAndCompactBy
336 -- -- *** Splitting By Sequences
337 , splitOnSeq
338 , splitOnSuffixSeq
339 -- , splitOnPrefixSeq
341 -- Keeping the delimiters
342 , splitBySeq
343 , splitWithSuffixSeq
344 -- , splitByPrefixSeq
345 -- , wordsBySeq
347 -- Splitting using multiple sequence separators
348 -- , splitOnAnySeq
349 -- , splitOnAnySuffixSeq
350 -- , splitOnAnyPrefixSeq
352 -- -- *** Splitting By Streams
353 -- -- | Splitting a stream using another stream as separator.
355 -- Nested splitting
356 , splitInnerBy
357 , splitInnerBySuffix
359 -- ** Grouping
360 -- In imperative terms, grouped folding can be considered as a nested loop
361 -- where we loop over the stream to group elements and then loop over
362 -- individual groups to fold them to a single value that is yielded in the
363 -- output stream.
365 -- , groupScan
367 , groups
368 , groupsBy
369 , groupsByRolling
371 -- ** Group map
372 , rollingMapM
373 , rollingMap
375 -- * Windowed Classification
377 -- | Split the stream into windows or chunks in space or time. Each window
378 -- can be associated with a key, all events associated with a particular
379 -- key in the window can be folded to a single result. The stream is split
380 -- into windows of specified size, the window can be terminated early if
381 -- the closing flag is specified in the input stream.
382 --
383 -- The term "chunk" is used for a space window and the term "session" is
384 -- used for a time window.
386 -- ** Tumbling Windows
387 -- | A new window starts after the previous window is finished.
389 -- , classifyChunksOf
390 , classifySessionsBy
391 , classifySessionsOf
393 -- ** Keep Alive Windows
394 -- | The window size is extended if an event arrives within the specified
395 -- window size. This can represent sessions with idle or inactive timeout.
397 -- , classifyKeepAliveChunks
398 , classifyKeepAliveSessions
400 {-
401 -- ** Sliding Windows
402 -- | A new window starts after the specified slide from the previous
403 -- window. Therefore windows can overlap.
404 , classifySlidingChunks
405 , classifySlidingSessions
406 -}
407 -- ** Sliding Window Buffers
408 -- , slidingChunkBuffer
409 -- , slidingSessionBuffer
411 -- * Combining Streams
413 -- ** Appending
414 , append
416 -- ** Interleaving
417 , interleave
418 , interleaveMin
419 , interleaveSuffix
420 , interleaveInfix
422 , Serial.wSerialFst
423 , Serial.wSerialMin
425 -- ** Scheduling
426 , roundrobin
428 -- ** Parallel
429 , Par.parallelFst
430 , Par.parallelMin
432 -- ** Merging
434 -- , merge
435 , mergeBy
436 , mergeByM
437 , mergeAsyncBy
438 , mergeAsyncByM
440 -- ** Zipping
441 , Z.zipWith
442 , Z.zipWithM
443 , Z.zipAsyncWith
444 , Z.zipAsyncWithM
446 -- ** Folding Containers of Streams
447 , foldWith
448 , foldMapWith
449 , forEachWith
451 -- Flattening Nested Streams
452 -- ** Folding Streams of Streams
453 , concat
454 , concatM
455 , concatMap
456 , concatMapM
457 -- XXX add stateful concatMapWith?
458 , concatMapWith
459 -- , bindWith
461 -- ** Flattening Using Unfolds
462 , concatUnfold
463 , concatUnfoldInterleave
464 , concatUnfoldRoundrobin
466 -- ** Feedback Loops
467 , concatMapIterateWith
468 , concatMapTreeWith
469 , concatMapLoopWith
470 , concatMapTreeYieldLeavesWith
471 , K.mfix
473 -- ** Inserting Streams in Streams
474 , gintercalate
475 , gintercalateSuffix
476 , intercalate
477 , intercalateSuffix
478 , interpose
479 , interposeSuffix
480 -- , interposeBy
482 -- * Exceptions
483 , before
484 , after
485 , afterIO
486 , bracket
487 , bracketIO
488 , onException
489 , finally
490 , finallyIO
491 , handle
493 -- * Generalize Inner Monad
494 , hoist
495 , generally
497 -- * Transform Inner Monad
498 , liftInner
499 , usingReaderT
500 , runReaderT
501 , evalStateT
502 , usingStateT
503 , runStateT
505 -- * Diagnostics
506 , inspectMode
508 -- * Deprecated
509 , K.once
510 , each
511 , scanx
512 , foldx
513 , foldxM
514 , foldr1
515 , runStream
516 , runN
517 , runWhile
518 , fromHandle
519 , toHandle
520 )
521where
523import Control.Concurrent (threadDelay)
524import Control.Exception (Exception, assert)
525import Control.Monad (void)
526import Control.Monad.Catch (MonadCatch, MonadThrow)
527import Control.Monad.IO.Class (MonadIO(..))
528import Control.Monad.Trans.Reader (ReaderT)
529import Control.Monad.Trans.State.Strict (StateT)
530import Control.Monad.Trans.Class (MonadTrans(..))
531import Control.Monad.Trans.Control (MonadBaseControl)
532import Data.Functor.Identity (Identity (..))
533import Data.Kind (Type)
534import Data.Heap (Entry(..))
535import Data.Maybe (isJust, fromJust, isNothing)
536import Data.Void (Void)
537import Foreign.Storable (Storable)
538import Prelude
539 hiding (filter, drop, dropWhile, take, takeWhile, zipWith, foldr,
540 foldl, map, mapM, mapM_, sequence, all, any, sum, product, elem,
541 notElem, maximum, minimum, head, last, tail, length, null,
542 reverse, iterate, init, and, or, lookup, foldr1, (!!),
543 scanl, scanl1, replicate, concatMap, span, splitAt, break,
544 repeat, concat, mconcat)
546import qualified Data.Heap as H
547import qualified Data.Map.Strict as Map
548import qualified Prelude
549import qualified System.IO as IO
551import Streamly.Internal.Data.Stream.Enumeration (Enumerable(..), enumerate, enumerateTo)
552import Streamly.Internal.Data.Fold.Types (Fold (..), Fold2 (..))
553import Streamly.Internal.Data.Parser (Parser (..))
554import Streamly.Internal.Data.Unfold.Types (Unfold)
555import Streamly.Internal.Memory.Array.Types (Array, writeNUnsafe)
556-- import Streamly.Memory.Ring (Ring)
557import Streamly.Internal.Data.SVar (MonadAsync, defState, Rate)
558import Streamly.Internal.Data.Stream.Combinators (inspectMode, maxYields)
559import Streamly.Internal.Data.Stream.Prelude
560 (fromStreamS, toStreamS, foldWith, foldMapWith, forEachWith)
561import Streamly.Internal.Data.Stream.StreamD (fromStreamD, toStreamD)
562import Streamly.Internal.Data.Stream.StreamK (IsStream((|:), consM))
563import Streamly.Internal.Data.Stream.Serial (SerialT, WSerialT)
564import Streamly.Internal.Data.Stream.Zip (ZipSerialM)
565import Streamly.Internal.Data.Pipe.Types (Pipe (..))
566import Streamly.Internal.Data.Time.Units
567 (AbsTime, MilliSecond64(..), addToAbsTime, toRelTime,
568 toAbsTime, TimeUnit64, RelTime64, addToAbsTime64)
569import Streamly.Internal.Mutable.Prim.Var (Prim, Var)
571import Streamly.Internal.Data.Strict
573import qualified Streamly.Internal.Memory.Array as A
574import qualified Streamly.Data.Fold as FL
575import qualified Streamly.Internal.Data.Fold.Types as FL
576import qualified Streamly.Internal.Data.Stream.Prelude as P
577import qualified Streamly.Internal.Data.Stream.StreamK as K
578import qualified Streamly.Internal.Data.Stream.StreamD as D
580#ifdef USE_STREAMK_ONLY
581import qualified Streamly.Internal.Data.Stream.StreamK as S
582#else
583import qualified Streamly.Internal.Data.Stream.StreamD as S
584#endif
586-- import qualified Streamly.Internal.Data.Stream.Async as Async
587import qualified Streamly.Internal.Data.Stream.Serial as Serial
588import qualified Streamly.Internal.Data.Stream.Parallel as Par
589import qualified Streamly.Internal.Data.Stream.Zip as Z
590import qualified Streamly.Internal.Data.Parser.ParserK.Types as PRK
591import qualified Streamly.Internal.Data.Parser.ParserD as PRD
593------------------------------------------------------------------------------
594-- Deconstruction
595------------------------------------------------------------------------------
597-- | Decompose a stream into its head and tail. If the stream is empty, returns
598-- 'Nothing'. If the stream is non-empty, returns @Just (a, ma)@, where @a@ is
599-- the head of the stream and @ma@ its tail.
600--
601-- This is a brute force primitive. Avoid using it as long as possible, use it
602-- when no other combinator can do the job. This can be used to do pretty much
603-- anything in an imperative manner, as it just breaks down the stream into
604-- individual elements and we can loop over them as we deem fit. For example,
605-- this can be used to convert a streamly stream into other stream types.
606--
607-- @since 0.1.0
608{-# INLINE uncons #-}
609uncons :: (IsStream t, Monad m) => SerialT m a -> m (Maybe (a, t m a))
610uncons m = K.uncons (K.adapt m)
612------------------------------------------------------------------------------
613-- Generation by Unfolding
614------------------------------------------------------------------------------
616-- |
617-- @
618-- unfoldr step s =
619-- case step s of
620-- Nothing -> 'K.nil'
621-- Just (a, b) -> a \`cons` unfoldr step b
622-- @
623--
624-- Build a stream by unfolding a /pure/ step function @step@ starting from a
625-- seed @s@. The step function returns the next element in the stream and the
626-- next seed value. When it is done it returns 'Nothing' and the stream ends.
627-- For example,
628--
629-- @
630-- let f b =
631-- if b > 3
632-- then Nothing
633-- else Just (b, b + 1)
634-- in toList $ unfoldr f 0
635-- @
636-- @
637-- [0,1,2,3]
638-- @
639--
640-- @since 0.1.0
641{-# INLINE_EARLY unfoldr #-}
642unfoldr :: (Monad m, IsStream t) => (b -> Maybe (a, b)) -> b -> t m a
643unfoldr step seed = fromStreamS (S.unfoldr step seed)
644{-# RULES "unfoldr fallback to StreamK" [1]
645 forall a b. S.toStreamK (S.unfoldr a b) = K.unfoldr a b #-}
647-- | Build a stream by unfolding a /monadic/ step function starting from a
648-- seed. The step function returns the next element in the stream and the next
649-- seed value. When it is done it returns 'Nothing' and the stream ends. For
650-- example,
651--
652-- @
653-- let f b =
654-- if b > 3
655-- then return Nothing
656-- else print b >> return (Just (b, b + 1))
657-- in drain $ unfoldrM f 0
658-- @
659-- @
660-- 0
661-- 1
662-- 2
663-- 3
664-- @
665-- When run concurrently, the next unfold step can run concurrently with the
666-- processing of the output of the previous step. Note that more than one step
667-- cannot run concurrently as the next step depends on the output of the
668-- previous step.
669--
670-- @
671-- (asyncly $ S.unfoldrM (\\n -> liftIO (threadDelay 1000000) >> return (Just (n, n + 1))) 0)
672-- & S.foldlM' (\\_ a -> threadDelay 1000000 >> print a) ()
673-- @
674--
675-- /Concurrent/
676--
677-- /Since: 0.1.0/
678{-# INLINE_EARLY unfoldrM #-}
679unfoldrM :: (IsStream t, MonadAsync m) => (b -> m (Maybe (a, b))) -> b -> t m a
680unfoldrM = K.unfoldrM
682{-# RULES "unfoldrM serial" unfoldrM = unfoldrMSerial #-}
683{-# INLINE_EARLY unfoldrMSerial #-}
684unfoldrMSerial :: MonadAsync m => (b -> m (Maybe (a, b))) -> b -> SerialT m a
685unfoldrMSerial = Serial.unfoldrM
687{-# RULES "unfoldrM wSerial" unfoldrM = unfoldrMWSerial #-}
688{-# INLINE_EARLY unfoldrMWSerial #-}
689unfoldrMWSerial :: MonadAsync m => (b -> m (Maybe (a, b))) -> b -> WSerialT m a
690unfoldrMWSerial = Serial.unfoldrM
692{-# RULES "unfoldrM zipSerial" unfoldrM = unfoldrMZipSerial #-}
693{-# INLINE_EARLY unfoldrMZipSerial #-}
694unfoldrMZipSerial :: MonadAsync m => (b -> m (Maybe (a, b))) -> b -> ZipSerialM m a
695unfoldrMZipSerial = Serial.unfoldrM
697-- | Convert an 'Unfold' into a stream by supplying it an input seed.
698--
699-- >>> unfold (UF.replicateM 10) (putStrLn "hello")
700--
701-- /Since: 0.7.0/
702{-# INLINE unfold #-}
703unfold :: (IsStream t, Monad m) => Unfold m a b -> a -> t m b
704unfold unf x = fromStreamD $ D.unfold unf x
706-- | Convert an 'Unfold' with a closed input end into a stream.
707--
708-- /Internal/
709{-# INLINE unfold0 #-}
710unfold0 :: (IsStream t, Monad m) => Unfold m Void b -> t m b
711unfold0 unf = unfold unf (error "unfold0: unexpected void evaluation")
713------------------------------------------------------------------------------
714-- Specialized Generation
715------------------------------------------------------------------------------
717-- Faster than yieldM because there is no bind.
718--
719-- |
720-- @
721-- yield a = a \`cons` nil
722-- @
723--
724-- Create a singleton stream from a pure value.
725--
726-- The following holds in monadic streams, but not in Zip streams:
727--
728-- @
729-- yield = pure
730-- yield = yieldM . pure
731-- @
732--
733-- In Zip applicative streams 'yield' is not the same as 'pure' because in that
734-- case 'pure' is equivalent to 'repeat' instead. 'yield' and 'pure' are
735-- equally efficient, in other cases 'yield' may be slightly more efficient
736-- than the other equivalent definitions.
737--
738-- @since 0.4.0
739{-# INLINE yield #-}
740yield :: IsStream t => a -> t m a
741yield = K.yield
743-- |
744-- @
745-- yieldM m = m \`consM` nil
746-- @
747--
748-- Create a singleton stream from a monadic action.
749--
750-- @
751-- > toList $ yieldM getLine
752-- hello
753-- ["hello"]
754-- @
755--
756-- @since 0.4.0
757{-# INLINE yieldM #-}
758yieldM :: (Monad m, IsStream t) => m a -> t m a
759yieldM = K.yieldM
761-- |
762-- @
763-- fromIndices f = let g i = f i \`cons` g (i + 1) in g 0
764-- @
765--
766-- Generate an infinite stream, whose values are the output of a function @f@
767-- applied on the corresponding index. Index starts at 0.
768--
769-- @
770-- > S.toList $ S.take 5 $ S.fromIndices id
771-- [0,1,2,3,4]
772-- @
773--
774-- @since 0.6.0
775{-# INLINE fromIndices #-}
776fromIndices :: (IsStream t, Monad m) => (Int -> a) -> t m a
777fromIndices = fromStreamS . S.fromIndices
779--
780-- |
781-- @
782-- fromIndicesM f = let g i = f i \`consM` g (i + 1) in g 0
783-- @
784--
785-- Generate an infinite stream, whose values are the output of a monadic
786-- function @f@ applied on the corresponding index. Index starts at 0.
787--
788-- /Concurrent/
789--
790-- @since 0.6.0
791{-# INLINE_EARLY fromIndicesM #-}
792fromIndicesM :: (IsStream t, MonadAsync m) => (Int -> m a) -> t m a
793fromIndicesM = K.fromIndicesM
795{-# RULES "fromIndicesM serial" fromIndicesM = fromIndicesMSerial #-}
796{-# INLINE fromIndicesMSerial #-}
797fromIndicesMSerial :: MonadAsync m => (Int -> m a) -> SerialT m a
798fromIndicesMSerial = fromStreamS . S.fromIndicesM
800-- |
801-- @
802-- replicateM = take n . repeatM
803-- @
804--
805-- Generate a stream by performing a monadic action @n@ times. Same as:
806--
807-- @
808-- drain $ serially $ S.replicateM 10 $ (threadDelay 1000000 >> print 1)
809-- drain $ asyncly $ S.replicateM 10 $ (threadDelay 1000000 >> print 1)
810-- @
811--
812-- /Concurrent/
813--
814-- @since 0.1.1
815{-# INLINE_EARLY replicateM #-}
816replicateM :: (IsStream t, MonadAsync m) => Int -> m a -> t m a
817replicateM = K.replicateM
819{-# RULES "replicateM serial" replicateM = replicateMSerial #-}
820{-# INLINE replicateMSerial #-}
821replicateMSerial :: MonadAsync m => Int -> m a -> SerialT m a
822replicateMSerial n = fromStreamS . S.replicateM n
824-- |
825-- @
826-- replicate = take n . repeat
827-- @
828--
829-- Generate a stream of length @n@ by repeating a value @n@ times.
830--
831-- @since 0.6.0
832{-# INLINE_NORMAL replicate #-}
833replicate :: (IsStream t, Monad m) => Int -> a -> t m a
834replicate n = fromStreamS . S.replicate n
836-- |
837-- Generate an infinite stream by repeating a pure value.
838--
839-- @since 0.4.0
840{-# INLINE_NORMAL repeat #-}
841repeat :: (IsStream t, Monad m) => a -> t m a
842repeat = fromStreamS . S.repeat
844-- |
845-- @
846-- repeatM = fix . consM
847-- repeatM = cycle1 . yieldM
848-- @
849--
850-- Generate a stream by repeatedly executing a monadic action forever.
851--
852-- @
853-- drain $ serially $ S.take 10 $ S.repeatM $ (threadDelay 1000000 >> print 1)
854-- drain $ asyncly $ S.take 10 $ S.repeatM $ (threadDelay 1000000 >> print 1)
855-- @
856--
857-- /Concurrent, infinite (do not use with 'parallely')/
858--
859-- @since 0.2.0
860{-# INLINE_EARLY repeatM #-}
861repeatM :: (IsStream t, MonadAsync m) => m a -> t m a
862repeatM = K.repeatM
864{-# RULES "repeatM serial" repeatM = repeatMSerial #-}
865{-# INLINE repeatMSerial #-}
866repeatMSerial :: MonadAsync m => m a -> SerialT m a
867repeatMSerial = fromStreamS . S.repeatM
869-- |
870-- @
871-- iterate f x = x \`cons` iterate f x
872-- @
873--
874-- Generate an infinite stream with @x@ as the first element and each
875-- successive element derived by applying the function @f@ on the previous
876-- element.
877--
878-- @
879-- > S.toList $ S.take 5 $ S.iterate (+1) 1
880-- [1,2,3,4,5]
881-- @
882--
883-- @since 0.1.2
884{-# INLINE_NORMAL iterate #-}
885iterate :: (IsStream t, Monad m) => (a -> a) -> a -> t m a
886iterate step = fromStreamS . S.iterate step
888-- |
889-- @
890-- iterateM f m = m >>= \a -> return a \`consM` iterateM f (f a)
891-- @
892--
893-- Generate an infinite stream with the first element generated by the action
894-- @m@ and each successive element derived by applying the monadic function
895-- @f@ on the previous element.
896--
897-- When run concurrently, the next iteration can run concurrently with the
898-- processing of the previous iteration. Note that more than one iteration
899-- cannot run concurrently as the next iteration depends on the output of the
900-- previous iteration.
901--
902-- @
903-- drain $ serially $ S.take 10 $ S.iterateM
904-- (\\x -> threadDelay 1000000 >> print x >> return (x + 1)) (return 0)
905--
906-- drain $ asyncly $ S.take 10 $ S.iterateM
907-- (\\x -> threadDelay 1000000 >> print x >> return (x + 1)) (return 0)
908-- @
909--
910-- /Concurrent/
911--
912-- /Since: 0.7.0 (signature change)/
913--
914-- /Since: 0.1.2/
915{-# INLINE_EARLY iterateM #-}
916iterateM :: (IsStream t, MonadAsync m) => (a -> m a) -> m a -> t m a
917iterateM = K.iterateM
919{-# RULES "iterateM serial" iterateM = iterateMSerial #-}
920{-# INLINE iterateMSerial #-}
921iterateMSerial :: MonadAsync m => (a -> m a) -> m a -> SerialT m a
922iterateMSerial step = fromStreamS . S.iterateM step
924------------------------------------------------------------------------------
925-- Conversions
926------------------------------------------------------------------------------
928-- |
929-- @
930-- fromListM = 'Prelude.foldr' 'K.consM' 'K.nil'
931-- @
932--
933-- Construct a stream from a list of monadic actions. This is more efficient
934-- than 'fromFoldableM' for serial streams.
935--
936-- @since 0.4.0
937{-# INLINE_EARLY fromListM #-}
938fromListM :: (MonadAsync m, IsStream t) => [m a] -> t m a
939fromListM = fromStreamD . D.fromListM
940{-# RULES "fromListM fallback to StreamK" [1]
941 forall a. D.toStreamK (D.fromListM a) = fromFoldableM a #-}
943-- |
944-- @
945-- fromFoldableM = 'Prelude.foldr' 'consM' 'K.nil'
946-- @
947--
948-- Construct a stream from a 'Foldable' containing monadic actions.
949--
950-- @
951-- drain $ serially $ S.fromFoldableM $ replicateM 10 (threadDelay 1000000 >> print 1)
952-- drain $ asyncly $ S.fromFoldableM $ replicateM 10 (threadDelay 1000000 >> print 1)
953-- @
954--
955-- /Concurrent (do not use with 'parallely' on infinite containers)/
956--
957-- @since 0.3.0
958{-# INLINE fromFoldableM #-}
959fromFoldableM :: (IsStream t, MonadAsync m, Foldable f) => f (m a) -> t m a
960fromFoldableM = Prelude.foldr consM K.nil
962-- | Same as 'fromFoldable'.
963--
964-- @since 0.1.0
965{-# DEPRECATED each "Please use fromFoldable instead." #-}
966{-# INLINE each #-}
967each :: (IsStream t, Foldable f) => f a -> t m a
968each = K.fromFoldable
970-- | Read lines from an IO Handle into a stream of Strings.
971--
972-- @since 0.1.0
973{-# DEPRECATED fromHandle
974 "Please use Streamly.FileSystem.Handle module (see the changelog)" #-}
975fromHandle :: (IsStream t, MonadIO m) => IO.Handle -> t m String
976fromHandle h = go
977 where
978 go = K.mkStream $ \_ yld _ stp -> do
979 eof <- liftIO $ IO.hIsEOF h
980 if eof
981 then stp
982 else do
983 str <- liftIO $ IO.hGetLine h
984 yld str go
986-- | Construct a stream by reading a 'Prim' 'Var' repeatedly.
987--
988-- /Internal/
989--
990{-# INLINE fromPrimVar #-}
991fromPrimVar :: (IsStream t, MonadIO m, Prim a) => Var IO a -> t m a
992fromPrimVar = fromStreamD . D.fromPrimVar
994-- | Takes a callback setter function and provides it with a callback. The
995-- callback when invoked adds a value at the tail of the stream. Returns a
996-- stream of values generated by the callback.
997--
998-- /Internal/
999--
1000{-# INLINE fromCallback #-}
1001fromCallback :: MonadAsync m => ((a -> m ()) -> m ()) -> SerialT m a
1002fromCallback setCallback = concatM $ do
1003 (callback, stream) <- D.newCallbackStream
1004 setCallback callback
1005 return stream
1007------------------------------------------------------------------------------
1008-- Time related
1009------------------------------------------------------------------------------
1011-- | @timesWith g@ returns a stream of time value tuples. The first component
1012-- of the tuple is an absolute time reference (epoch) denoting the start of the
1013-- stream and the second component is a time relative to the reference.
1015-- The argument @g@ specifies the granularity of the relative time in seconds.
1016-- A lower granularity clock gives higher precision but is more expensive in
1017-- terms of CPU usage. Any granularity lower than 1 ms is treated as 1 ms.
1019-- @
1020-- >>> S.mapM_ (\x -> print x >> threadDelay 1000000) $ S.timesWith 0.01
1021-- > (AbsTime (TimeSpec {sec = 2496295, nsec = 536223000}),RelTime64 (NanoSecond64 0))
1022-- > (AbsTime (TimeSpec {sec = 2496295, nsec = 536223000}),RelTime64 (NanoSecond64 1002028000))
1023-- > (AbsTime (TimeSpec {sec = 2496295, nsec = 536223000}),RelTime64 (NanoSecond64 1996656000))
1024-- @
1026-- Note: This API is not safe on 32-bit machines.
1028-- /Internal/
1030{-# INLINE timesWith #-}
1031timesWith :: (IsStream t, MonadAsync m) => Double -> t m (AbsTime, RelTime64)
1032timesWith g = fromStreamD $ D.times g
1034-- | @times@ returns a stream of time value tuples with clock of 10 ms
1035-- granularity. The first component of the tuple is an absolute time reference
1036-- (epoch) denoting the start of the stream and the second component is a time
1037-- relative to the reference.
1039-- @
1040-- >>> S.mapM_ (\x -> print x >> threadDelay 1000000) $ S.times
1041-- > (AbsTime (TimeSpec {sec = 2496295, nsec = 536223000}),RelTime64 (NanoSecond64 0))
1042-- > (AbsTime (TimeSpec {sec = 2496295, nsec = 536223000}),RelTime64 (NanoSecond64 1002028000))
1043-- > (AbsTime (TimeSpec {sec = 2496295, nsec = 536223000}),RelTime64 (NanoSecond64 1996656000))
1044-- @
1046-- Note: This API is not safe on 32-bit machines.
1048-- /Internal/
1050{-# INLINE times #-}
1051times :: (IsStream t, MonadAsync m) => t m (AbsTime, RelTime64)
1052times = timesWith 0.01
1054-- | @absTimesWith g@ returns a stream of absolute timestamps using a clock of
1055-- granularity @g@ specified in seconds. A low granularity clock is more
1056-- expensive in terms of CPU usage. Any granularity lower than 1 ms is treated
1057-- as 1 ms.
1059-- @
1060-- >>> S.mapM_ print $ S.delayPre 1 $ S.absTimesWith 0.01
1061-- @
1063-- Note: This API is not safe on 32-bit machines.
1065-- /Internal/
1067{-# INLINE absTimesWith #-}
1068absTimesWith :: (IsStream t, MonadAsync m, Functor (t m))
1069 => Double -> t m AbsTime
1070absTimesWith = fmap (uncurry addToAbsTime64) . timesWith
1072-- | @absTimes@ returns a stream of absolute timestamps using a clock of 10 ms
1073-- granularity.
1075-- @
1076-- >>> S.mapM_ print $ S.delayPre 1 $ S.absTimes
1077-- @
1079-- Note: This API is not safe on 32-bit machines.
1081-- /Internal/
1083{-# INLINE absTimes #-}
1084absTimes :: (IsStream t, MonadAsync m, Functor (t m)) => t m AbsTime
1085absTimes = fmap (uncurry addToAbsTime64) times
1087{-# DEPRECATED currentTime "Please use absTimes instead" #-}
1088{-# INLINE currentTime #-}
1089currentTime :: (IsStream t, MonadAsync m, Functor (t m))
1090 => Double -> t m AbsTime
1091currentTime = absTimesWith
1093-- | @relTimesWith g@ returns a stream of relative time values starting from 0,
1094-- using a clock of granularity @g@ specified in seconds. A low granularity
1095-- clock is more expensive in terms of CPU usage. Any granularity lower than 1
1096-- ms is treated as 1 ms.
1098-- @
1099-- >>> S.mapM_ print $ S.delayPre 1 $ S.relTimesWith 0.01
1100-- > RelTime64 (NanoSecond64 0)
1101-- > RelTime64 (NanoSecond64 91139000)
1102-- > RelTime64 (NanoSecond64 204052000)
1103-- @
1105-- Note: This API is not safe on 32-bit machines.
1107-- /Internal/
1109{-# INLINE relTimesWith #-}
1110relTimesWith :: (IsStream t, MonadAsync m, Functor (t m))
1111 => Double -> t m RelTime64
1112relTimesWith = fmap snd . timesWith
1114-- | @relTimes@ returns a stream of relative time values starting from 0,
1115-- using a clock of granularity 10 ms.
1117-- @
1118-- >>> S.mapM_ print $ S.delayPre 1 $ S.relTimes
1119-- @
1121-- Note: This API is not safe on 32-bit machines.
1123-- /Internal/
1125{-# INLINE relTimes #-}
1126relTimes :: (IsStream t, MonadAsync m, Functor (t m)) => t m RelTime64
1127relTimes = fmap snd times
1129-- | @durations g@ returns a stream of relative time values measuring the time
1130-- elapsed since the immediate predecessor element of the stream was generated.
1131-- The first element of the stream is always 0. @durations@ uses a clock of
1132-- granularity @g@ specified in seconds. A low granularity clock is more
1133-- expensive in terms of CPU usage. The minimum granularity is 1 millisecond.
1134-- Durations lower than 1 ms will be 0.
1136-- Note: This API is not safe on 32-bit machines.
1138-- /Unimplemented/
1140{-# INLINE durations #-}
1141durations :: -- (IsStream t, MonadAsync m) =>
1142 Double -> t m RelTime64
1143durations = undefined
1145-- | Generate ticks at the specified rate. The rate is adaptive, the tick
1146-- generation speed can be increased or decreased at different times to achieve
1147-- the specified rate. The specific behavior for different styles of 'Rate'
1148-- specifications is documented under 'Rate'. The effective maximum rate
1149-- achieved by a stream is governed by the processor speed.
1151-- /Unimplemented/
1153{-# INLINE ticks #-}
1154ticks :: -- (IsStream t, MonadAsync m) =>
1155 Rate -> t m ()
1156ticks = undefined
1158-- | Generate a singleton event at or after the specified absolute time. Note
1159-- that this is different from a threadDelay, a threadDelay starts from the
1160-- time when the action is evaluated, whereas if we use AbsTime based timeout
1161-- it will immediately expire if the action is evaluated too late.
1163-- /Unimplemented/
1165{-# INLINE timeout #-}
1166timeout :: -- (IsStream t, MonadAsync m) =>
1167 AbsTime -> t m ()
1168timeout = undefined
1170------------------------------------------------------------------------------
1171-- Elimination by Folding
1172------------------------------------------------------------------------------
1174-- | Right associative/lazy pull fold. @foldrM build final stream@ constructs
1175-- an output structure using the step function @build@. @build@ is invoked with
1176-- the next input element and the remaining (lazy) tail of the output
1177-- structure. It builds a lazy output expression using the two. When the "tail
1178-- structure" in the output expression is evaluated it calls @build@ again thus
1179-- lazily consuming the input @stream@ until either the output expression built
1180-- by @build@ is free of the "tail" or the input is exhausted in which case
1181-- @final@ is used as the terminating case for the output structure. For more
1182-- details see the description in the previous section.
1184-- Example, determine if any element is 'odd' in a stream:
1186-- >>> S.foldrM (\x xs -> if odd x then return True else xs) (return False) $ S.fromList (2:4:5:undefined)
1187-- > True
1189-- /Since: 0.7.0 (signature changed)/
1191-- /Since: 0.2.0 (signature changed)/
1193-- /Since: 0.1.0/
1194{-# INLINE foldrM #-}
1195foldrM :: Monad m => (a -> m b -> m b) -> m b -> SerialT m a -> m b
1196foldrM = P.foldrM
1198-- | Right fold to a streaming monad.
1200-- > foldrS S.cons S.nil === id
1202-- 'foldrS' can be used to perform stateless stream to stream transformations
1203-- like map and filter in general. It can be coupled with a scan to perform
1204-- stateful transformations. However, note that the custom map and filter
1205-- routines can be much more efficient than this due to better stream fusion.
1207-- >>> S.toList $ S.foldrS S.cons S.nil $ S.fromList [1..5]
1208-- > [1,2,3,4,5]
1210-- Find if any element in the stream is 'True':
1212-- >>> 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)
1213-- > [True]
1215-- Map (+2) on odd elements and filter out the even elements:
1217-- >>> 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)
1218-- > [3,5,7]
1220-- 'foldrM' can also be represented in terms of 'foldrS', however, the former
1221-- is much more efficient:
1223-- > foldrM f z s = runIdentityT $ foldrS (\x xs -> lift $ f x (runIdentityT xs)) (lift z) s
1225-- /Internal/
1226{-# INLINE foldrS #-}
1227foldrS :: IsStream t => (a -> t m b -> t m b) -> t m b -> t m a -> t m b
1228foldrS = K.foldrS
1230-- | Right fold to a transformer monad. This is the most general right fold
1231-- function. 'foldrS' is a special case of 'foldrT', however 'foldrS'
1232-- implementation can be more efficient:
1234-- > foldrS = foldrT
1235-- > foldrM f z s = runIdentityT $ foldrT (\x xs -> lift $ f x (runIdentityT xs)) (lift z) s
1237-- 'foldrT' can be used to translate streamly streams to other transformer
1238-- monads e.g. to a different streaming type.
1240-- /Internal/
1241{-# INLINE foldrT #-}
1242foldrT :: (IsStream t, Monad m, Monad (s m), MonadTrans s)
1243 => (a -> s m b -> s m b) -> s m b -> t m a -> s m b
1244foldrT f z s = S.foldrT f z (toStreamS s)
1246-- | Right fold, lazy for lazy monads and pure streams, and strict for strict
1247-- monads.
1249-- Please avoid using this routine in strict monads like IO unless you need a
1250-- strict right fold. This is provided only for use in lazy monads (e.g.
1251-- Identity) or pure streams. Note that with this signature it is not possible
1252-- to implement a lazy foldr when the monad @m@ is strict. In that case it
1253-- would be strict in its accumulator and therefore would necessarily consume
1254-- all its input.
1256-- @since 0.1.0
1257{-# INLINE foldr #-}
1258foldr :: Monad m => (a -> b -> b) -> b -> SerialT m a -> m b
1259foldr = P.foldr
1261-- XXX This seems to be of limited use as it cannot be used to construct
1262-- recursive structures and for reduction foldl1' is better.
1264-- | Lazy right fold for non-empty streams, using first element as the starting
1265-- value. Returns 'Nothing' if the stream is empty.
1267-- @since 0.5.0
1268{-# INLINE foldr1 #-}
1269{-# DEPRECATED foldr1 "Use foldrM instead." #-}
1270foldr1 :: Monad m => (a -> a -> a) -> SerialT m a -> m (Maybe a)
1271foldr1 f m = S.foldr1 f (toStreamS m)
1273-- | Strict left fold with an extraction function. Like the standard strict
1274-- left fold, but applies a user supplied extraction function (the third
1275-- argument) to the folded value at the end. This is designed to work with the
1276-- @foldl@ library. The suffix @x@ is a mnemonic for extraction.
1278-- @since 0.2.0
1279{-# DEPRECATED foldx "Please use foldl' followed by fmap instead." #-}
1280{-# INLINE foldx #-}
1281foldx :: Monad m => (x -> a -> x) -> x -> (x -> b) -> SerialT m a -> m b
1282foldx = P.foldlx'
1284-- | Left associative/strict push fold. @foldl' reduce initial stream@ invokes
1285-- @reduce@ with the accumulator and the next input in the input stream, using
1286-- @initial@ as the initial value of the current value of the accumulator. When
1287-- the input is exhausted the current value of the accumulator is returned.
1288-- Make sure to use a strict data structure for accumulator to not build
1289-- unnecessary lazy expressions unless that's what you want. See the previous
1290-- section for more details.
1292-- @since 0.2.0
1293{-# INLINE foldl' #-}
1294foldl' :: Monad m => (b -> a -> b) -> b -> SerialT m a -> m b
1295foldl' = P.foldl'
1297-- | Strict left fold, for non-empty streams, using first element as the
1298-- starting value. Returns 'Nothing' if the stream is empty.
1300-- @since 0.5.0
1301{-# INLINE foldl1' #-}
1302foldl1' :: Monad m => (a -> a -> a) -> SerialT m a -> m (Maybe a)
1303foldl1' step m = do
1304 r <- uncons m
1305 case r of
1306 Nothing -> return Nothing
1307 Just (h, t) -> do
1308 res <- foldl' step h t
1309 return $ Just res
1311-- | Like 'foldx', but with a monadic step function.
1313-- @since 0.2.0
1314{-# DEPRECATED foldxM "Please use foldlM' followed by fmap instead." #-}
1315{-# INLINE foldxM #-}
1316foldxM :: Monad m => (x -> a -> m x) -> m x -> (x -> m b) -> SerialT m a -> m b
1317foldxM = P.foldlMx'
1319-- | Like 'foldl'' but with a monadic step function.
1321-- @since 0.2.0
1322{-# INLINE foldlM' #-}
1323foldlM' :: Monad m => (b -> a -> m b) -> m b -> SerialT m a -> m b
1324foldlM' step begin m = S.foldlM' step begin $ toStreamS m
1326------------------------------------------------------------------------------
1327-- Running a Fold
1328------------------------------------------------------------------------------
1330-- | Fold a stream using the supplied left fold.
1332-- >>> S.fold FL.sum (S.enumerateFromTo 1 100)
1333-- 5050
1335-- @since 0.7.0
1336{-# INLINE fold #-}
1337fold :: Monad m => Fold m a b -> SerialT m a -> m b
1338fold = P.runFold
1340------------------------------------------------------------------------------
1341-- Running a sink
1342------------------------------------------------------------------------------
1345-- | Drain a stream to a 'Sink'.
1346{-# INLINE runSink #-}
1347runSink :: Monad m => Sink m a -> SerialT m a -> m ()
1348runSink = fold . toFold
1351------------------------------------------------------------------------------
1352-- Running a Parser
1353------------------------------------------------------------------------------
1355-- | Parse a stream using the supplied 'Parser'.
1357-- /Internal/
1359{-# INLINE_NORMAL parseD #-}
1360parseD :: MonadThrow m => PRD.Parser m a b -> SerialT m a -> m b
1361parseD (PRD.Parser step initial extract) = P.parselMx' step initial extract
1363{-# INLINE parseK #-}
1364parseK :: MonadThrow m => PRK.Parser m a b -> SerialT m a -> m b
1365parseK = parse
1367-- | Parse a stream using the supplied 'Parser'.
1369-- /Internal/
1371{-# INLINE [3] parse #-}
1372parse :: MonadThrow m => Parser m a b -> SerialT m a -> m b
1373parse = parseD . PRK.fromParserK
1375------------------------------------------------------------------------------
1376-- Specialized folds
1377------------------------------------------------------------------------------
1379-- |
1380-- > drain = mapM_ (\_ -> return ())
1382-- Run a stream, discarding the results. By default it interprets the stream
1383-- as 'SerialT', to run other types of streams use the type adapting
1384-- combinators for example @drain . 'asyncly'@.
1386-- @since 0.7.0
1387{-# INLINE drain #-}
1388drain :: Monad m => SerialT m a -> m ()
1389drain = P.drain
1391-- | Run a stream, discarding the results. By default it interprets the stream
1392-- as 'SerialT', to run other types of streams use the type adapting
1393-- combinators for example @runStream . 'asyncly'@.
1395-- @since 0.2.0
1396{-# DEPRECATED runStream "Please use \"drain\" instead" #-}
1397{-# INLINE runStream #-}
1398runStream :: Monad m => SerialT m a -> m ()
1399runStream = drain
1401-- |
1402-- > drainN n = drain . take n
1404-- Run maximum up to @n@ iterations of a stream.
1406-- @since 0.7.0
1407{-# INLINE drainN #-}
1408drainN :: Monad m => Int -> SerialT m a -> m ()
1409drainN n = drain . take n
1411-- |
1412-- > runN n = runStream . take n
1414-- Run maximum up to @n@ iterations of a stream.
1416-- @since 0.6.0
1417{-# DEPRECATED runN "Please use \"drainN\" instead" #-}
1418{-# INLINE runN #-}
1419runN :: Monad m => Int -> SerialT m a -> m ()
1420runN = drainN
1422-- |
1423-- > drainWhile p = drain . takeWhile p
1425-- Run a stream as long as the predicate holds true.
1427-- @since 0.7.0
1428{-# INLINE drainWhile #-}
1429drainWhile :: Monad m => (a -> Bool) -> SerialT m a -> m ()
1430drainWhile p = drain . takeWhile p
1432-- |
1433-- > runWhile p = runStream . takeWhile p
1435-- Run a stream as long as the predicate holds true.
1437-- @since 0.6.0
1438{-# DEPRECATED runWhile "Please use \"drainWhile\" instead" #-}
1439{-# INLINE runWhile #-}
1440runWhile :: Monad m => (a -> Bool) -> SerialT m a -> m ()
1441runWhile = drainWhile
1443-- | Determine whether the stream is empty.
1445-- @since 0.1.1
1446{-# INLINE null #-}
1447null :: Monad m => SerialT m a -> m Bool
1448null = S.null . toStreamS
1450-- | Extract the first element of the stream, if any.
1452-- > head = (!! 0)
1454-- @since 0.1.0
1455{-# INLINE head #-}
1456head :: Monad m => SerialT m a -> m (Maybe a)
1457head = S.head . toStreamS
1459-- | Extract the first element of the stream, if any, otherwise use the
1460-- supplied default value. It can help avoid one branch in high performance
1461-- code.
1463-- /Internal/
1464{-# INLINE headElse #-}
1465headElse :: Monad m => a -> SerialT m a -> m a
1466headElse x = D.headElse x . toStreamD
1468-- |
1469-- > tail = fmap (fmap snd) . uncons
1471-- Extract all but the first element of the stream, if any.
1473-- @since 0.1.1
1474{-# INLINE tail #-}
1475tail :: (IsStream t, Monad m) => SerialT m a -> m (Maybe (t m a))
1476tail m = K.tail (K.adapt m)
1478-- | Extract all but the last element of the stream, if any.
1480-- @since 0.5.0
1481{-# INLINE init #-}
1482init :: (IsStream t, Monad m) => SerialT m a -> m (Maybe (t m a))
1483init m = K.init (K.adapt m)
1485-- | Extract the last element of the stream, if any.
1487-- > last xs = xs !! (length xs - 1)
1489-- @since 0.1.1
1490{-# INLINE last #-}
1491last :: Monad m => SerialT m a -> m (Maybe a)
1492last m = S.last $ toStreamS m
1494-- | Determine whether an element is present in the stream.
1496-- @since 0.1.0
1497{-# INLINE elem #-}
1498elem :: (Monad m, Eq a) => a -> SerialT m a -> m Bool
1499elem e m = S.elem e (toStreamS m)
1501-- | Determine whether an element is not present in the stream.
1503-- @since 0.1.0
1504{-# INLINE notElem #-}
1505notElem :: (Monad m, Eq a) => a -> SerialT m a -> m Bool
1506notElem e m = S.notElem e (toStreamS m)
1508-- | Determine the length of the stream.
1510-- @since 0.1.0
1511{-# INLINE length #-}
1512length :: Monad m => SerialT m a -> m Int
1513length = foldl' (\n _ -> n + 1) 0
1515-- | Determine whether all elements of a stream satisfy a predicate.
1517-- @since 0.1.0
1518{-# INLINE all #-}
1519all :: Monad m => (a -> Bool) -> SerialT m a -> m Bool
1520all p m = S.all p (toStreamS m)
1522-- | Determine whether any of the elements of a stream satisfy a predicate.
1524-- @since 0.1.0
1525{-# INLINE any #-}
1526any :: Monad m => (a -> Bool) -> SerialT m a -> m Bool
1527any p m = S.any p (toStreamS m)
1529-- | Determines if all elements of a boolean stream are True.
1531-- @since 0.5.0
1532{-# INLINE and #-}
1533and :: Monad m => SerialT m Bool -> m Bool
1534and = all (==True)
1536-- | Determines whether at least one element of a boolean stream is True.
1538-- @since 0.5.0
1539{-# INLINE or #-}
1540or :: Monad m => SerialT m Bool -> m Bool
1541or = any (==True)
1543-- | Determine the sum of all elements of a stream of numbers. Returns @0@ when
1544-- the stream is empty. Note that this is not numerically stable for floating
1545-- point numbers.
1547-- @since 0.1.0
1548{-# INLINE sum #-}
1549sum :: (Monad m, Num a) => SerialT m a -> m a
1550sum = foldl' (+) 0
1552-- | Determine the product of all elements of a stream of numbers. Returns @1@
1553-- when the stream is empty.
1555-- @since 0.1.1
1556{-# INLINE product #-}
1557product :: (Monad m, Num a) => SerialT m a -> m a
1558product = foldl' (*) 1
1560-- | Fold a stream of monoid elements by appending them.
1562-- /Internal/
1563{-# INLINE mconcat #-}
1564mconcat :: (Monad m, Monoid a) => SerialT m a -> m a
1565mconcat = foldr mappend mempty
1567-- |
1568-- @
1569-- minimum = 'minimumBy' compare
1570-- @
1572-- Determine the minimum element in a stream.
1574-- @since 0.1.0
1575{-# INLINE minimum #-}
1576minimum :: (Monad m, Ord a) => SerialT m a -> m (Maybe a)
1577minimum m = S.minimum (toStreamS m)
1579-- | Determine the minimum element in a stream using the supplied comparison
1580-- function.
1582-- @since 0.6.0
1583{-# INLINE minimumBy #-}
1584minimumBy :: Monad m => (a -> a -> Ordering) -> SerialT m a -> m (Maybe a)
1585minimumBy cmp m = S.minimumBy cmp (toStreamS m)
1587-- |
1588-- @
1589-- maximum = 'maximumBy' compare
1590-- @
1592-- Determine the maximum element in a stream.
1594-- @since 0.1.0
1595{-# INLINE maximum #-}
1596maximum :: (Monad m, Ord a) => SerialT m a -> m (Maybe a)
1597maximum = P.maximum
1599-- | Determine the maximum element in a stream using the supplied comparison
1600-- function.
1602-- @since 0.6.0
1603{-# INLINE maximumBy #-}
1604maximumBy :: Monad m => (a -> a -> Ordering) -> SerialT m a -> m (Maybe a)
1605maximumBy cmp m = S.maximumBy cmp (toStreamS m)
1607-- | Lookup the element at the given index.
1609-- @since 0.6.0
1610{-# INLINE (!!) #-}
1611(!!) :: Monad m => SerialT m a -> Int -> m (Maybe a)
1612m !! i = toStreamS m S.!! i
1614-- | In a stream of (key-value) pairs @(a, b)@, return the value @b@ of the
1615-- first pair where the key equals the given value @a@.
1617-- > lookup = snd <$> find ((==) . fst)
1619-- @since 0.5.0
1620{-# INLINE lookup #-}
1621lookup :: (Monad m, Eq a) => a -> SerialT m (a, b) -> m (Maybe b)
1622lookup a m = S.lookup a (toStreamS m)
1624-- | Like 'findM' but with a non-monadic predicate.
1626-- > find p = findM (return . p)
1628-- @since 0.5.0
1629{-# INLINE find #-}
1630find :: Monad m => (a -> Bool) -> SerialT m a -> m (Maybe a)
1631find p m = S.find p (toStreamS m)
1633-- | Returns the first element that satisfies the given predicate.
1635-- @since 0.6.0
1636{-# INLINE findM #-}
1637findM :: Monad m => (a -> m Bool) -> SerialT m a -> m (Maybe a)
1638findM p m = S.findM p (toStreamS m)
1640-- | Find all the indices where the element in the stream satisfies the given
1641-- predicate.
1643-- @since 0.5.0
1644{-# INLINE findIndices #-}
1645findIndices :: (IsStream t, Monad m) => (a -> Bool) -> t m a -> t m Int
1646findIndices p m = fromStreamS $ S.findIndices p (toStreamS m)
1648-- | Returns the first index that satisfies the given predicate.
1650-- @since 0.5.0
1651{-# INLINE findIndex #-}
1652findIndex :: Monad m => (a -> Bool) -> SerialT m a -> m (Maybe Int)
1653findIndex p = head . findIndices p
1655-- | Find all the indices where the value of the element in the stream is equal
1656-- to the given value.
1658-- @since 0.5.0
1659{-# INLINE elemIndices #-}
1660elemIndices :: (IsStream t, Eq a, Monad m) => a -> t m a -> t m Int
1661elemIndices a = findIndices (==a)
1663-- | Returns the first index where a given value is found in the stream.
1665-- > elemIndex a = findIndex (== a)
1667-- @since 0.5.0
1668{-# INLINE elemIndex #-}
1669elemIndex :: (Monad m, Eq a) => a -> SerialT m a -> m (Maybe Int)
1670elemIndex a = findIndex (== a)
1672------------------------------------------------------------------------------
1673-- Substreams
1674------------------------------------------------------------------------------
1676-- | Returns 'True' if the first stream is the same as or a prefix of the
1677-- second. A stream is a prefix of itself.
1679-- @
1680-- > S.isPrefixOf (S.fromList "hello") (S.fromList "hello" :: SerialT IO Char)
1681-- True
1682-- @
1684-- @since 0.6.0
1685{-# INLINE isPrefixOf #-}
1686isPrefixOf :: (Eq a, IsStream t, Monad m) => t m a -> t m a -> m Bool
1687isPrefixOf m1 m2 = D.isPrefixOf (toStreamD m1) (toStreamD m2)
1689-- Note: isPrefixOf uses the prefix stream only once. In contrast, isSuffixOf
1690-- may use the suffix stream many times. To run in optimal memory we do not
1691-- want to buffer the suffix stream in memory therefore we need an ability to
1692-- clone (or consume it multiple times) the suffix stream without any side
1693-- effects so that multiple potential suffix matches can proceed in parallel
1694-- without buffering the suffix stream. For example, we may create the suffix
1695-- stream from a file handle, however, if we evaluate the stream multiple
1696-- times, once for each match, we will need a different file handle each time
1697-- which may exhaust the file descriptors. Instead, we want to share the same
1698-- underlying file descriptor, use pread on it to generate the stream and clone
1699-- the stream for each match. Therefore the suffix stream should be built in
1700-- such a way that it can be consumed multiple times without any problems.
1702-- XXX Can be implemented with better space/time complexity.
1703-- Space: @O(n)@ worst case where @n@ is the length of the suffix.
1705-- | Returns 'True' if the first stream is a suffix of the second. A stream is
1706-- considered a suffix of itself.
1708-- @
1709-- > S.isSuffixOf (S.fromList "hello") (S.fromList "hello" :: SerialT IO Char)
1710-- True
1711-- @
1713-- Space: @O(n)@, buffers entire input stream and the suffix.
1715-- /Internal/
1717-- /Suboptimal/ - Help wanted.
1719{-# INLINE isSuffixOf #-}
1720isSuffixOf :: (Monad m, Eq a) => SerialT m a -> SerialT m a -> m Bool
1721isSuffixOf suffix stream = reverse suffix `isPrefixOf` reverse stream
1723-- | Returns 'True' if the first stream is an infix of the second. A stream is
1724-- considered an infix of itself.
1726-- @
1727-- > S.isInfixOf (S.fromList "hello") (S.fromList "hello" :: SerialT IO Char)
1728-- True
1729-- @
1731-- Space: @O(n)@ worst case where @n@ is the length of the infix.
1733-- /Internal/
1735-- /Requires 'Storable' constraint/ - Help wanted.
1737{-# INLINE isInfixOf #-}
1738isInfixOf :: (MonadIO m, Eq a, Enum a, Storable a)
1739 => SerialT m a -> SerialT m a -> m Bool
1740isInfixOf infx stream = do
1741 arr <- fold A.write infx
1742 -- XXX can use breakOnSeq instead (when available)
1743 r <- null $ drop 1 $ splitOnSeq arr FL.drain stream
1744 return (not r)
1746-- | Returns 'True' if all the elements of the first stream occur, in order, in
1747-- the second stream. The elements do not have to occur consecutively. A stream
1748-- is a subsequence of itself.
1750-- @
1751-- > S.isSubsequenceOf (S.fromList "hlo") (S.fromList "hello" :: SerialT IO Char)
1752-- True
1753-- @
1755-- @since 0.6.0
1756{-# INLINE isSubsequenceOf #-}
1757isSubsequenceOf :: (Eq a, IsStream t, Monad m) => t m a -> t m a -> m Bool
1758isSubsequenceOf m1 m2 = D.isSubsequenceOf (toStreamD m1) (toStreamD m2)
1760-- | Strip prefix if present and tell whether it was stripped or not. Returns
1761-- 'Nothing' if the stream does not start with the given prefix, stripped
1762-- stream otherwise. Returns @Just nil@ when the prefix is the same as the
1763-- stream.
1765-- Space: @O(1)@
1767-- @since 0.6.0
1768{-# INLINE stripPrefix #-}
1769stripPrefix
1770 :: (Eq a, IsStream t, Monad m)
1771 => t m a -> t m a -> m (Maybe (t m a))
1772stripPrefix m1 m2 = fmap fromStreamD <$>
1773 D.stripPrefix (toStreamD m1) (toStreamD m2)
1775-- Note: If we want to return a Maybe value to know whether the
1776-- suffix/infix was present or not along with the stripped stream then
1777-- we need to buffer the whole input stream.
1779-- | Drops the given suffix from a stream. Returns 'Nothing' if the stream does
1780-- not end with the given suffix. Returns @Just nil@ when the suffix is the
1781-- same as the stream.
1783-- It may be more efficient to convert the stream to an Array and use
1784-- stripSuffix on that especially if the elements have a Storable or Prim
1785-- instance.
1787-- Space: @O(n)@, buffers the entire input stream as well as the suffix
1789-- /Internal/
1790{-# INLINE stripSuffix #-}
1791stripSuffix
1792 :: (Monad m, Eq a)
1793 => SerialT m a -> SerialT m a -> m (Maybe (SerialT m a))
1794stripSuffix m1 m2 = fmap reverse <$> stripPrefix (reverse m1) (reverse m2)
1796-- | Drop prefix from the input stream if present.
1798-- Space: @O(1)@
1800-- /Unimplemented/ - Help wanted.
1801{-# INLINE dropPrefix #-}
1802dropPrefix ::
1803 -- (Eq a, IsStream t, Monad m) =>
1804 t m a -> t m a -> t m a
1805dropPrefix = error "Not implemented yet!"
1807-- | Drop all matching infix from the input stream if present. Infix stream
1808-- may be consumed multiple times.
1810-- Space: @O(n)@ where n is the length of the infix.
1812-- /Unimplemented/ - Help wanted.
1813{-# INLINE dropInfix #-}
1814dropInfix ::
1815 -- (Eq a, IsStream t, Monad m) =>
1816 t m a -> t m a -> t m a
1817dropInfix = error "Not implemented yet!"
1819-- | Drop suffix from the input stream if present. Suffix stream may be
1820-- consumed multiple times.
1822-- Space: @O(n)@ where n is the length of the suffix.
1824-- /Unimplemented/ - Help wanted.
1825{-# INLINE dropSuffix #-}
1826dropSuffix ::
1827 -- (Eq a, IsStream t, Monad m) =>
1828 t m a -> t m a -> t m a
1829dropSuffix = error "Not implemented yet!"
1831------------------------------------------------------------------------------
1832-- Map and Fold
1833------------------------------------------------------------------------------
1835-- XXX this can utilize parallel mapping if we implement it as drain . mapM
1836-- |
1837-- > mapM_ = drain . mapM
1839-- Apply a monadic action to each element of the stream and discard the output
1840-- of the action. This is not really a pure transformation operation but a
1841-- transformation followed by fold.
1843-- @since 0.1.0
1844{-# INLINE mapM_ #-}
1845mapM_ :: Monad m => (a -> m b) -> SerialT m a -> m ()
1846mapM_ f m = S.mapM_ f $ toStreamS m
1848------------------------------------------------------------------------------
1849-- Conversions
1850------------------------------------------------------------------------------
1852-- |
1853-- @
1854-- toList = S.foldr (:) []
1855-- @
1857-- Convert a stream into a list in the underlying monad. The list can be
1858-- consumed lazily in a lazy monad (e.g. 'Identity'). In a strict monad (e.g.
1859-- IO) the whole list is generated and buffered before it can be consumed.
1861-- /Warning!/ working on large lists accumulated as buffers in memory could be
1862-- very inefficient, consider using "Streamly.Array" instead.
1864-- @since 0.1.0
1865{-# INLINE toList #-}
1866toList :: Monad m => SerialT m a -> m [a]
1867toList = P.toList
1869-- |
1870-- @
1871-- toListRev = S.foldl' (flip (:)) []
1872-- @
1874-- Convert a stream into a list in reverse order in the underlying monad.
1876-- /Warning!/ working on large lists accumulated as buffers in memory could be
1877-- very inefficient, consider using "Streamly.Array" instead.
1879-- /Internal/
1880{-# INLINE toListRev #-}
1881toListRev :: Monad m => SerialT m a -> m [a]
1882toListRev = D.toListRev . toStreamD
1884-- |
1885-- @
1886-- toHandle h = S.mapM_ $ hPutStrLn h
1887-- @
1889-- Write a stream of Strings to an IO Handle.
1891-- @since 0.1.0
1892{-# DEPRECATED toHandle
1893 "Please use Streamly.FileSystem.Handle module (see the changelog)" #-}
1894toHandle :: MonadIO m => IO.Handle -> SerialT m String -> m ()
1895toHandle h = go
1896 where
1897 go m1 =
1898 let stop = return ()
1899 single a = liftIO (IO.hPutStrLn h a)
1900 yieldk a r = liftIO (IO.hPutStrLn h a) >> go r
1901 in K.foldStream defState yieldk single stop m1
1903-- XXX rename these to write/writeRev to make the naming consistent with folds
1904-- in other modules.
1906-- | A fold that buffers its input to a pure stream.
1908-- /Warning!/ working on large streams accumulated as buffers in memory could
1909-- be very inefficient, consider using "Streamly.Array" instead.
1911-- /Internal/
1912{-# INLINE toStream #-}
1913toStream :: Monad m => Fold m a (SerialT Identity a)
1914toStream = Fold (\f x -> return $ f . (x `K.cons`))
1915 (return id)
1916 (return . ($ K.nil))
1918-- This is more efficient than 'toStream'. toStream is exactly the same as
1919-- reversing the stream after toStreamRev.
1921-- | Buffers the input stream to a pure stream in the reverse order of the
1922-- input.
1924-- /Warning!/ working on large streams accumulated as buffers in memory could
1925-- be very inefficient, consider using "Streamly.Array" instead.
1927-- /Internal/
1929-- xn : ... : x2 : x1 : []
1930{-# INLINABLE toStreamRev #-}
1931toStreamRev :: Monad m => Fold m a (SerialT Identity a)
1932toStreamRev = Fold (\xs x -> return $ x `K.cons` xs) (return K.nil) return
1934-- | Convert a stream to a pure stream.
1936-- @
1937-- toPure = foldr cons nil
1938-- @
1940-- /Internal/
1942{-# INLINE toPure #-}
1943toPure :: Monad m => SerialT m a -> m (SerialT Identity a)
1944toPure = foldr K.cons K.nil
1946-- | Convert a stream to a pure stream in reverse order.
1948-- @
1949-- toPureRev = foldl' (flip cons) nil
1950-- @
1952-- /Internal/
1954{-# INLINE toPureRev #-}
1955toPureRev :: Monad m => SerialT m a -> m (SerialT Identity a)
1956toPureRev = foldl' (flip K.cons) K.nil
1958------------------------------------------------------------------------------
1959-- Concurrent Application
1960------------------------------------------------------------------------------
1962infixr 0 |$
1963infixr 0 |$.
1965infixl 1 |&
1966infixl 1 |&.
1968-- | Parallel transform application operator; applies a stream transformation
1969-- function @t m a -> t m b@ to a stream @t m a@ concurrently; the input stream
1970-- is evaluated asynchronously in an independent thread yielding elements to a
1971-- buffer and the transformation function runs in another thread consuming the
1972-- input from the buffer. '|$' is just like regular function application
1973-- operator '$' except that it is concurrent.
1975-- If you read the signature as @(t m a -> t m b) -> (t m a -> t m b)@ you can
1976-- look at it as a transformation that converts a transform function to a
1977-- buffered concurrent transform function.
1979-- The following code prints a value every second even though each stage adds a
1980-- 1 second delay.
1983-- @
1984-- drain $
1985-- S.mapM (\\x -> threadDelay 1000000 >> print x)
1986-- |$ S.repeatM (threadDelay 1000000 >> return 1)
1987-- @
1989-- /Concurrent/
1991-- @since 0.3.0
1992{-# INLINE (|$) #-}
1993(|$) :: (IsStream t, MonadAsync m) => (t m a -> t m b) -> (t m a -> t m b)
1994-- (|$) f = f . Async.mkAsync
1995(|$) f = f . D.mkParallel
1997-- | Same as '|$'.
1999-- /Internal/
2001{-# INLINE applyAsync #-}
2002applyAsync :: (IsStream t, MonadAsync m)
2003 => (t m a -> t m b) -> (t m a -> t m b)
2004applyAsync = (|$)
2006-- | Parallel reverse function application operator for streams; just like the
2007-- regular reverse function application operator '&' except that it is
2008-- concurrent.
2010-- @
2011-- drain $
2012-- S.repeatM (threadDelay 1000000 >> return 1)
2013-- |& S.mapM (\\x -> threadDelay 1000000 >> print x)
2014-- @
2016-- /Concurrent/
2018-- @since 0.3.0
2019{-# INLINE (|&) #-}
2020(|&) :: (IsStream t, MonadAsync m) => t m a -> (t m a -> t m b) -> t m b
2021x |& f = f |$ x
2023-- | Parallel fold application operator; applies a fold function @t m a -> m b@
2024-- to a stream @t m a@ concurrently; The the input stream is evaluated
2025-- asynchronously in an independent thread yielding elements to a buffer and
2026-- the folding action runs in another thread consuming the input from the
2027-- buffer.
2029-- If you read the signature as @(t m a -> m b) -> (t m a -> m b)@ you can look
2030-- at it as a transformation that converts a fold function to a buffered
2031-- concurrent fold function.
2033-- The @.@ at the end of the operator is a mnemonic for termination of the
2034-- stream.
2036-- @
2037-- S.foldlM' (\\_ a -> threadDelay 1000000 >> print a) ()
2038-- |$. S.repeatM (threadDelay 1000000 >> return 1)
2039-- @
2041-- /Concurrent/
2043-- @since 0.3.0
2044{-# INLINE (|$.) #-}
2045(|$.) :: (IsStream t, MonadAsync m) => (t m a -> m b) -> (t m a -> m b)
2046-- (|$.) f = f . Async.mkAsync
2047(|$.) f = f . D.mkParallel
2049-- | Same as '|$.'.
2051-- /Internal/
2053{-# INLINE foldAsync #-}
2054foldAsync :: (IsStream t, MonadAsync m) => (t m a -> m b) -> (t m a -> m b)
2055foldAsync = (|$.)
2057-- | Parallel reverse function application operator for applying a run or fold
2058-- functions to a stream. Just like '|$.' except that the operands are reversed.
2060-- @
2061-- S.repeatM (threadDelay 1000000 >> return 1)
2062-- |&. S.foldlM' (\\_ a -> threadDelay 1000000 >> print a) ()
2063-- @
2065-- /Concurrent/
2067-- @since 0.3.0
2068{-# INLINE (|&.) #-}
2069(|&.) :: (IsStream t, MonadAsync m) => t m a -> (t m a -> m b) -> m b
2070x |&. f = f |$. x
2072------------------------------------------------------------------------------
2073-- General Transformation
2074------------------------------------------------------------------------------
2076-- | Use a 'Pipe' to transform a stream.
2078-- /Internal/
2080{-# INLINE transform #-}
2081transform :: (IsStream t, Monad m) => Pipe m a b -> t m a -> t m b
2082transform pipe xs = fromStreamD $ D.transform pipe (toStreamD xs)
2084------------------------------------------------------------------------------
2085-- Transformation by Folding (Scans)
2086------------------------------------------------------------------------------
2088-- XXX It may be useful to have a version of scan where we can keep the
2089-- accumulator independent of the value emitted. So that we do not necessarily
2090-- have to keep a value in the accumulator which we are not using. We can pass
2091-- an extraction function that will take the accumulator and the current value
2092-- of the element and emit the next value in the stream. That will also make it
2093-- possible to modify the accumulator after using it. In fact, the step function
2094-- can return new accumulator and the value to be emitted. The signature would
2095-- be more like mapAccumL. Or we can change the signature of scanx to
2096-- accommodate this.
2098-- | Strict left scan with an extraction function. Like 'scanl'', but applies a
2099-- user supplied extraction function (the third argument) at each step. This is
2100-- designed to work with the @foldl@ library. The suffix @x@ is a mnemonic for
2101-- extraction.
2103-- /Since: 0.7.0 (Monad m constraint)/
2105-- /Since 0.2.0/
2106{-# DEPRECATED scanx "Please use scanl followed by map instead." #-}
2107{-# INLINE scanx #-}
2108scanx :: (IsStream t, Monad m) => (x -> a -> x) -> x -> (x -> b) -> t m a -> t m b
2109scanx = P.scanlx'
2111-- XXX this needs to be concurrent
2112-- XXX because of the use of D.cons for appending, scanlM' has quadratic
2113-- complexity when iterated over a stream. We should use StreamK style scanlM'
2114-- for linear performance on iteration.
2116-- | Like 'scanl'' but with a monadic fold function.
2118-- @since 0.4.0
2119{-# INLINE scanlM' #-}
2120scanlM' :: (IsStream t, Monad m) => (b -> a -> m b) -> b -> t m a -> t m b
2121scanlM' step begin m = fromStreamD $ D.scanlM' step begin $ toStreamD m
2123-- | @scanlMAfter' accumulate initial done stream@ is like 'scanlM'' except
2124-- that it provides an additional @done@ function to be applied on the
2125-- accumulator when the stream stops. The result of @done@ is also emitted in
2126-- the stream.
2128-- This function can be used to allocate a resource in the beginning of the
2129-- scan and release it when the stream ends or to flush the internal state of
2130-- the scan at the end.
2132-- /Internal/
2134{-# INLINE scanlMAfter' #-}
2135scanlMAfter' :: (IsStream t, Monad m)
2136 => (b -> a -> m b) -> m b -> (b -> m b) -> t m a -> t m b
2137scanlMAfter' step initial done stream =
2138 fromStreamD $ D.scanlMAfter' step initial done $ toStreamD stream
2140-- XXX because of the use of D.cons for appending, scanl' has quadratic
2141-- complexity when iterated over a stream. We should use StreamK style scanlM'
2142-- for linear performance on iteration.
2144-- | Strict left scan. Like 'map', 'scanl'' too is a one to one transformation,
2145-- however it adds an extra element.
2147-- @
2148-- > S.toList $ S.scanl' (+) 0 $ fromList [1,2,3,4]
2149-- [0,1,3,6,10]
2150-- @
2152-- @
2153-- > S.toList $ S.scanl' (flip (:)) [] $ S.fromList [1,2,3,4]
2154-- [[],[1],[2,1],[3,2,1],[4,3,2,1]]
2155-- @
2157-- The output of 'scanl'' is the initial value of the accumulator followed by
2158-- all the intermediate steps and the final result of 'foldl''.
2160-- By streaming the accumulated state after each fold step, we can share the
2161-- state across multiple stages of stream composition. Each stage can modify or
2162-- extend the state, do some processing with it and emit it for the next stage,
2163-- thus modularizing the stream processing. This can be useful in
2164-- stateful or event-driven programming.
2166-- Consider the following monolithic example, computing the sum and the product
2167-- of the elements in a stream in one go using a @foldl'@:
2169-- @
2170-- > S.foldl' (\\(s, p) x -> (s + x, p * x)) (0,1) $ S.fromList \[1,2,3,4]
2171-- (10,24)
2172-- @
2174-- Using @scanl'@ we can make it modular by computing the sum in the first
2175-- stage and passing it down to the next stage for computing the product:
2177-- @
2178-- > S.foldl' (\\(_, p) (s, x) -> (s, p * x)) (0,1)
2179-- $ S.scanl' (\\(s, _) x -> (s + x, x)) (0,1)
2180-- $ S.fromList \[1,2,3,4]
2181-- (10,24)
2182-- @
2184-- IMPORTANT: 'scanl'' evaluates the accumulator to WHNF. To avoid building
2185-- lazy expressions inside the accumulator, it is recommended that a strict
2186-- data structure is used for accumulator.
2188-- @since 0.2.0
2189{-# INLINE scanl' #-}
2190scanl' :: (IsStream t, Monad m) => (b -> a -> b) -> b -> t m a -> t m b
2191scanl' step z m = fromStreamS $ S.scanl' step z $ toStreamS m
2193-- | Like 'scanl'' but does not stream the initial value of the accumulator.
2195-- > postscanl' f z xs = S.drop 1 $ S.scanl' f z xs
2197-- @since 0.7.0
2198{-# INLINE postscanl' #-}
2199postscanl' :: (IsStream t, Monad m) => (b -> a -> b) -> b -> t m a -> t m b
2200postscanl' step z m = fromStreamD $ D.postscanl' step z $ toStreamD m
2202-- XXX this needs to be concurrent
2203-- | Like 'postscanl'' but with a monadic step function.
2205-- @since 0.7.0
2206{-# INLINE postscanlM' #-}
2207postscanlM' :: (IsStream t, Monad m) => (b -> a -> m b) -> b -> t m a -> t m b
2208postscanlM' step z m = fromStreamD $ D.postscanlM' step z $ toStreamD m
2210-- XXX prescanl does not sound very useful, enable only if there is a
2211-- compelling use case.
2213-- | Like scanl' but does not stream the final value of the accumulator.
2215-- /Internal/
2216{-# INLINE prescanl' #-}
2217prescanl' :: (IsStream t, Monad m) => (b -> a -> b) -> b -> t m a -> t m b
2218prescanl' step z m = fromStreamD $ D.prescanl' step z $ toStreamD m
2220-- XXX this needs to be concurrent
2221-- | Like postscanl' but with a monadic step function.
2223-- /Internal/
2224{-# INLINE prescanlM' #-}
2225prescanlM' :: (IsStream t, Monad m) => (b -> a -> m b) -> m b -> t m a -> t m b
2226prescanlM' step z m = fromStreamD $ D.prescanlM' step z $ toStreamD m
2228-- XXX this needs to be concurrent
2229-- | Like 'scanl1'' but with a monadic step function.
2231-- @since 0.6.0
2232{-# INLINE scanl1M' #-}
2233scanl1M' :: (IsStream t, Monad m) => (a -> a -> m a) -> t m a -> t m a
2234scanl1M' step m = fromStreamD $ D.scanl1M' step $ toStreamD m
2236-- | Like 'scanl'' but for a non-empty stream. The first element of the stream
2237-- is used as the initial value of the accumulator. Does nothing if the stream
2238-- is empty.
2240-- @
2241-- > S.toList $ S.scanl1 (+) $ fromList [1,2,3,4]
2242-- [1,3,6,10]
2243-- @
2245-- @since 0.6.0
2246{-# INLINE scanl1' #-}
2247scanl1' :: (IsStream t, Monad m) => (a -> a -> a) -> t m a -> t m a
2248scanl1' step m = fromStreamD $ D.scanl1' step $ toStreamD m
2250------------------------------------------------------------------------------
2251-- Scanning with a Fold
2252------------------------------------------------------------------------------
2254-- | Scan a stream using the given monadic fold.
2256-- @since 0.7.0
2257{-# INLINE scan #-}
2258scan :: (IsStream t, Monad m) => Fold m a b -> t m a -> t m b
2259scan (Fold step begin done) = P.scanlMx' step begin done
2261-- | Postscan a stream using the given monadic fold.
2263-- @since 0.7.0
2264{-# INLINE postscan #-}
2265postscan :: (IsStream t, Monad m) => Fold m a b -> t m a -> t m b
2266postscan (Fold step begin done) = P.postscanlMx' step begin done
2268------------------------------------------------------------------------------
2269-- Stateful Transformations
2270------------------------------------------------------------------------------
2272-- XXX this is not a one-to-one map so calling it map may not be right.
2273-- We can perhaps call it zipWithTail or rollWith.
2275-- | Apply a function on every two successive elements of a stream. If the
2276-- stream consists of a single element the output is an empty stream.
2278-- This is the stream equivalent of the list idiom @zipWith f xs (tail xs)@.
2280-- /Internal/
2282{-# INLINE rollingMap #-}
2283rollingMap :: (IsStream t, Monad m) => (a -> a -> b) -> t m a -> t m b
2284rollingMap f m = fromStreamD $ D.rollingMap f $ toStreamD m
2286-- | Like 'rollingMap' but with an effectful map function.
2288-- /Internal/
2290{-# INLINE rollingMapM #-}
2291rollingMapM :: (IsStream t, Monad m) => (a -> a -> m b) -> t m a -> t m b
2292rollingMapM f m = fromStreamD $ D.rollingMapM f $ toStreamD m
2294------------------------------------------------------------------------------
2295-- Transformation by Filtering
2296------------------------------------------------------------------------------
2298-- | Include only those elements that pass a predicate.
2300-- @since 0.1.0
2301{-# INLINE filter #-}
2302#if __GLASGOW_HASKELL__ != 802
2303-- GHC 8.2.2 crashes with this code, when used with "stack"
2304filter :: (IsStream t, Monad m) => (a -> Bool) -> t m a -> t m a
2305filter p m = fromStreamS $ S.filter p $ toStreamS m
2306#else
2307filter :: IsStream t => (a -> Bool) -> t m a -> t m a
2308filter = K.filter
2309#endif
2311-- | Same as 'filter' but with a monadic predicate.
2313-- @since 0.4.0
2314{-# INLINE filterM #-}
2315filterM :: (IsStream t, Monad m) => (a -> m Bool) -> t m a -> t m a
2316filterM p m = fromStreamD $ D.filterM p $ toStreamD m
2318-- | Drop repeated elements that are adjacent to each other.
2320-- @since 0.6.0
2321{-# INLINE uniq #-}
2322uniq :: (Eq a, IsStream t, Monad m) => t m a -> t m a
2323uniq = fromStreamD . D.uniq . toStreamD
2325-- | Ensures that all the elements of the stream are identical and then returns
2326-- that unique element.
2328-- @since 0.6.0
2329{-# INLINE the #-}
2330the :: (Eq a, Monad m) => SerialT m a -> m (Maybe a)
2331the m = S.the (toStreamS m)
2333-- | Take first 'n' elements from the stream and discard the rest.
2335-- @since 0.1.0
2336{-# INLINE take #-}
2337take :: (IsStream t, Monad m) => Int -> t m a -> t m a
2338take n m = fromStreamS $ S.take n $ toStreamS
2339 (maxYields (Just (fromIntegral n)) m)
2341-- | End the stream as soon as the predicate fails on an element.
2343-- @since 0.1.0
2344{-# INLINE takeWhile #-}
2345takeWhile :: (IsStream t, Monad m) => (a -> Bool) -> t m a -> t m a
2346takeWhile p m = fromStreamS $ S.takeWhile p $ toStreamS m
2348-- | Same as 'takeWhile' but with a monadic predicate.
2350-- @since 0.4.0
2351{-# INLINE takeWhileM #-}
2352takeWhileM :: (IsStream t, Monad m) => (a -> m Bool) -> t m a -> t m a
2353takeWhileM p m = fromStreamD $ D.takeWhileM p $ toStreamD m
2355-- | @takeByTime duration@ yields stream elements upto specified time
2356-- @duration@. The duration starts when the stream is evaluated for the first
2357-- time, before the first element is yielded. The time duration is checked
2358-- before generating each element, if the duration has expired the stream
2359-- stops.
2361-- The total time taken in executing the stream is guaranteed to be /at least/
2362-- @duration@, however, because the duration is checked before generating an
2363-- element, the upper bound is indeterminate and depends on the time taken in
2364-- generating and processing the last element.
2366-- No element is yielded if the duration is zero. At least one element is
2367-- yielded if the duration is non-zero.
2369-- /Internal/
2371{-# INLINE takeByTime #-}
2372takeByTime ::(MonadIO m, IsStream t, TimeUnit64 d) => d -> t m a -> t m a
2373takeByTime d = fromStreamD . D.takeByTime d . toStreamD
2375-- | Discard first 'n' elements from the stream and take the rest.
2377-- @since 0.1.0
2378{-# INLINE drop #-}
2379drop :: (IsStream t, Monad m) => Int -> t m a -> t m a
2380drop n m = fromStreamS $ S.drop n $ toStreamS m
2382-- | Drop elements in the stream as long as the predicate succeeds and then
2383-- take the rest of the stream.
2385-- @since 0.1.0
2386{-# INLINE dropWhile #-}
2387dropWhile :: (IsStream t, Monad m) => (a -> Bool) -> t m a -> t m a
2388dropWhile p m = fromStreamS $ S.dropWhile p $ toStreamS m
2390-- | Same as 'dropWhile' but with a monadic predicate.
2392-- @since 0.4.0
2393{-# INLINE dropWhileM #-}
2394dropWhileM :: (IsStream t, Monad m) => (a -> m Bool) -> t m a -> t m a
2395dropWhileM p m = fromStreamD $ D.dropWhileM p $ toStreamD m
2397-- | @dropByTime duration@ drops stream elements until specified @duration@ has
2398-- passed. The duration begins when the stream is evaluated for the first
2399-- time. The time duration is checked /after/ generating a stream element, the
2400-- element is yielded if the duration has expired otherwise it is dropped.
2402-- The time elapsed before starting to generate the first element is /at most/
2403-- @duration@, however, because the duration expiry is checked after the
2404-- element is generated, the lower bound is indeterminate and depends on the
2405-- time taken in generating an element.
2407-- All elements are yielded if the duration is zero.
2409-- /Internal/
2411{-# INLINE dropByTime #-}
2412dropByTime ::(MonadIO m, IsStream t, TimeUnit64 d) => d -> t m a -> t m a
2413dropByTime d = fromStreamD . D.dropByTime d . toStreamD
2415------------------------------------------------------------------------------
2416-- Transformation by Mapping
2417------------------------------------------------------------------------------
2419-- |
2420-- @
2421-- mapM f = sequence . map f
2422-- @
2424-- Apply a monadic function to each element of the stream and replace it with
2425-- the output of the resulting action.
2427-- @
2428-- > drain $ S.mapM putStr $ S.fromList ["a", "b", "c"]
2429-- abc
2431-- drain $ S.replicateM 10 (return 1)
2432-- & (serially . S.mapM (\\x -> threadDelay 1000000 >> print x))
2434-- drain $ S.replicateM 10 (return 1)
2435-- & (asyncly . S.mapM (\\x -> threadDelay 1000000 >> print x))
2436-- @
2438-- /Concurrent (do not use with 'parallely' on infinite streams)/
2440-- @since 0.1.0
2441{-# INLINE_EARLY mapM #-}
2442mapM :: (IsStream t, MonadAsync m) => (a -> m b) -> t m a -> t m b
2443mapM = K.mapM
2445{-# RULES "mapM serial" mapM = mapMSerial #-}
2446{-# INLINE mapMSerial #-}
2447mapMSerial :: Monad m => (a -> m b) -> SerialT m a -> SerialT m b
2448mapMSerial = Serial.mapM
2450-- |
2451-- @
2452-- sequence = mapM id
2453-- @
2455-- Replace the elements of a stream of monadic actions with the outputs of
2456-- those actions.
2458-- @
2459-- > drain $ S.sequence $ S.fromList [putStr "a", putStr "b", putStrLn "c"]
2460-- abc
2462-- drain $ S.replicateM 10 (return $ threadDelay 1000000 >> print 1)
2463-- & (serially . S.sequence)
2465-- drain $ S.replicateM 10 (return $ threadDelay 1000000 >> print 1)
2466-- & (asyncly . S.sequence)
2467-- @
2469-- /Concurrent (do not use with 'parallely' on infinite streams)/
2471-- @since 0.1.0
2472{-# INLINE sequence #-}
2473sequence :: (IsStream t, MonadAsync m) => t m (m a) -> t m a
2474sequence m = fromStreamS $ S.sequence (toStreamS m)
2476------------------------------------------------------------------------------
2477-- Transformation by Map and Filter
2478------------------------------------------------------------------------------
2480-- | Map a 'Maybe' returning function to a stream, filter out the 'Nothing'
2481-- elements, and return a stream of values extracted from 'Just'.
2483-- Equivalent to:
2485-- @
2486-- mapMaybe f = S.map 'fromJust' . S.filter 'isJust' . S.map f
2487-- @
2489-- @since 0.3.0
2490{-# INLINE mapMaybe #-}
2491mapMaybe :: (IsStream t, Monad m) => (a -> Maybe b) -> t m a -> t m b
2492mapMaybe f m = fromStreamS $ S.mapMaybe f $ toStreamS m
2494-- | Like 'mapMaybe' but maps a monadic function.
2496-- Equivalent to:
2498-- @
2499-- mapMaybeM f = S.map 'fromJust' . S.filter 'isJust' . S.mapM f
2500-- @
2502-- /Concurrent (do not use with 'parallely' on infinite streams)/
2504-- @since 0.3.0
2505{-# INLINE_EARLY mapMaybeM #-}
2506mapMaybeM :: (IsStream t, MonadAsync m, Functor (t m))
2507 => (a -> m (Maybe b)) -> t m a -> t m b
2508mapMaybeM f = fmap fromJust . filter isJust . K.mapM f
2510{-# RULES "mapMaybeM serial" mapMaybeM = mapMaybeMSerial #-}
2511{-# INLINE mapMaybeMSerial #-}
2512mapMaybeMSerial :: Monad m => (a -> m (Maybe b)) -> SerialT m a -> SerialT m b
2513mapMaybeMSerial f m = fromStreamD $ D.mapMaybeM f $ toStreamD m
2515------------------------------------------------------------------------------
2516-- Transformation by Reordering
2517------------------------------------------------------------------------------
2519-- XXX Use a compact region list to temporarily store the list, in both reverse
2520-- as well as in reverse'.
2522-- /Note:/ 'reverse'' is much faster than this, use that when performance
2523-- matters.
2525-- > reverse = S.foldlT (flip S.cons) S.nil
2527-- | Returns the elements of the stream in reverse order. The stream must be
2528-- finite. Note that this necessarily buffers the entire stream in memory.
2530-- /Since 0.7.0 (Monad m constraint)/
2532-- /Since: 0.1.1/
2533{-# INLINE reverse #-}
2534reverse :: (IsStream t, Monad m) => t m a -> t m a
2535reverse s = fromStreamS $ S.reverse $ toStreamS s
2537-- | Like 'reverse' but several times faster, requires a 'Storable' instance.
2539-- /Internal/
2540{-# INLINE reverse' #-}
2541reverse' :: (IsStream t, MonadIO m, Storable a) => t m a -> t m a
2542reverse' s = fromStreamD $ D.reverse' $ toStreamD s
2544------------------------------------------------------------------------------
2545-- Transformation by Inserting
2546------------------------------------------------------------------------------
2548-- intersperseM = intersperseBySpan 1
2550-- | Insert an effect and its output before consuming an element of a stream
2551-- except the first one.
2553-- @
2554-- >>> S.toList $ S.trace putChar $ S.intersperseM (putChar '.' >> return ',') $ S.fromList "hello"
2555-- > h.,e.,l.,l.,o"h,e,l,l,o"
2556-- @
2558-- @since 0.5.0
2559{-# INLINE intersperseM #-}
2560intersperseM :: (IsStream t, MonadAsync m) => m a -> t m a -> t m a
2561intersperseM m = fromStreamS . S.intersperseM m . toStreamS
2563-- | Insert a side effect before consuming an element of a stream except the
2564-- first one.
2566-- @
2567-- >>> S.drain $ S.trace putChar $ S.intersperseM_ (putChar '.') $ S.fromList "hello"
2568-- > h.e.l.l.o
2569-- @
2571-- /Internal/
2572{-# INLINE intersperseM_ #-}
2573intersperseM_ :: (IsStream t, Monad m) => m b -> t m a -> t m a
2574intersperseM_ m = fromStreamD . D.intersperseM_ m . toStreamD
2576-- | Insert a pure value between successive elements of a stream.
2578-- @
2579-- > S.toList $ S.intersperse ',' $ S.fromList "hello"
2580-- "h,e,l,l,o"
2581-- @
2583-- @since 0.7.0
2584{-# INLINE intersperse #-}
2585intersperse :: (IsStream t, MonadAsync m) => a -> t m a -> t m a
2586intersperse a = fromStreamS . S.intersperse a . toStreamS
2588-- | Insert an effect and its output after consuming an element of a stream.
2590-- @
2591-- >>> S.toList $ S.trace putChar $ S.intersperseSuffix (putChar '.' >> return ',') $ S.fromList "hello"
2592-- > h.,e.,l.,l.,o.,"h,e,l,l,o,"
2593-- @
2595-- /Internal/
2596{-# INLINE intersperseSuffix #-}
2597intersperseSuffix :: (IsStream t, MonadAsync m) => m a -> t m a -> t m a
2598intersperseSuffix m = fromStreamD . D.intersperseSuffix m . toStreamD
2600-- | Insert a side effect after consuming an element of a stream.
2602-- @
2603-- > S.mapM_ putChar $ S.intersperseSuffix_ (threadDelay 1000000) $ S.fromList "hello"
2604-- @
2606-- /Internal/
2608{-# INLINE intersperseSuffix_ #-}
2609intersperseSuffix_ :: (IsStream t, Monad m) => m b -> t m a -> t m a
2610intersperseSuffix_ m = fromStreamD . D.intersperseSuffix_ m . toStreamD
2612-- | Insert a side effect before consuming an element of a stream.
2614-- @
2615-- >>> S.toList $ S.trace putChar $ S.interspersePrefix_ (putChar '.' >> return ',') $ S.fromList "hello"
2616-- > .h.e.l.l.o"hello"
2617-- @
2619-- See also: 'trace_'
2621-- /Concurrent/
2623-- /Internal/
2625{-# INLINE interspersePrefix_ #-}
2626interspersePrefix_ :: (IsStream t, MonadAsync m) => m b -> t m a -> t m a
2627interspersePrefix_ m = mapM (\x -> void m >> return x)
2629-- Note: delay must be serial.
2631-- | Introduce a delay of specified seconds before consuming an element of the
2632-- stream except the first one.
2634-- @
2635-- >>> S.mapM_ print $ S.timestamped $ S.delay 1 $ S.enumerateFromTo 1 3
2636-- > (AbsTime (TimeSpec {sec = 2502706, nsec = 751137000}),1)
2637-- > (AbsTime (TimeSpec {sec = 2502707, nsec = 743535000}),2)
2638-- > (AbsTime (TimeSpec {sec = 2502708, nsec = 749758000}),3)
2639-- @
2641-- /Internal/
2643{-# INLINE delay #-}
2644delay :: (IsStream t, MonadIO m) => Double -> t m a -> t m a
2645delay n = intersperseM_ $ liftIO $ threadDelay $ round $ n * 1000000
2647-- Note: delay must be serial.
2649-- | Introduce a delay of specified seconds after consuming an element of a
2650-- stream.
2652-- @
2653-- >>> S.mapM_ print $ S.timestamped $ S.delayPost 1 $ S.enumerateFromTo 1 3
2654-- > (AbsTime (TimeSpec {sec = 2502826, nsec = 119030000}),1)
2655-- > (AbsTime (TimeSpec {sec = 2502827, nsec = 111393000}),2)
2656-- > (AbsTime (TimeSpec {sec = 2502828, nsec = 112221000}),3)
2657-- @
2659-- /Internal/
2661{-# INLINE delayPost #-}
2662delayPost :: (IsStream t, MonadIO m) => Double -> t m a -> t m a
2663delayPost n = intersperseSuffix_ $ liftIO $ threadDelay $ round $ n * 1000000
2665-- Note: delay must be serial, that's why 'trace_' is used.
2667-- | Introduce a delay of specified seconds before consuming an element of a
2668-- stream.
2670-- @
2671-- >>> S.mapM_ print $ S.timestamped $ S.delayPre 1 $ S.enumerateFromTo 1 3
2672-- > (AbsTime (TimeSpec {sec = 2502207, nsec = 533177000}),1)
2673-- > (AbsTime (TimeSpec {sec = 2502208, nsec = 530859000}),2)
2674-- > (AbsTime (TimeSpec {sec = 2502209, nsec = 531619000}),3)
2675-- @
2677-- /Internal/
2679{-# INLINE delayPre #-}
2680delayPre :: (IsStream t, MonadIO m) => Double -> t m a -> t m a
2681delayPre n = trace_ $ liftIO $ threadDelay $ round $ n * 1000000
2683-- | Like 'intersperseSuffix' but intersperses an effectful action into the
2684-- input stream after every @n@ elements and after the last element.
2686-- @
2687-- > S.toList $ S.intersperseSuffixBySpan 2 (return ',') $ S.fromList "hello"
2688-- "he,ll,o,"
2689-- @
2691-- /Internal/
2693{-# INLINE intersperseSuffixBySpan #-}
2694intersperseSuffixBySpan :: (IsStream t, MonadAsync m)
2695 => Int -> m a -> t m a -> t m a
2696intersperseSuffixBySpan n eff =
2697 fromStreamD . D.intersperseSuffixBySpan n eff . toStreamD
2700-- | Intersperse a monadic action into the input stream after every @n@
2701-- elements.
2703-- @
2704-- > S.toList $ S.intersperseBySpan 2 (return ',') $ S.fromList "hello"
2705-- "he,ll,o"
2706-- @
2708-- @since 0.7.0
2709{-# INLINE intersperseBySpan #-}
2710intersperseBySpan :: IsStream t => Int -> m a -> t m a -> t m a
2711intersperseBySpan _n _f _xs = undefined
2714-- | Intersperse a monadic action into the input stream after every @n@
2715-- seconds.
2717-- @
2718-- > S.drain $ S.interjectSuffix 1 (putChar ',') $ S.mapM (\\x -> threadDelay 1000000 >> putChar x) $ S.fromList "hello"
2719-- "h,e,l,l,o"
2720-- @
2722-- /Internal/
2723{-# INLINE interjectSuffix #-}
2724interjectSuffix
2725 :: (IsStream t, MonadAsync m)
2726 => Double -> m a -> t m a -> t m a
2727interjectSuffix n f xs = xs `Par.parallelFst` repeatM timed
2728 where timed = liftIO (threadDelay (round $ n * 1000000)) >> f
2730-- | @insertBy cmp elem stream@ inserts @elem@ before the first element in
2731-- @stream@ that is less than @elem@ when compared using @cmp@.
2733-- @
2734-- insertBy cmp x = 'mergeBy' cmp ('yield' x)
2735-- @
2737-- @
2738-- > S.toList $ S.insertBy compare 2 $ S.fromList [1,3,5]
2739-- [1,2,3,5]
2740-- @
2742-- @since 0.6.0
2743{-# INLINE insertBy #-}
2744insertBy ::
2745 (IsStream t, Monad m) => (a -> a -> Ordering) -> a -> t m a -> t m a
2746insertBy cmp x m = fromStreamS $ S.insertBy cmp x (toStreamS m)
2748------------------------------------------------------------------------------
2749-- Deleting
2750------------------------------------------------------------------------------
2752-- | Deletes the first occurrence of the element in the stream that satisfies
2753-- the given equality predicate.
2755-- @
2756-- > S.toList $ S.deleteBy (==) 3 $ S.fromList [1,3,3,5]
2757-- [1,3,5]
2758-- @
2760-- @since 0.6.0
2761{-# INLINE deleteBy #-}
2762deleteBy :: (IsStream t, Monad m) => (a -> a -> Bool) -> a -> t m a -> t m a
2763deleteBy cmp x m = fromStreamS $ S.deleteBy cmp x (toStreamS m)
2765------------------------------------------------------------------------------
2766-- Zipping
2767------------------------------------------------------------------------------
2769-- |
2770-- > indexed = S.postscanl' (\(i, _) x -> (i + 1, x)) (-1,undefined)
2771-- > indexed = S.zipWith (,) (S.enumerateFrom 0)
2773-- Pair each element in a stream with its index, starting from index 0.
2775-- @
2776-- > S.toList $ S.indexed $ S.fromList "hello"
2777-- [(0,'h'),(1,'e'),(2,'l'),(3,'l'),(4,'o')]
2778-- @
2780-- @since 0.6.0
2781{-# INLINE indexed #-}
2782indexed :: (IsStream t, Monad m) => t m a -> t m (Int, a)
2783indexed = fromStreamD . D.indexed . toStreamD
2785-- |
2786-- > indexedR n = S.postscanl' (\(i, _) x -> (i - 1, x)) (n + 1,undefined)
2787-- > indexedR n = S.zipWith (,) (S.enumerateFromThen n (n - 1))
2789-- Pair each element in a stream with its index, starting from the
2790-- given index @n@ and counting down.
2792-- @
2793-- > S.toList $ S.indexedR 10 $ S.fromList "hello"
2794-- [(10,'h'),(9,'e'),(8,'l'),(7,'l'),(6,'o')]
2795-- @
2797-- @since 0.6.0
2798{-# INLINE indexedR #-}
2799indexedR :: (IsStream t, Monad m) => Int -> t m a -> t m (Int, a)
2800indexedR n = fromStreamD . D.indexedR n . toStreamD
2802-- Note: The timestamp stream must be the second stream in the zip so that the
2803-- timestamp is generated after generating the stream element and not before.
2804-- If we do not do that then the following example will generate the same
2805-- timestamp for first two elements:
2807-- S.mapM_ print $ S.timestamped $ S.delay $ S.enumerateFromTo 1 3
2809-- | Pair each element in a stream with an absolute timestamp, using a clock of
2810-- specified granularity. The timestamp is generated just before the element
2811-- is consumed.
2813-- @
2814-- >>> S.mapM_ print $ S.timestampWith 0.01 $ S.delay 1 $ S.enumerateFromTo 1 3
2815-- @
2817-- /Internal/
2819{-# INLINE timestampWith #-}
2820timestampWith :: (IsStream t, MonadAsync m, Functor (t m))
2821 => Double -> t m a -> t m (AbsTime, a)
2822timestampWith g stream = Z.zipWith (flip (,)) stream (absTimesWith g)
2824-- TBD: check performance vs a custom implementation without using zipWith.
2826-- | Pair each element in a stream with an absolute timestamp, using a clock of
2827-- 10 ms granularity. The timestamp is generated just before the element is
2828-- consumed.
2830-- @
2831-- >>> S.mapM_ print $ S.timestamped $ S.delay 1 $ S.enumerateFromTo 1 3
2832-- (AbsTime (TimeSpec {sec = 2460689, nsec = 641121000}),1)
2833-- (AbsTime (TimeSpec {sec = 2460690, nsec = 639334000}),2)
2834-- (AbsTime (TimeSpec {sec = 2460691, nsec = 644479000}),3)
2835-- @
2837-- /Internal/
2839{-# INLINE timestamped #-}
2840timestamped :: (IsStream t, MonadAsync m, Functor (t m))
2841 => t m a -> t m (AbsTime, a)
2842timestamped = timestampWith 0.01
2844-- | Pair each element in a stream with relative times starting from 0, using a
2845-- clock with the specified granularity. The time is measured just before the
2846-- element is consumed.
2848-- @
2849-- >>> S.mapM_ print $ S.timeIndexWith 0.01 $ S.delay 1 $ S.enumerateFromTo 1 3
2850-- @
2852-- /Internal/
2854{-# INLINE timeIndexWith #-}
2855timeIndexWith :: (IsStream t, MonadAsync m, Functor (t m))
2856 => Double -> t m a -> t m (RelTime64, a)
2857timeIndexWith g stream = Z.zipWith (flip (,)) stream (relTimesWith g)
2859-- | Pair each element in a stream with relative times starting from 0, using a
2860-- 10 ms granularity clock. The time is measured just before the element is
2861-- consumed.
2863-- @
2864-- >>> S.mapM_ print $ S.timeIndexed $ S.delay 1 $ S.enumerateFromTo 1 3
2865-- (RelTime64 (NanoSecond64 0),1)
2866-- (RelTime64 (NanoSecond64 996239000),2)
2867-- (RelTime64 (NanoSecond64 1996712000),3)
2868-- @
2870-- /Internal/
2872{-# INLINE timeIndexed #-}
2873timeIndexed :: (IsStream t, MonadAsync m, Functor (t m))
2874 => t m a -> t m (RelTime64, a)
2875timeIndexed = timeIndexWith 0.01
2877------------------------------------------------------------------------------
2878-- Comparison
2879------------------------------------------------------------------------------
2881-- | Compare two streams for equality using an equality function.
2883-- @since 0.6.0
2884{-# INLINABLE eqBy #-}
2885eqBy :: (IsStream t, Monad m) => (a -> b -> Bool) -> t m a -> t m b -> m Bool
2886eqBy = P.eqBy
2888-- | Compare two streams lexicographically using a comparison function.
2890-- @since 0.6.0
2891{-# INLINABLE cmpBy #-}
2892cmpBy
2893 :: (IsStream t, Monad m)
2894 => (a -> b -> Ordering) -> t m a -> t m b -> m Ordering
2895cmpBy = P.cmpBy
2897------------------------------------------------------------------------------
2898-- Merge
2899------------------------------------------------------------------------------
2901-- | Merge two streams using a comparison function. The head elements of both
2902-- the streams are compared and the smaller of the two elements is emitted, if
2903-- both elements are equal then the element from the first stream is used
2904-- first.
2906-- If the streams are sorted in ascending order, the resulting stream would
2907-- also remain sorted in ascending order.
2909-- @
2910-- > S.toList $ S.mergeBy compare (S.fromList [1,3,5]) (S.fromList [2,4,6,8])
2911-- [1,2,3,4,5,6,8]
2912-- @
2914-- @since 0.6.0
2915{-# INLINABLE mergeBy #-}
2916mergeBy ::
2917 (IsStream t, Monad m) => (a -> a -> Ordering) -> t m a -> t m a -> t m a
2918mergeBy f m1 m2 = fromStreamS $ S.mergeBy f (toStreamS m1) (toStreamS m2)
2920-- | Like 'mergeBy' but with a monadic comparison function.
2922-- Merge two streams randomly:
2924-- @
2925-- > randomly _ _ = randomIO >>= \x -> return $ if x then LT else GT
2926-- > S.toList $ S.mergeByM randomly (S.fromList [1,1,1,1]) (S.fromList [2,2,2,2])
2927-- [2,1,2,2,2,1,1,1]
2928-- @
2930-- Merge two streams in a proportion of 2:1:
2932-- @
2933-- proportionately m n = do
2934-- ref <- newIORef $ cycle $ concat [replicate m LT, replicate n GT]
2935-- return $ \\_ _ -> do
2936-- r <- readIORef ref
2937-- writeIORef ref $ tail r
2938-- return $ head r
2940-- main = do
2941-- f <- proportionately 2 1
2942-- xs <- S.toList $ S.mergeByM f (S.fromList [1,1,1,1,1,1]) (S.fromList [2,2,2])
2943-- print xs
2944-- @
2945-- @
2946-- [1,1,2,1,1,2,1,1,2]
2947-- @
2949-- @since 0.6.0
2950{-# INLINABLE mergeByM #-}
2951mergeByM
2952 :: (IsStream t, Monad m)
2953 => (a -> a -> m Ordering) -> t m a -> t m a -> t m a
2954mergeByM f m1 m2 = fromStreamS $ S.mergeByM f (toStreamS m1) (toStreamS m2)
2957-- | Like 'mergeByM' but stops merging as soon as any of the two streams stops.
2958{-# INLINABLE mergeEndByAny #-}
2959mergeEndByAny
2960 :: (IsStream t, Monad m)
2961 => (a -> a -> m Ordering) -> t m a -> t m a -> t m a
2962mergeEndByAny f m1 m2 = fromStreamD $
2963 D.mergeEndByAny f (toStreamD m1) (toStreamD m2)
2965-- Like 'mergeByM' but stops merging as soon as the first stream stops.
2966{-# INLINABLE mergeEndByFirst #-}
2967mergeEndByFirst
2968 :: (IsStream t, Monad m)
2969 => (a -> a -> m Ordering) -> t m a -> t m a -> t m a
2970mergeEndByFirst f m1 m2 = fromStreamS $
2971 D.mergeEndByFirst f (toStreamD m1) (toStreamD m2)
2974-- Holding this back for now, we may want to use the name "merge" differently
2976-- | Same as @'mergeBy' 'compare'@.
2978-- @
2979-- > S.toList $ S.merge (S.fromList [1,3,5]) (S.fromList [2,4,6,8])
2980-- [1,2,3,4,5,6,8]
2981-- @
2983-- @since 0.6.0
2984{-# INLINABLE merge #-}
2985merge ::
2986 (IsStream t, Monad m, Ord a) => t m a -> t m a -> t m a
2987merge = mergeBy compare
2990-- | Like 'mergeBy' but merges concurrently (i.e. both the elements being
2991-- merged are generated concurrently).
2993-- @since 0.6.0
2994{-# INLINE mergeAsyncBy #-}
2995mergeAsyncBy :: (IsStream t, MonadAsync m)
2996 => (a -> a -> Ordering) -> t m a -> t m a -> t m a
2997mergeAsyncBy f = mergeAsyncByM (\a b -> return $ f a b)
2999-- | Like 'mergeByM' but merges concurrently (i.e. both the elements being
3000-- merged are generated concurrently).
3002-- @since 0.6.0
3003{-# INLINE mergeAsyncByM #-}
3004mergeAsyncByM :: (IsStream t, MonadAsync m)
3005 => (a -> a -> m Ordering) -> t m a -> t m a -> t m a
3006mergeAsyncByM f m1 m2 = fromStreamD $
3007 D.mergeByM f (D.mkParallelD $ toStreamD m1) (D.mkParallelD $ toStreamD m2)
3009------------------------------------------------------------------------------
3010-- Nesting
3011------------------------------------------------------------------------------
3013-- | @concatMapWith merge map stream@ is a two dimensional looping combinator.
3014-- The first argument specifies a merge or concat function that is used to
3015-- merge the streams generated by applying the second argument i.e. the @map@
3016-- function to each element of the input stream. The concat function could be
3017-- 'serial', 'parallel', 'async', 'ahead' or any other zip or merge function
3018-- and the second argument could be any stream generation function using a
3019-- seed.
3021-- /Compare 'foldMapWith'/
3023-- @since 0.7.0
3024{-# INLINE concatMapWith #-}
3025concatMapWith
3026 :: IsStream t
3027 => (t m b -> t m b -> t m b)
3028 -> (a -> t m b)
3029 -> t m a
3030 -> t m b
3031concatMapWith = K.concatMapBy
3033-- | Map a stream producing function on each element of the stream and then
3034-- flatten the results into a single stream.
3036-- @
3037-- concatMap = 'concatMapWith' 'Serial.serial'
3038-- concatMap f = 'concatMapM' (return . f)
3039-- concatMap f = 'concatUnfold' (UF.lmap f UF.fromStream)
3040-- @
3042-- @since 0.6.0
3043{-# INLINE concatMap #-}
3044concatMap ::(IsStream t, Monad m) => (a -> t m b) -> t m a -> t m b
3045concatMap f m = fromStreamD $ D.concatMap (toStreamD . f) (toStreamD m)
3047-- | Flatten a stream of streams to a single stream.
3049-- @
3050-- concat = concatMap id
3051-- @
3053-- /Internal/
3054{-# INLINE concat #-}
3055concat :: (IsStream t, Monad m) => t m (t m a) -> t m a
3056concat = concatMap id
3058-- | Append the outputs of two streams, yielding all the elements from the
3059-- first stream and then yielding all the elements from the second stream.
3061-- IMPORTANT NOTE: This could be 100x faster than @serial/<>@ for appending a
3062-- few (say 100) streams because it can fuse via stream fusion. However, it
3063-- does not scale for a large number of streams (say 1000s) and becomes
3064-- qudartically slow. Therefore use this for custom appending of a few streams
3065-- but use 'concatMap' or 'concatMapWith serial' for appending @n@ streams or
3066-- infinite containers of streams.
3068-- /Internal/
3069{-# INLINE append #-}
3070append ::(IsStream t, Monad m) => t m b -> t m b -> t m b
3071append m1 m2 = fromStreamD $ D.append (toStreamD m1) (toStreamD m2)
3073-- XXX Same as 'wSerial'. We should perhaps rename wSerial to interleave.
3074-- XXX Document the interleaving behavior of side effects in all the
3075-- interleaving combinators.
3076-- XXX Write time-domain equivalents of these. In the time domain we can
3077-- interleave two streams such that the value of second stream is always taken
3078-- from its last value even if no new value is being yielded, like
3079-- zipWithLatest. It would be something like interleaveWithLatest.
3081-- | Interleaves the outputs of two streams, yielding elements from each stream
3082-- alternately, starting from the first stream. If any of the streams finishes
3083-- early the other stream continues alone until it too finishes.
3085-- >>> :set -XOverloadedStrings
3086-- >>> interleave "ab" ",,,," :: SerialT Identity Char
3087-- fromList "a,b,,,"
3088-- >>> interleave "abcd" ",," :: SerialT Identity Char
3089-- fromList "a,b,cd"
3091-- 'interleave' is dual to 'interleaveMin', it can be called @interleaveMax@.
3093-- Do not use at scale in concatMapWith.
3095-- /Internal/
3096{-# INLINE interleave #-}
3097interleave ::(IsStream t, Monad m) => t m b -> t m b -> t m b
3098interleave m1 m2 = fromStreamD $ D.interleave (toStreamD m1) (toStreamD m2)
3100-- | Interleaves the outputs of two streams, yielding elements from each stream
3101-- alternately, starting from the first stream. As soon as the first stream
3102-- finishes, the output stops, discarding the remaining part of the second
3103-- stream. In this case, the last element in the resulting stream would be from
3104-- the second stream. If the second stream finishes early then the first stream
3105-- still continues to yield elements until it finishes.
3107-- >>> :set -XOverloadedStrings
3108-- >>> interleaveSuffix "abc" ",,,," :: SerialT Identity Char
3109-- fromList "a,b,c,"
3110-- >>> interleaveSuffix "abc" "," :: SerialT Identity Char
3111-- fromList "a,bc"
3113-- 'interleaveSuffix' is a dual of 'interleaveInfix'.
3115-- Do not use at scale in concatMapWith.
3117-- /Internal/
3118{-# INLINE interleaveSuffix #-}
3119interleaveSuffix ::(IsStream t, Monad m) => t m b -> t m b -> t m b
3120interleaveSuffix m1 m2 =
3121 fromStreamD $ D.interleaveSuffix (toStreamD m1) (toStreamD m2)
3123-- | Interleaves the outputs of two streams, yielding elements from each stream
3124-- alternately, starting from the first stream and ending at the first stream.
3125-- If the second stream is longer than the first, elements from the second
3126-- stream are infixed with elements from the first stream. If the first stream
3127-- is longer then it continues yielding elements even after the second stream
3128-- has finished.
3130-- >>> :set -XOverloadedStrings
3131-- >>> interleaveInfix "abc" ",,,," :: SerialT Identity Char
3132-- fromList "a,b,c"
3133-- >>> interleaveInfix "abc" "," :: SerialT Identity Char
3134-- fromList "a,bc"
3136-- 'interleaveInfix' is a dual of 'interleaveSuffix'.
3138-- Do not use at scale in concatMapWith.
3140-- /Internal/
3141{-# INLINE interleaveInfix #-}
3142interleaveInfix ::(IsStream t, Monad m) => t m b -> t m b -> t m b
3143interleaveInfix m1 m2 =
3144 fromStreamD $ D.interleaveInfix (toStreamD m1) (toStreamD m2)
3146-- | Interleaves the outputs of two streams, yielding elements from each stream
3147-- alternately, starting from the first stream. The output stops as soon as any
3148-- of the two streams finishes, discarding the remaining part of the other
3149-- stream. The last element of the resulting stream would be from the longer
3150-- stream.
3152-- >>> :set -XOverloadedStrings
3153-- >>> interleaveMin "ab" ",,,," :: SerialT Identity Char
3154-- fromList "a,b,"
3155-- >>> interleaveMin "abcd" ",," :: SerialT Identity Char
3156-- fromList "a,b,c"
3158-- 'interleaveMin' is dual to 'interleave'.
3160-- Do not use at scale in concatMapWith.
3162-- /Internal/
3163{-# INLINE interleaveMin #-}
3164interleaveMin ::(IsStream t, Monad m) => t m b -> t m b -> t m b
3165interleaveMin m1 m2 = fromStreamD $ D.interleaveMin (toStreamD m1) (toStreamD m2)
3167-- | Schedule the execution of two streams in a fair round-robin manner,
3168-- executing each stream once, alternately. Execution of a stream may not
3169-- necessarily result in an output, a stream may chose to @Skip@ producing an
3170-- element until later giving the other stream a chance to run. Therefore, this
3171-- combinator fairly interleaves the execution of two streams rather than
3172-- fairly interleaving the output of the two streams. This can be useful in
3173-- co-operative multitasking without using explicit threads. This can be used
3174-- as an alternative to `async`.
3176-- Do not use at scale in concatMapWith.
3178-- /Internal/
3179{-# INLINE roundrobin #-}
3180roundrobin ::(IsStream t, Monad m) => t m b -> t m b -> t m b
3181roundrobin m1 m2 = fromStreamD $ D.roundRobin (toStreamD m1) (toStreamD m2)
3183-- | Map a stream producing monadic function on each element of the stream
3184-- and then flatten the results into a single stream. Since the stream
3185-- generation function is monadic, unlike 'concatMap', it can produce an
3186-- effect at the beginning of each iteration of the inner loop.
3188-- @since 0.6.0
3189{-# INLINE concatMapM #-}
3190concatMapM :: (IsStream t, Monad m) => (a -> m (t m b)) -> t m a -> t m b
3191concatMapM f m = fromStreamD $ D.concatMapM (fmap toStreamD . f) (toStreamD m)
3193-- | Given a stream value in the underlying monad, lift and join the underlying
3194-- monad with the stream monad.
3196-- Compare with 'concat' and 'sequence'.
3198-- /Internal/
3200{-# INLINE concatM #-}
3201concatM :: (IsStream t, Monad m) => m (t m a) -> t m a
3202concatM generator = concatMapM (\() -> generator) (yield ())
3204-- | Like 'concatMap' but uses an 'Unfold' for stream generation. Unlike
3205-- 'concatMap' this can fuse the 'Unfold' code with the inner loop and
3206-- therefore provide many times better performance.
3208-- @since 0.7.0
3209{-# INLINE concatUnfold #-}
3210concatUnfold ::(IsStream t, Monad m) => Unfold m a b -> t m a -> t m b
3211concatUnfold u m = fromStreamD $ D.concatMapU u (toStreamD m)
3213-- | Like 'concatUnfold' but interleaves the streams in the same way as
3214-- 'interleave' behaves instead of appending them.
3216-- /Internal/
3217{-# INLINE concatUnfoldInterleave #-}
3218concatUnfoldInterleave ::(IsStream t, Monad m)
3219 => Unfold m a b -> t m a -> t m b
3220concatUnfoldInterleave u m =
3221 fromStreamD $ D.concatUnfoldInterleave u (toStreamD m)
3223-- | Like 'concatUnfold' but executes the streams in the same way as
3224-- 'roundrobin'.
3226-- /Internal/
3227{-# INLINE concatUnfoldRoundrobin #-}
3228concatUnfoldRoundrobin ::(IsStream t, Monad m)
3229 => Unfold m a b -> t m a -> t m b
3230concatUnfoldRoundrobin u m =
3231 fromStreamD $ D.concatUnfoldRoundrobin u (toStreamD m)
3233-- XXX we can swap the order of arguments to gintercalate so that the
3234-- definition of concatUnfold becomes simpler? The first stream should be
3235-- infixed inside the second one. However, if we change the order in
3236-- "interleave" as well similarly, then that will make it a bit unintuitive.
3238-- > concatUnfold unf str =
3239-- > gintercalate unf str (UF.nilM (\_ -> return ())) (repeat ())
3241-- | 'interleaveInfix' followed by unfold and concat.
3243-- /Internal/
3244{-# INLINE gintercalate #-}
3245gintercalate
3246 :: (IsStream t, Monad m)
3247 => Unfold m a c -> t m a -> Unfold m b c -> t m b -> t m c
3248gintercalate unf1 str1 unf2 str2 =
3249 D.fromStreamD $ D.gintercalate
3250 unf1 (D.toStreamD str1)
3251 unf2 (D.toStreamD str2)
3253-- XXX The order of arguments in "intercalate" is consistent with the list
3254-- intercalate but inconsistent with gintercalate and other stream interleaving
3255-- combinators. We can change the order of the arguments in other combinators
3256-- but then 'interleave' combinator may become a bit unintuitive because we
3257-- will be starting with the second stream.
3259-- > intercalate seed unf str = gintercalate unf str unf (repeatM seed)
3260-- > intercalate a unf str = concatUnfold unf $ intersperse a str
3262-- | 'intersperse' followed by unfold and concat.
3264-- > unwords = intercalate " " UF.fromList
3266-- >>> intercalate " " UF.fromList ["abc", "def", "ghi"]
3267-- > "abc def ghi"
3269-- /Internal/
3270{-# INLINE intercalate #-}
3271intercalate :: (IsStream t, Monad m)
3272 => b -> Unfold m b c -> t m b -> t m c
3273intercalate seed unf str = D.fromStreamD $
3274 D.concatMapU unf $ D.intersperse seed (toStreamD str)
3276-- > interpose x unf str = gintercalate unf str UF.identity (repeat x)
3278-- | Unfold the elements of a stream, intersperse the given element between the
3279-- unfolded streams and then concat them into a single stream.
3281-- > unwords = S.interpose ' '
3283-- /Internal/
3284{-# INLINE interpose #-}
3285interpose :: (IsStream t, Monad m)
3286 => c -> Unfold m b c -> t m b -> t m c
3287interpose x unf str =
3288 D.fromStreamD $ D.interpose (return x) unf (D.toStreamD str)
3290-- | 'interleaveSuffix' followed by unfold and concat.
3292-- /Internal/
3293{-# INLINE gintercalateSuffix #-}
3294gintercalateSuffix
3295 :: (IsStream t, Monad m)
3296 => Unfold m a c -> t m a -> Unfold m b c -> t m b -> t m c
3297gintercalateSuffix unf1 str1 unf2 str2 =
3298 D.fromStreamD $ D.gintercalateSuffix
3299 unf1 (D.toStreamD str1)
3300 unf2 (D.toStreamD str2)
3302-- > intercalateSuffix seed unf str = gintercalateSuffix unf str unf (repeatM seed)
3303-- > intercalateSuffix a unf str = concatUnfold unf $ intersperseSuffix a str
3305-- | 'intersperseSuffix' followed by unfold and concat.
3307-- > unlines = intercalateSuffix "\n" UF.fromList
3309-- >>> intercalate "\n" UF.fromList ["abc", "def", "ghi"]
3310-- > "abc\ndef\nghi\n"
3312-- /Internal/
3313{-# INLINE intercalateSuffix #-}
3314intercalateSuffix :: (IsStream t, Monad m)
3315 => b -> Unfold m b c -> t m b -> t m c
3316intercalateSuffix seed unf str = fromStreamD $ D.concatMapU unf
3317 $ D.intersperseSuffix (return seed) (D.toStreamD str)
3319-- interposeSuffix x unf str = gintercalateSuffix unf str UF.identity (repeat x)
3321-- | Unfold the elements of a stream, append the given element after each
3322-- unfolded stream and then concat them into a single stream.
3324-- > unlines = S.interposeSuffix '\n'
3326-- /Internal/
3327{-# INLINE interposeSuffix #-}
3328interposeSuffix :: (IsStream t, Monad m)
3329 => c -> Unfold m b c -> t m b -> t m c
3330interposeSuffix x unf str =
3331 D.fromStreamD $ D.interposeSuffix (return x) unf (D.toStreamD str)
3333------------------------------------------------------------------------------
3334-- Flattening Trees
3335------------------------------------------------------------------------------
3337-- | Like 'iterateM' but using a stream generator function.
3339-- /Internal/
3341{-# INLINE concatMapIterateWith #-}
3342concatMapIterateWith
3343 :: IsStream t
3344 => (t m a -> t m a -> t m a)
3345 -> (a -> t m a)
3346 -> t m a
3347 -> t m a
3348concatMapIterateWith combine f = concatMapWith combine go
3349 where
3350 go x = yield x `combine` concatMapWith combine go (f x)
3352-- concatMapIterateLeftsWith
3354-- | Traverse a forest with recursive tree structures whose non-leaf nodes are
3355-- of type @a@ and leaf nodes are of type @b@, flattening all the trees into
3356-- streams and combining the streams into a single stream consisting of both
3357-- leaf and non-leaf nodes.
3359-- 'concatMapTreeWith' is a generalization of 'concatMap', using a recursive
3360-- feedback loop to append the non-leaf nodes back to the input stream enabling
3361-- recursive traversal. 'concatMap' flattens a single level nesting whereas
3362-- 'concatMapTreeWith' flattens a recursively nested structure.
3364-- Traversing a directory tree recursively is a canonical use case of
3365-- 'concatMapTreeWith'.
3367-- @
3368-- concatMapTreeWith combine f xs = concatMapIterateWith combine g xs
3369-- where
3370-- g (Left tree) = f tree
3371-- g (Right leaf) = nil
3372-- @
3374-- /Internal/
3376{-# INLINE concatMapTreeWith #-}
3377concatMapTreeWith
3378 :: IsStream t
3379 => (t m (Either a b) -> t m (Either a b) -> t m (Either a b))
3380 -> (a -> t m (Either a b))
3381 -> t m (Either a b) -- Should be t m a?
3382 -> t m (Either a b)
3383concatMapTreeWith combine f = concatMapWith combine go
3384 where
3385 go (Left tree) = yield (Left tree) `combine` concatMapWith combine go (f tree)
3386 go (Right leaf) = yield $ Right leaf
3389-- | Like concatMapTreeWith but produces only stream of leaf elements.
3390-- On an either stream, iterate lefts but yield only rights.
3392-- concatMapEitherYieldRightsWith combine f xs =
3393-- catRights $ concatMapTreeWith combine f xs
3395{-# INLINE concatMapEitherYieldRightsWith #-}
3396concatMapEitherYieldRightsWith :: (IsStream t, MonadAsync m)
3397 => _ -> (a -> t m (Either a b)) -> t m (Either a b) -> t m b
3398concatMapEitherYieldRightsWith combine f xs = undefined
3402{-# INLINE concatUnfoldTree #-}
3403concatUnfoldTree :: (IsStream t, MonadAsync m)
3404 => Unfold m a (Either a b) -> t m (Either a b) -> t m (Either a b)
3405concatUnfoldTree unf xs = undefined
3408------------------------------------------------------------------------------
3409-- Feedback loop
3410------------------------------------------------------------------------------
3412-- We can perhaps even implement the SVar using this. The stream we are mapping
3413-- on is the work queue. When evaluated it results in either a leaf element to
3414-- yield or a tail stream to queue back to the work queue.
3416-- | Flatten a stream with a feedback loop back into the input.
3418-- For example, exceptions generated by the output stream can be fed back to
3419-- the input to take any corrective action. The corrective action may be to
3420-- retry the action or do nothing or log the errors. For the retry case we need
3421-- a feedback loop.
3423-- /Internal/
3425{-# INLINE concatMapLoopWith #-}
3426concatMapLoopWith
3427 :: (IsStream t, MonadAsync m)
3428 => (forall x. t m x -> t m x -> t m x)
3429 -> (a -> t m (Either b c))
3430 -> (b -> t m a) -- ^ feedback function to feed @b@ back into input
3431 -> t m a
3432 -> t m c
3433concatMapLoopWith combine f fb xs =
3434 concatMapWith combine go $ concatMapWith combine f xs
3435 where
3436 go (Left b) = concatMapLoopWith combine f fb $ fb b
3437 go (Right c) = yield c
3439-- | Concat a stream of trees, generating only leaves.
3441-- Compare with 'concatMapTreeWith'. While the latter returns all nodes in the
3442-- tree, this one returns only the leaves.
3444-- Traversing a directory tree recursively and yielding on the files is a
3445-- canonical use case of 'concatMapTreeYieldLeavesWith'.
3447-- @
3448-- concatMapTreeYieldLeavesWith combine f = concatMapLoopWith combine f yield
3449-- @
3451-- /Internal/
3453{-# INLINE concatMapTreeYieldLeavesWith #-}
3454concatMapTreeYieldLeavesWith
3455 :: (IsStream t, MonadAsync m)
3456 => (forall x. t m x -> t m x -> t m x)
3457 -> (a -> t m (Either a b))
3458 -> t m a
3459 -> t m b
3460concatMapTreeYieldLeavesWith combine f = concatMapLoopWith combine f yield
3462------------------------------------------------------------------------------
3463-- Parsing
3464------------------------------------------------------------------------------
3466-- Splitting operations that take a predicate and a Fold can be
3467-- expressed using parseMany. Operations like chunksOf, intervalsOf, split*,
3468-- can be expressed using parseMany when used with an appropriate Parser.
3470-- XXX We need takeGE/takeBetween to implement "some" using "many".
3472-- | Apply a 'Parser' repeatedly on a stream and emit the parsed values in the
3473-- output stream.
3475-- This is the streaming equivalent of the 'Streamly.Internal.Data.Parser.many'
3476-- parse combinator.
3478-- >>> S.toList $ S.parseMany (PR.take 2 $ PR.fromFold FL.sum) $ S.fromList [1..10]
3479-- > [3,7,11,15,19]
3481-- >>> S.toList $ S.parseMany (PR.line FL.toList) $ S.fromList "hello\nworld"
3482-- > ["hello\n","world"]
3484-- /Internal
3486{-# INLINE parseMany #-}
3487parseMany
3488 :: (IsStream t, MonadThrow m)
3489 => Parser m a b
3490 -> t m a
3491 -> t m b
3492parseMany p m =
3493 D.fromStreamD $ D.parseMany (PRK.fromParserK p) (D.toStreamD m)
3495-- | @parseManyTill collect test stream@ tries the parser @test@ on the input,
3496-- if @test@ fails it backtracks and tries @collect@, after @collect@ succeeds
3497-- @test@ is tried again and so on. The parser stops when @test@ succeeds. The
3498-- output of @test@ is discarded and the output of @collect@ is emitted in the
3499-- output stream. The parser fails if @collect@ fails.
3501-- /Unimplemented/
3503{-# INLINE parseManyTill #-}
3504parseManyTill ::
3505 -- (IsStream t, MonadThrow m) =>
3506 Parser m a b
3507 -> Parser m a x
3508 -> t m a
3509 -> t m b
3510parseManyTill = undefined
3512-- | Iterate a parser generating function on a stream. The initial value @b@ is
3513-- used to generate the first parser, the parser is applied on the stream and
3514-- the result is used to generate the next parser and so on.
3516-- >>> S.toList $ S.map getSum $ S.parseIterate (\b -> PR.take 2 (FL.mconcatTo b)) 0 $ S.map Sum $ S.fromList [1..10]
3517-- > [3,10,21,36,55,55]
3519-- This is the streaming equivalent of monad like sequenced application of
3520-- parsers where next parser is dependent on the previous parser.
3522-- /Internal/
3524{-# INLINE parseIterate #-}
3525parseIterate
3526 :: (IsStream t, MonadThrow m)
3527 => (b -> Parser m a b)
3528 -> b
3529 -> t m a
3530 -> t m b
3531parseIterate f i m = D.fromStreamD $
3532 D.parseIterate (PRK.fromParserK . f) i (D.toStreamD m)
3534------------------------------------------------------------------------------
3535-- Grouping/Splitting
3536------------------------------------------------------------------------------
3538------------------------------------------------------------------------------
3539-- Grouping without looking at elements
3540------------------------------------------------------------------------------
3542------------------------------------------------------------------------------
3543-- Binary APIs
3544------------------------------------------------------------------------------
3547------------------------------------------------------------------------------
3548-- N-ary APIs
3549------------------------------------------------------------------------------
3551------------------------------------------------------------------------------
3552-- Generalized grouping
3553------------------------------------------------------------------------------
3555-- This combinator is the most general grouping combinator and can be used to
3556-- implement all other grouping combinators.
3558-- XXX check if this can implement the splitOn combinator i.e. we can slide in
3559-- new elements, slide out old elements and incrementally compute the hash.
3560-- Also, can we implement the windowed classification combinators using this?
3562-- In fact this is a parse. Instead of using a special return value in the fold
3563-- we are using a mapping function.
3565-- Note that 'scanl'' (usually followed by a map to extract the desired value
3566-- from the accumulator) can be used to realize many implementations e.g. a
3567-- sliding window implementation. A scan followed by a mapMaybe is also a good
3568-- pattern to express many problems where we want to emit a filtered output and
3569-- not emit an output on every input.
3571-- Passing on of the initial accumulator value to the next fold is equivalent
3572-- to returning the leftover concept.
3575-- | @groupScan splitter fold stream@ folds the input stream using @fold@.
3576-- @splitter@ is applied on the accumulator of the fold every time an item is
3577-- consumed by the fold. The fold continues until @splitter@ returns a 'Just'
3578-- value. A 'Just' result from the @splitter@ specifies a result to be emitted
3579-- in the output stream and the initial value of the accumulator for the next
3580-- group's fold. This allows us to control whether to start fresh for the next
3581-- fold or to continue from the previous fold's output.
3583{-# INLINE groupScan #-}
3584groupScan
3585 :: (IsStream t, Monad m)
3586 => (x -> m (Maybe (b, x))) -> Fold m a x -> t m a -> t m b
3587groupScan split fold m = undefined
3590-- | Group the input stream into groups of @n@ elements each and then fold each
3591-- group using the provided fold function.
3593-- >> S.toList $ S.chunksOf 2 FL.sum (S.enumerateFromTo 1 10)
3594-- > [3,7,11,15,19]
3596-- This can be considered as an n-fold version of 'ltake' where we apply
3597-- 'ltake' repeatedly on the leftover stream until the stream exhausts.
3599-- @since 0.7.0
3600{-# INLINE chunksOf #-}
3601chunksOf
3602 :: (IsStream t, Monad m)
3603 => Int -> Fold m a b -> t m a -> t m b
3604chunksOf n f m = D.fromStreamD $ D.groupsOf n f (D.toStreamD m)
3606-- |
3608-- /Internal/
3609{-# INLINE chunksOf2 #-}
3610chunksOf2
3611 :: (IsStream t, Monad m)
3612 => Int -> m c -> Fold2 m c a b -> t m a -> t m b
3613chunksOf2 n action f m = D.fromStreamD $ D.groupsOf2 n action f (D.toStreamD m)
3615-- | @arraysOf n stream@ groups the elements in the input stream into arrays of
3616-- @n@ elements each.
3618-- Same as the following but may be more efficient:
3620-- > arraysOf n = S.chunksOf n (A.writeN n)
3622-- /Internal/
3623{-# INLINE arraysOf #-}
3624arraysOf :: (IsStream t, MonadIO m, Storable a)
3625 => Int -> t m a -> t m (Array a)
3626arraysOf n = chunksOf n (writeNUnsafe n)
3628-- XXX we can implement this by repeatedly applying the 'lrunFor' fold.
3629-- XXX add this example after fixing the serial stream rate control
3630-- >>> S.toList $ S.take 5 $ intervalsOf 1 FL.sum $ constRate 2 $ S.enumerateFrom 1
3631-- > [3,7,11,15,19]
3633-- | Group the input stream into windows of @n@ second each and then fold each
3634-- group using the provided fold function.
3636-- @since 0.7.0
3637{-# INLINE intervalsOf #-}
3638intervalsOf
3639 :: (IsStream t, MonadAsync m)
3640 => Double -> Fold m a b -> t m a -> t m b
3641intervalsOf n f xs =
3642 splitWithSuffix isNothing (FL.lcatMaybes f)
3643 (interjectSuffix n (return Nothing) (Serial.map Just xs))
3645------------------------------------------------------------------------------
3646-- N-ary APIs
3647------------------------------------------------------------------------------
3649-- | @groupsBy cmp f $ S.fromList [a,b,c,...]@ assigns the element @a@ to the
3650-- first group, if @b \`cmp` a@ is 'True' then @b@ is also assigned to the same
3651-- group. If @c \`cmp` a@ is 'True' then @c@ is also assigned to the same
3652-- group and so on. When the comparison fails a new group is started. Each
3653-- group is folded using the fold @f@ and the result of the fold is emitted in
3654-- the output stream.
3656-- >>> S.toList $ S.groupsBy (>) FL.toList $ S.fromList [1,3,7,0,2,5]
3657-- > [[1,3,7],[0,2,5]]
3659-- @since 0.7.0
3660{-# INLINE groupsBy #-}
3661groupsBy
3662 :: (IsStream t, Monad m)
3663 => (a -> a -> Bool)
3664 -> Fold m a b
3665 -> t m a
3666 -> t m b
3667groupsBy cmp f m = D.fromStreamD $ D.groupsBy cmp f (D.toStreamD m)
3669-- | Unlike @groupsBy@ this function performs a rolling comparison of two
3670-- successive elements in the input stream. @groupsByRolling cmp f $ S.fromList
3671-- [a,b,c,...]@ assigns the element @a@ to the first group, if @a \`cmp` b@ is
3672-- 'True' then @b@ is also assigned to the same group. If @b \`cmp` c@ is
3673-- 'True' then @c@ is also assigned to the same group and so on. When the
3674-- comparison fails a new group is started. Each group is folded using the fold
3675-- @f@.
3677-- >>> S.toList $ S.groupsByRolling (\a b -> a + 1 == b) FL.toList $ S.fromList [1,2,3,7,8,9]
3678-- > [[1,2,3],[7,8,9]]
3680-- @since 0.7.0
3681{-# INLINE groupsByRolling #-}
3682groupsByRolling
3683 :: (IsStream t, Monad m)
3684 => (a -> a -> Bool)
3685 -> Fold m a b
3686 -> t m a
3687 -> t m b
3688groupsByRolling cmp f m = D.fromStreamD $ D.groupsRollingBy cmp f (D.toStreamD m)
3690-- |
3691-- > groups = groupsBy (==)
3692-- > groups = groupsByRolling (==)
3694-- Groups contiguous spans of equal elements together in individual groups.
3696-- >>> S.toList $ S.groups FL.toList $ S.fromList [1,1,2,2]
3697-- > [[1,1],[2,2]]
3699-- @since 0.7.0
3700groups :: (IsStream t, Monad m, Eq a) => Fold m a b -> t m a -> t m b
3701groups = groupsBy (==)
3703------------------------------------------------------------------------------
3704-- N-ary split on a predicate
3705------------------------------------------------------------------------------
3707-- TODO: Use a Splitter configuration similar to the "split" package to make it
3708-- possible to express all splitting combinations. In general, we can have
3709-- infix/suffix/prefix/condensing of separators, dropping both leading/trailing
3710-- separators. We can have a single split operation taking the splitter config
3711-- as argument.
3713-- | Split on an infixed separator element, dropping the separator. Splits the
3714-- stream on separator elements determined by the supplied predicate, separator
3715-- is considered as infixed between two segments, if one side of the separator
3716-- is missing then it is parsed as an empty stream. The supplied 'Fold' is
3717-- applied on the split segments. With '-' representing non-separator elements
3718-- and '.' as separator, 'splitOn' splits as follows:
3720-- @
3721-- "--.--" => "--" "--"
3722-- "--." => "--" ""
3723-- ".--" => "" "--"
3724-- @
3726-- @splitOn (== x)@ is an inverse of @intercalate (S.yield x)@
3728-- Let's use the following definition for illustration:
3730-- > splitOn' p xs = S.toList $ S.splitOn p (FL.toList) (S.fromList xs)
3732-- >>> splitOn' (== '.') ""
3733-- [""]
3735-- >>> splitOn' (== '.') "."
3736-- ["",""]
3738-- >>> splitOn' (== '.') ".a"
3739-- > ["","a"]
3741-- >>> splitOn' (== '.') "a."
3742-- > ["a",""]
3744-- >>> splitOn' (== '.') "a.b"
3745-- > ["a","b"]
3747-- >>> splitOn' (== '.') "a..b"
3748-- > ["a","","b"]
3750-- @since 0.7.0
3752-- This can be considered as an n-fold version of 'breakOn' where we apply
3753-- 'breakOn' successively on the input stream, dropping the first element
3754-- of the second segment after each break.
3756{-# INLINE splitOn #-}
3757splitOn
3758 :: (IsStream t, Monad m)
3759 => (a -> Bool) -> Fold m a b -> t m a -> t m b
3760splitOn predicate f m =
3761 D.fromStreamD $ D.splitBy predicate f (D.toStreamD m)
3763-- | Like 'splitOn' but the separator is considered as suffixed to the segments
3764-- in the stream. A missing suffix at the end is allowed. A separator at the
3765-- beginning is parsed as empty segment. With '-' representing elements and
3766-- '.' as separator, 'splitOnSuffix' splits as follows:
3768-- @
3769-- "--.--." => "--" "--"
3770-- "--.--" => "--" "--"
3771-- ".--." => "" "--"
3772-- @
3774-- > splitOnSuffix' p xs = S.toList $ S.splitSuffixBy p (FL.toList) (S.fromList xs)
3776-- >>> splitOnSuffix' (== '.') ""
3777-- []
3779-- >>> splitOnSuffix' (== '.') "."
3780-- [""]
3782-- >>> splitOnSuffix' (== '.') "a"
3783-- ["a"]
3785-- >>> splitOnSuffix' (== '.') ".a"
3786-- > ["","a"]
3788-- >>> splitOnSuffix' (== '.') "a."
3789-- > ["a"]
3791-- >>> splitOnSuffix' (== '.') "a.b"
3792-- > ["a","b"]
3794-- >>> splitOnSuffix' (== '.') "a.b."
3795-- > ["a","b"]
3797-- >>> splitOnSuffix' (== '.') "a..b.."
3798-- > ["a","","b",""]
3800-- > lines = splitOnSuffix (== '\n')
3802-- @since 0.7.0
3804-- This can be considered as an n-fold version of 'breakPost' where we apply
3805-- 'breakPost' successively on the input stream, dropping the first element
3806-- of the second segment after each break.
3808{-# INLINE splitOnSuffix #-}
3809splitOnSuffix
3810 :: (IsStream t, Monad m)
3811 => (a -> Bool) -> Fold m a b -> t m a -> t m b
3812splitOnSuffix predicate f m =
3813 D.fromStreamD $ D.splitSuffixBy predicate f (D.toStreamD m)
3815-- | Like 'splitOn' after stripping leading, trailing, and repeated separators.
3816-- Therefore, @".a..b."@ with '.' as the separator would be parsed as
3817-- @["a","b"]@. In other words, its like parsing words from whitespace
3818-- separated text.
3820-- > wordsBy' p xs = S.toList $ S.wordsBy p (FL.toList) (S.fromList xs)
3822-- >>> wordsBy' (== ',') ""
3823-- > []
3825-- >>> wordsBy' (== ',') ","
3826-- > []
3828-- >>> wordsBy' (== ',') ",a,,b,"
3829-- > ["a","b"]
3831-- > words = wordsBy isSpace
3833-- @since 0.7.0
3835-- It is equivalent to splitting in any of the infix/prefix/suffix styles
3836-- followed by removal of empty segments.
3837{-# INLINE wordsBy #-}
3838wordsBy
3839 :: (IsStream t, Monad m)
3840 => (a -> Bool) -> Fold m a b -> t m a -> t m b
3841wordsBy predicate f m =
3842 D.fromStreamD $ D.wordsBy predicate f (D.toStreamD m)
3844-- | Like 'splitOnSuffix' but keeps the suffix attached to the resulting
3845-- splits.
3847-- > splitWithSuffix' p xs = S.toList $ S.splitWithSuffix p (FL.toList) (S.fromList xs)
3849-- >>> splitWithSuffix' (== '.') ""
3850-- []
3852-- >>> splitWithSuffix' (== '.') "."
3853-- ["."]
3855-- >>> splitWithSuffix' (== '.') "a"
3856-- ["a"]
3858-- >>> splitWithSuffix' (== '.') ".a"
3859-- > [".","a"]
3861-- >>> splitWithSuffix' (== '.') "a."
3862-- > ["a."]
3864-- >>> splitWithSuffix' (== '.') "a.b"
3865-- > ["a.","b"]
3867-- >>> splitWithSuffix' (== '.') "a.b."
3868-- > ["a.","b."]
3870-- >>> splitWithSuffix' (== '.') "a..b.."
3871-- > ["a.",".","b.","."]
3873-- @since 0.7.0
3875-- This can be considered as an n-fold version of 'breakPost' where we apply
3876-- 'breakPost' successively on the input stream.
3878{-# INLINE splitWithSuffix #-}
3879splitWithSuffix
3880 :: (IsStream t, Monad m)
3881 => (a -> Bool) -> Fold m a b -> t m a -> t m b
3882splitWithSuffix predicate f m =
3883 D.fromStreamD $ D.splitSuffixBy' predicate f (D.toStreamD m)
3885------------------------------------------------------------------------------
3886-- Split on a delimiter sequence
3887------------------------------------------------------------------------------
3889-- Int list examples for splitOn:
3891-- >>> splitList [] [1,2,3,3,4]
3892-- > [[1],[2],[3],[3],[4]]
3894-- >>> splitList [5] [1,2,3,3,4]
3895-- > [[1,2,3,3,4]]
3897-- >>> splitList [1] [1,2,3,3,4]
3898-- > [[],[2,3,3,4]]
3900-- >>> splitList [4] [1,2,3,3,4]
3901-- > [[1,2,3,3],[]]
3903-- >>> splitList [2] [1,2,3,3,4]
3904-- > [[1],[3,3,4]]
3906-- >>> splitList [3] [1,2,3,3,4]
3907-- > [[1,2],[],[4]]
3909-- >>> splitList [3,3] [1,2,3,3,4]
3910-- > [[1,2],[4]]
3912-- >>> splitList [1,2,3,3,4] [1,2,3,3,4]
3913-- > [[],[]]
3915-- | Like 'splitOn' but the separator is a sequence of elements instead of a
3916-- single element.
3918-- For illustration, let's define a function that operates on pure lists:
3920-- @
3921-- splitOnSeq' pat xs = S.toList $ S.splitOnSeq (A.fromList pat) (FL.toList) (S.fromList xs)
3922-- @
3924-- >>> splitOnSeq' "" "hello"
3925-- > ["h","e","l","l","o"]
3927-- >>> splitOnSeq' "hello" ""
3928-- > [""]
3930-- >>> splitOnSeq' "hello" "hello"
3931-- > ["",""]
3933-- >>> splitOnSeq' "x" "hello"
3934-- > ["hello"]
3936-- >>> splitOnSeq' "h" "hello"
3937-- > ["","ello"]
3939-- >>> splitOnSeq' "o" "hello"
3940-- > ["hell",""]
3942-- >>> splitOnSeq' "e" "hello"
3943-- > ["h","llo"]
3945-- >>> splitOnSeq' "l" "hello"
3946-- > ["he","","o"]
3948-- >>> splitOnSeq' "ll" "hello"
3949-- > ["he","o"]
3951-- 'splitOnSeq' is an inverse of 'intercalate'. The following law always holds:
3953-- > intercalate . splitOn == id
3955-- The following law holds when the separator is non-empty and contains none of
3956-- the elements present in the input lists:
3958-- > splitOn . intercalate == id
3960-- /Internal/
3962-- XXX We can use a polymorphic vector implemented by Array# to represent the
3963-- sequence, that way we can avoid the Storable constraint. If we still need
3964-- Storable Array for performance, we can use a separate splitOnArray API for
3965-- that. We can also have an API where the sequence itself is a lazy stream, so
3966-- that we can search files in files for example.
3967{-# INLINE splitOnSeq #-}
3968splitOnSeq
3969 :: (IsStream t, MonadIO m, Storable a, Enum a, Eq a)
3970 => Array a -> Fold m a b -> t m a -> t m b
3971splitOnSeq patt f m = D.fromStreamD $ D.splitOn patt f (D.toStreamD m)
3974-- This can be implemented easily using Rabin Karp
3975-- | Split on any one of the given patterns.
3976{-# INLINE splitOnAny #-}
3977splitOnAny
3978 :: (IsStream t, Monad m, Storable a, Integral a)
3979 => [Array a] -> Fold m a b -> t m a -> t m b
3980splitOnAny subseq f m = undefined -- D.fromStreamD $ D.splitOnAny f subseq (D.toStreamD m)
3983-- | Like 'splitSuffixBy' but the separator is a sequence of elements, instead
3984-- of a predicate for a single element.
3986-- > splitSuffixOn_ pat xs = S.toList $ S.splitSuffixOn (A.fromList pat) (FL.toList) (S.fromList xs)
3988-- >>> splitSuffixOn_ "." ""
3989-- [""]
3991-- >>> splitSuffixOn_ "." "."
3992-- [""]
3994-- >>> splitSuffixOn_ "." "a"
3995-- ["a"]
3997-- >>> splitSuffixOn_ "." ".a"
3998-- > ["","a"]
4000-- >>> splitSuffixOn_ "." "a."
4001-- > ["a"]
4003-- >>> splitSuffixOn_ "." "a.b"
4004-- > ["a","b"]
4006-- >>> splitSuffixOn_ "." "a.b."
4007-- > ["a","b"]
4009-- >>> splitSuffixOn_ "." "a..b.."
4010-- > ["a","","b",""]
4012-- > lines = splitSuffixOn "\n"
4014-- /Internal/
4015{-# INLINE splitOnSuffixSeq #-}
4016splitOnSuffixSeq
4017 :: (IsStream t, MonadIO m, Storable a, Enum a, Eq a)
4018 => Array a -> Fold m a b -> t m a -> t m b
4019splitOnSuffixSeq patt f m =
4020 D.fromStreamD $ D.splitSuffixOn False patt f (D.toStreamD m)
4023-- | Like 'splitOn' but drops any empty splits.
4025{-# INLINE wordsOn #-}
4026wordsOn
4027 :: (IsStream t, Monad m, Storable a, Eq a)
4028 => Array a -> Fold m a b -> t m a -> t m b
4029wordsOn subseq f m = undefined -- D.fromStreamD $ D.wordsOn f subseq (D.toStreamD m)
4032-- XXX use a non-monadic intersperse to remove the MonadAsync constraint.
4034-- | Like 'splitOnSeq' but splits the separator as well, as an infix token.
4036-- > splitOn'_ pat xs = S.toList $ S.splitOn' (A.fromList pat) (FL.toList) (S.fromList xs)
4038-- >>> splitOn'_ "" "hello"
4039-- > ["h","","e","","l","","l","","o"]
4041-- >>> splitOn'_ "hello" ""
4042-- > [""]
4044-- >>> splitOn'_ "hello" "hello"
4045-- > ["","hello",""]
4047-- >>> splitOn'_ "x" "hello"
4048-- > ["hello"]
4050-- >>> splitOn'_ "h" "hello"
4051-- > ["","h","ello"]
4053-- >>> splitOn'_ "o" "hello"
4054-- > ["hell","o",""]
4056-- >>> splitOn'_ "e" "hello"
4057-- > ["h","e","llo"]
4059-- >>> splitOn'_ "l" "hello"
4060-- > ["he","l","","l","o"]
4062-- >>> splitOn'_ "ll" "hello"
4063-- > ["he","ll","o"]
4065-- /Internal/
4066{-# INLINE splitBySeq #-}
4067splitBySeq
4068 :: (IsStream t, MonadAsync m, Storable a, Enum a, Eq a)
4069 => Array a -> Fold m a b -> t m a -> t m b
4070splitBySeq patt f m =
4071 intersperseM (fold f (A.toStream patt)) $ splitOnSeq patt f m
4073-- | Like 'splitSuffixOn' but keeps the suffix intact in the splits.
4075-- > splitSuffixOn'_ pat xs = S.toList $ FL.splitSuffixOn' (A.fromList pat) (FL.toList) (S.fromList xs)
4077-- >>> splitSuffixOn'_ "." ""
4078-- [""]
4080-- >>> splitSuffixOn'_ "." "."
4081-- ["."]
4083-- >>> splitSuffixOn'_ "." "a"
4084-- ["a"]
4086-- >>> splitSuffixOn'_ "." ".a"
4087-- > [".","a"]
4089-- >>> splitSuffixOn'_ "." "a."
4090-- > ["a."]
4092-- >>> splitSuffixOn'_ "." "a.b"
4093-- > ["a.","b"]
4095-- >>> splitSuffixOn'_ "." "a.b."
4096-- > ["a.","b."]
4098-- >>> splitSuffixOn'_ "." "a..b.."
4099-- > ["a.",".","b.","."]
4101-- /Internal/
4102{-# INLINE splitWithSuffixSeq #-}
4103splitWithSuffixSeq
4104 :: (IsStream t, MonadIO m, Storable a, Enum a, Eq a)
4105 => Array a -> Fold m a b -> t m a -> t m b
4106splitWithSuffixSeq patt f m =
4107 D.fromStreamD $ D.splitSuffixOn True patt f (D.toStreamD m)
4110-- This can be implemented easily using Rabin Karp
4111-- | Split post any one of the given patterns.
4112{-# INLINE splitSuffixOnAny #-}
4113splitSuffixOnAny
4114 :: (IsStream t, Monad m, Storable a, Integral a)
4115 => [Array a] -> Fold m a b -> t m a -> t m b
4116splitSuffixOnAny subseq f m = undefined
4117 -- D.fromStreamD $ D.splitPostAny f subseq (D.toStreamD m)
4120------------------------------------------------------------------------------
4121-- Nested Split
4122------------------------------------------------------------------------------
4124-- | @splitInnerBy splitter joiner stream@ splits the inner containers @f a@ of
4125-- an input stream @t m (f a)@ using the @splitter@ function. Container
4126-- elements @f a@ are collected until a split occurs, then all the elements
4127-- before the split are joined using the @joiner@ function.
4129-- For example, if we have a stream of @Array Word8@, we may want to split the
4130-- stream into arrays representing lines separated by '\n' byte such that the
4131-- resulting stream after a split would be one array for each line.
4133-- CAUTION! This is not a true streaming function as the container size after
4134-- the split and merge may not be bounded.
4136-- /Internal/
4137{-# INLINE splitInnerBy #-}
4138splitInnerBy
4139 :: (IsStream t, Monad m)
4140 => (f a -> m (f a, Maybe (f a))) -- splitter
4141 -> (f a -> f a -> m (f a)) -- joiner
4142 -> t m (f a)
4143 -> t m (f a)
4144splitInnerBy splitter joiner xs =
4145 D.fromStreamD $ D.splitInnerBy splitter joiner $ D.toStreamD xs
4147-- | Like 'splitInnerBy' but splits assuming the separator joins the segment in
4148-- a suffix style.
4150-- /Internal/
4151{-# INLINE splitInnerBySuffix #-}
4152splitInnerBySuffix
4153 :: (IsStream t, Monad m, Eq (f a), Monoid (f a))
4154 => (f a -> m (f a, Maybe (f a))) -- splitter
4155 -> (f a -> f a -> m (f a)) -- joiner
4156 -> t m (f a)
4157 -> t m (f a)
4158splitInnerBySuffix splitter joiner xs =
4159 D.fromStreamD $ D.splitInnerBySuffix splitter joiner $ D.toStreamD xs
4161------------------------------------------------------------------------------
4162-- Reorder in sequence
4163------------------------------------------------------------------------------
4166-- Buffer until the next element in sequence arrives. The function argument
4167-- determines the difference in sequence numbers. This could be useful in
4168-- implementing sequenced streams, for example, TCP reassembly.
4169{-# INLINE reassembleBy #-}
4170reassembleBy
4171 :: (IsStream t, Monad m)
4172 => Fold m a b
4173 -> (a -> a -> Int)
4174 -> t m a
4175 -> t m b
4176reassembleBy = undefined
4179------------------------------------------------------------------------------
4180-- Distributing
4181------------------------------------------------------------------------------
4183-- | Tap the data flowing through a stream into a 'Fold'. For example, you may
4184-- add a tap to log the contents flowing through the stream. The fold is used
4185-- only for effects, its result is discarded.
4187-- @
4188-- Fold m a b
4189-- |
4190-- -----stream m a ---------------stream m a-----
4192-- @
4194-- @
4195-- > S.drain $ S.tap (FL.drainBy print) (S.enumerateFromTo 1 2)
4196-- 1
4197-- 2
4198-- @
4200-- Compare with 'trace'.
4202-- @since 0.7.0
4203{-# INLINE tap #-}
4204tap :: (IsStream t, Monad m) => FL.Fold m a b -> t m a -> t m a
4205tap f xs = D.fromStreamD $ D.tap f (D.toStreamD xs)
4207-- | @tapOffsetEvery offset n@ taps every @n@th element in the stream
4208-- starting at @offset@. @offset@ can be between @0@ and @n - 1@. Offset 0
4209-- means start at the first element in the stream. If the offset is outside
4210-- this range then @offset `mod` n@ is used as offset.
4212-- @
4213-- >>> S.drain $ S.tapOffsetEvery 0 2 (FL.mapM print FL.toList) $ S.enumerateFromTo 0 10
4214-- > [0,2,4,6,8,10]
4215-- @
4217-- /Internal/
4219{-# INLINE tapOffsetEvery #-}
4220tapOffsetEvery :: (IsStream t, Monad m)
4221 => Int -> Int -> FL.Fold m a b -> t m a -> t m a
4222tapOffsetEvery offset n f xs =
4223 D.fromStreamD $ D.tapOffsetEvery offset n f (D.toStreamD xs)
4225-- | Redirect a copy of the stream to a supplied fold and run it concurrently
4226-- in an independent thread. The fold may buffer some elements. The buffer size
4227-- is determined by the prevailing 'maxBuffer' setting.
4229-- @
4230-- Stream m a -> m b
4231-- |
4232-- -----stream m a ---------------stream m a-----
4234-- @
4236-- @
4237-- > S.drain $ S.tapAsync (S.mapM_ print) (S.enumerateFromTo 1 2)
4238-- 1
4239-- 2
4240-- @
4242-- Exceptions from the concurrently running fold are propagated to the current
4243-- computation. Note that, because of buffering in the fold, exceptions may be
4244-- delayed and may not correspond to the current element being processed in the
4245-- parent stream, but we guarantee that before the parent stream stops the tap
4246-- finishes and all exceptions from it are drained.
4249-- Compare with 'tap'.
4251-- /Internal/
4252{-# INLINE tapAsync #-}
4253tapAsync :: (IsStream t, MonadAsync m) => FL.Fold m a b -> t m a -> t m a
4254tapAsync f xs = D.fromStreamD $ D.tapAsync f (D.toStreamD xs)
4256-- | @pollCounts predicate transform fold stream@ counts those elements in the
4257-- stream that pass the @predicate@. The resulting count stream is sent to
4258-- another thread which transforms it using @transform@ and then folds it using
4259-- @fold@. The thread is automatically cleaned up if the stream stops or
4260-- aborts due to exception.
4262-- For example, to print the count of elements processed every second:
4264-- @
4265-- > S.drain $ S.pollCounts (const True) (S.rollingMap (-) . S.delayPost 1) (FL.drainBy print)
4266-- $ S.enumerateFrom 0
4267-- @
4269-- Note: This may not work correctly on 32-bit machines.
4271-- /Internal/
4273{-# INLINE pollCounts #-}
4274pollCounts ::
4275 (IsStream t, MonadAsync m)
4276 => (a -> Bool)
4277 -> (t m Int -> t m Int)
4278 -> Fold m Int b
4279 -> t m a
4280 -> t m a
4281pollCounts predicate transf f xs =
4282 D.fromStreamD
4283 $ D.pollCounts predicate (D.toStreamD . transf . D.fromStreamD) f
4284 $ D.toStreamD xs
4286-- | Calls the supplied function with the number of elements consumed
4287-- every @n@ seconds. The given function is run in a separate thread
4288-- until the end of the stream. In case there is an exception in the
4289-- stream the thread is killed during the next major GC.
4291-- Note: The action is not guaranteed to run if the main thread exits.
4293-- @
4294-- > delay n = threadDelay (round $ n * 1000000) >> return n
4295-- > S.drain $ S.tapRate 2 (\\n -> print $ show n ++ " elements processed") (delay 1 S.|: delay 0.5 S.|: delay 0.5 S.|: S.nil)
4296-- 2 elements processed
4297-- 1 elements processed
4298-- @
4300-- Note: This may not work correctly on 32-bit machines.
4302-- /Internal/
4303{-# INLINE tapRate #-}
4304tapRate ::
4305 (IsStream t, MonadAsync m, MonadCatch m)
4306 => Double
4307 -> (Int -> m b)
4308 -> t m a
4309 -> t m a
4310tapRate n f xs = D.fromStreamD $ D.tapRate n f $ D.toStreamD xs
4312-- | Apply a monadic function to each element flowing through the stream and
4313-- discard the results.
4315-- @
4316-- > S.drain $ S.trace print (S.enumerateFromTo 1 2)
4317-- 1
4318-- 2
4319-- @
4321-- Compare with 'tap'.
4323-- @since 0.7.0
4324{-# INLINE trace #-}
4325trace :: (IsStream t, MonadAsync m) => (a -> m b) -> t m a -> t m a
4326trace f = mapM (\x -> void (f x) >> return x)
4328-- | Perform a side effect before yielding each element of the stream and
4329-- discard the results.
4331-- @
4332-- > S.drain $ S.trace_ (print "got here") (S.enumerateFromTo 1 2)
4333-- "got here"
4334-- "got here"
4335-- @
4337-- See also: 'trace', 'interspersePrefix_'
4339-- /Internal/
4340{-# INLINE trace_ #-}
4341trace_ :: (IsStream t, Monad m) => m b -> t m a -> t m a
4342trace_ eff = Serial.mapM (\x -> eff >> return x)
4344------------------------------------------------------------------------------
4345-- Windowed classification
4346------------------------------------------------------------------------------
4348-- We divide the stream into windows or chunks in space or time and each window
4349-- can be associated with a key, all events associated with a particular key in
4350-- the window can be folded to a single result. The stream can be split into
4351-- windows by size or by using a split predicate on the elements in the stream.
4352-- For example, when we receive a closing flag, we can close the window.
4354-- A "chunk" is a space window and a "session" is a time window. Are there any
4355-- other better short words to describe them. An alternative is to use
4356-- "swindow" and "twindow". Another word for "session" could be "spell".
4358-- TODO: To mark the position in space or time we can have Indexed or
4359-- TimeStamped types. That can make it easy to deal with the position indices
4360-- or timestamps.
4362------------------------------------------------------------------------------
4363-- Keyed Sliding Windows
4364------------------------------------------------------------------------------
4367{-# INLINABLE classifySlidingChunks #-}
4368classifySlidingChunks
4369 :: (IsStream t, MonadAsync m, Ord k)
4370 => Int -- ^ window size
4371 -> Int -- ^ window slide
4372 -> Fold m a b -- ^ Fold to be applied to window events
4373 -> t m (k, a, Bool) -- ^ window key, data, close event
4374 -> t m (k, b)
4375classifySlidingChunks wsize wslide (Fold step initial extract) str
4376 = undefined
4378-- XXX Another variant could be to slide the window on an event, e.g. in TCP we
4379-- slide the send window when an ack is received and we slide the receive
4380-- window when a sequence is complete. Sliding is stateful in case of TCP,
4381-- sliding releases the send buffer or makes data available to the user from
4382-- the receive buffer.
4383{-# INLINABLE classifySlidingSessions #-}
4384classifySlidingSessions
4385 :: (IsStream t, MonadAsync m, Ord k)
4386 => Double -- ^ timer tick in seconds
4387 -> Double -- ^ time window size
4388 -> Double -- ^ window slide
4389 -> Fold m a b -- ^ Fold to be applied to window events
4390 -> t m (k, a, Bool, AbsTime) -- ^ window key, data, close flag, timestamp
4391 -> t m (k, b)
4392classifySlidingSessions tick interval slide (Fold step initial extract) str
4393 = undefined
4396------------------------------------------------------------------------------
4397-- Sliding Window Buffers
4398------------------------------------------------------------------------------
4400-- These buffered versions could be faster than concurrent incremental folds of
4401-- all overlapping windows as in many cases we may not need all the values to
4402-- compute the fold, we can just compute the result using the old value and new
4403-- value. However, we may need the buffer once in a while, for example for
4404-- string search we usually compute the hash incrementally but when the hash
4405-- matches the hash of the pattern we need to compare the whole string.
4407-- XXX we should be able to implement sequence based splitting combinators
4408-- using this combinator.
4411-- | Buffer n elements of the input in a ring buffer. When t new elements are
4412-- collected, slide the window to remove the same number of oldest elements,
4413-- insert the new elements, and apply an incremental fold on the sliding
4414-- window, supplying the outgoing elements, the new ring buffer as arguments.
4415slidingChunkBuffer
4416 :: (IsStream t, Monad m, Ord a, Storable a)
4417 => Int -- window size
4418 -> Int -- window slide
4419 -> Fold m (Ring a, Array a) b
4420 -> t m a
4421 -> t m b
4422slidingChunkBuffer = undefined
4424-- Buffer n seconds worth of stream elements of the input in a radix tree.
4425-- Every t seconds, remove the items that are older than n seconds, and apply
4426-- an incremental fold on the sliding window, supplying the outgoing elements,
4427-- and the new radix tree buffer as arguments.
4428slidingSessionBuffer
4429 :: (IsStream t, Monad m, Ord a, Storable a)
4430 => Int -- window size
4431 -> Int -- tick size
4432 -> Fold m (RTree a, Array a) b
4433 -> t m a
4434 -> t m b
4435slidingSessionBuffer = undefined
4438------------------------------------------------------------------------------
4439-- Keyed Session Windows
4440------------------------------------------------------------------------------
4443-- | Keyed variable size space windows. Close the window if we do not receive a
4444-- window event in the next "spaceout" elements.
4445{-# INLINABLE classifyChunksBy #-}
4446classifyChunksBy
4447 :: (IsStream t, MonadAsync m, Ord k)
4448 => Int -- ^ window spaceout (spread)
4449 -> Bool -- ^ reset the spaceout when a chunk window element is received
4450 -> Fold m a b -- ^ Fold to be applied to chunk window elements
4451 -> t m (k, a, Bool) -- ^ chunk key, data, last element
4452 -> t m (k, b)
4453classifyChunksBy spanout reset (Fold step initial extract) str = undefined
4455-- | Like 'classifyChunksOf' but the chunk size is reset if an element is
4456-- received within the chunk size window. The chunk gets closed only if no
4457-- element is received within the chunk window.
4459{-# INLINABLE classifyKeepAliveChunks #-}
4460classifyKeepAliveChunks
4461 :: (IsStream t, MonadAsync m, Ord k)
4462 => Int -- ^ window spaceout (spread)
4463 -> Fold m a b -- ^ Fold to be applied to chunk window elements
4464 -> t m (k, a, Bool) -- ^ chunk key, data, last element
4465 -> t m (k, b)
4466classifyKeepAliveChunks spanout = classifyChunksBy spanout True
4469data SessionState t m k a b = SessionState
4470 { sessionCurTime :: !AbsTime -- ^ time since last event
4471 , sessionEventTime :: !AbsTime -- ^ time as per last event
4472 , sessionCount :: !Int -- ^ total number sessions in progress
4473 , sessionTimerHeap :: H.Heap (H.Entry AbsTime k) -- ^ heap for timeouts
4474 , sessionKeyValueMap :: Map.Map k a -- ^ Stored sessions for keys
4475 , sessionOutputStream :: t (m :: Type -> Type) (k, b) -- ^ Completed sessions
4478#undef Type
4480-- | @classifySessionsBy tick timeout idle pred f stream@ groups timestamped
4481-- events in an input event stream into sessions based on a session key. Each
4482-- element in the stream is an event consisting of a triple @(session key,
4483-- sesssion data, timestamp)@. @session key@ is a key that uniquely identifies
4484-- the session. All the events belonging to a session are folded using the
4485-- fold @f@ until the fold returns a 'Left' result or a timeout has occurred.
4486-- The session key and the result of the fold are emitted in the output stream
4487-- when the session is purged.
4489-- When @idle@ is 'False', @timeout@ is the maximum lifetime of a session in
4490-- seconds, measured from the @timestamp@ of the first event in that session.
4491-- When @idle@ is 'True' then the timeout is an idle timeout, it is reset after
4492-- every event received in the session.
4494-- @timestamp@ in an event characterizes the time when the input event was
4495-- generated, this is an absolute time measured from some @Epoch@. The notion
4496-- of current time is maintained by a monotonic event time clock using the
4497-- timestamps seen in the input stream. The latest timestamp seen till now is
4498-- used as the base for the current time. When no new events are seen, a timer
4499-- is started with a tick duration specified by @tick@. This timer is used to
4500-- detect session timeouts in the absence of new events.
4502-- The predicate @pred@ is invoked with the current session count, if it
4503-- returns 'True' a session is ejected from the session cache before inserting
4504-- a new session. This could be useful to alert or eject sessions when the
4505-- number of sessions becomes too high.
4507-- /Internal/
4510-- XXX Perhaps we should use an "Event a" type to represent timestamped data.
4511{-# INLINABLE classifySessionsBy #-}
4512classifySessionsBy
4513 :: (IsStream t, MonadAsync m, Ord k)
4514 => Double -- ^ timer tick in seconds
4515 -> Double -- ^ session timeout in seconds
4516 -> Bool -- ^ reset the timeout when an event is received
4517 -> (Int -> m Bool) -- ^ predicate to eject sessions based on session count
4518 -> Fold m a (Either b b) -- ^ Fold to be applied to session events
4519 -> t m (k, a, AbsTime) -- ^ session key, data, timestamp
4520 -> t m (k, b) -- ^ session key, fold result
4521classifySessionsBy tick tmout reset ejectPred
4522 (Fold step initial extract) str =
4523 concatMap sessionOutputStream $
4524 scanlMAfter' sstep (return szero) flush stream
4526 where
4528 timeoutMs = toRelTime (round (tmout * 1000) :: MilliSecond64)
4529 tickMs = toRelTime (round (tick * 1000) :: MilliSecond64)
4530 szero = SessionState
4531 { sessionCurTime = toAbsTime (0 :: MilliSecond64)
4532 , sessionEventTime = toAbsTime (0 :: MilliSecond64)
4533 , sessionCount = 0
4534 , sessionTimerHeap = H.empty
4535 , sessionKeyValueMap = Map.empty
4536 , sessionOutputStream = K.nil
4539 -- We can eject sessions based on the current session count to limit
4540 -- memory consumption. There are two possible strategies:
4541 --
4542 -- 1) Eject old sessions or sessions beyond a certain/lower timeout
4543 -- threshold even before timeout, effectively reduce the timeout.
4544 -- 2) Drop creation of new sessions but keep accepting new events for the
4545 -- old ones.
4546 --
4547 -- We use the first strategy as of now.
4549 -- Got a new stream input element
4550 sstep session@SessionState{..} (Just (key, value, timestamp)) = do
4551 -- XXX we should use a heap in pinned memory to scale it to a large
4552 -- size
4553 --
4554 -- To detect session inactivity we keep a timestamp of the latest event
4555 -- in the Map along with the fold result. When we purge the session
4556 -- from the heap we match the timestamp in the heap with the timestamp
4557 -- in the Map, if the latest timestamp is newer and has not expired we
4558 -- reinsert the key in the heap.
4559 --
4560 -- XXX if the key is an Int, we can also use an IntMap for slightly
4561 -- better performance.
4562 --
4563 let curTime = max sessionEventTime timestamp
4564 accumulate v = do
4565 old <- case v of
4566 Nothing -> initial
4567 Just (Tuple' _ acc) -> return acc
4568 new <- step old value
4569 return $ Tuple' timestamp new
4570 mOld = Map.lookup key sessionKeyValueMap
4572 acc@(Tuple' _ fres) <- accumulate mOld
4573 res <- extract fres
4574 case res of
4575 Left x -> do
4576 -- deleting a key from the heap is expensive, so we never
4577 -- delete a key from heap, we just purge it from the Map and it
4578 -- gets purged from the heap on timeout. We just need an extra
4579 -- lookup in the Map when the key is purged from the heap, that
4580 -- should not be expensive.
4581 --
4582 let (mp, cnt) = case mOld of
4583 Nothing -> (sessionKeyValueMap, sessionCount)
4584 Just _ -> (Map.delete key sessionKeyValueMap
4585 , sessionCount - 1)
4586 return $ session
4587 { sessionCurTime = curTime
4588 , sessionEventTime = curTime
4589 , sessionCount = cnt
4590 , sessionKeyValueMap = mp
4591 , sessionOutputStream = yield (key, x)
4593 Right _ -> do
4594 (hp1, mp1, out1, cnt1) <- do
4595 let vars = (sessionTimerHeap, sessionKeyValueMap,
4596 K.nil, sessionCount)
4597 case mOld of
4598 -- inserting new entry
4599 Nothing -> do
4600 -- Eject a session from heap and map is needed
4601 eject <- ejectPred sessionCount
4602 (hp, mp, out, cnt) <-
4603 if eject
4604 then ejectOne vars
4605 else return vars
4607 -- Insert the new session in heap
4608 let expiry = addToAbsTime timestamp timeoutMs
4609 hp' = H.insert (Entry expiry key) hp
4610 in return (hp', mp, out, cnt + 1)
4611 -- updating old entry
4612 Just _ -> return vars
4614 let mp2 = Map.insert key acc mp1
4615 return $ SessionState
4616 { sessionCurTime = curTime
4617 , sessionEventTime = curTime
4618 , sessionCount = cnt1
4619 , sessionTimerHeap = hp1
4620 , sessionKeyValueMap = mp2
4621 , sessionOutputStream = out1
4624 -- Got a timer tick event
4625 sstep sessionState@SessionState{..} Nothing =
4626 let curTime = addToAbsTime sessionCurTime tickMs
4627 in ejectExpired sessionState curTime
4629 flush session@SessionState{..} = do
4630 (hp', mp', out, count) <-
4631 ejectAll
4632 ( sessionTimerHeap
4633 , sessionKeyValueMap
4634 , K.nil
4635 , sessionCount
4637 return $ session
4638 { sessionCount = count
4639 , sessionTimerHeap = hp'
4640 , sessionKeyValueMap = mp'
4641 , sessionOutputStream = out
4644 fromEither e =
4645 case e of
4646 Left x -> x
4647 Right x -> x
4649 -- delete from map and output the fold accumulator
4650 ejectEntry hp mp out cnt acc key = do
4651 sess <- extract acc
4652 let out1 = (key, fromEither sess) `K.cons` out
4653 let mp1 = Map.delete key mp
4654 return (hp, mp1, out1, cnt - 1)
4656 ejectAll (hp, mp, out, !cnt) = do
4657 let hres = H.uncons hp
4658 case hres of
4659 Just (Entry _ key, hp1) -> do
4660 r <- case Map.lookup key mp of
4661 Nothing -> return (hp1, mp, out, cnt)
4662 Just (Tuple' _ acc) -> ejectEntry hp1 mp out cnt acc key
4663 ejectAll r
4664 Nothing -> do
4665 assert (Map.null mp) (return ())
4666 return (hp, mp, out, cnt)
4668 ejectOne (hp, mp, out, !cnt) = do
4669 let hres = H.uncons hp
4670 case hres of
4671 Just (Entry expiry key, hp1) ->
4672 case Map.lookup key mp of
4673 Nothing -> ejectOne (hp1, mp, out, cnt)
4674 Just (Tuple' latestTS acc) -> do
4675 let expiry1 = addToAbsTime latestTS timeoutMs
4676 if not reset || expiry1 <= expiry
4677 then ejectEntry hp1 mp out cnt acc key
4678 else
4679 -- reset the session timeout and continue
4680 let hp2 = H.insert (Entry expiry1 key) hp1
4681 in ejectOne (hp2, mp, out, cnt)
4682 Nothing -> do
4683 assert (Map.null mp) (return ())
4684 return (hp, mp, out, cnt)
4686 ejectExpired session@SessionState{..} curTime = do
4687 (hp', mp', out, count) <-
4688 ejectLoop sessionTimerHeap sessionKeyValueMap K.nil sessionCount
4689 return $ session
4690 { sessionCurTime = curTime
4691 , sessionCount = count
4692 , sessionTimerHeap = hp'
4693 , sessionKeyValueMap = mp'
4694 , sessionOutputStream = out
4697 where
4699 ejectLoop hp mp out !cnt = do
4700 let hres = H.uncons hp
4701 case hres of
4702 Just (Entry expiry key, hp1) -> do
4703 (eject, force) <-
4704 if curTime >= expiry
4705 then return (True, False)
4706 else do
4707 r <- ejectPred cnt
4708 return (r, r)
4709 if eject
4710 then
4711 case Map.lookup key mp of
4712 Nothing -> ejectLoop hp1 mp out cnt
4713 Just (Tuple' latestTS acc) -> do
4714 let expiry1 = addToAbsTime latestTS timeoutMs
4715 if expiry1 <= curTime || not reset || force
4716 then do
4717 (hp2,mp1,out1,cnt1) <-
4718 ejectEntry hp1 mp out cnt acc key
4719 ejectLoop hp2 mp1 out1 cnt1
4720 else
4721 -- reset the session timeout and continue
4722 let hp2 = H.insert (Entry expiry1 key) hp1
4723 in ejectLoop hp2 mp out cnt
4724 else return (hp, mp, out, cnt)
4725 Nothing -> do
4726 assert (Map.null mp) (return ())
4727 return (hp, mp, out, cnt)
4729 -- merge timer events in the stream
4730 stream = Serial.map Just str `Par.parallelFst` repeatM timer
4731 timer = do
4732 liftIO $ threadDelay (round $ tick * 1000000)
4733 return Nothing
4735-- | Like 'classifySessionsOf' but the session is kept alive if an event is
4736-- received within the session window. The session times out and gets closed
4737-- only if no event is received within the specified session window size.
4739-- If the ejection predicate returns 'True', the session that was idle for
4740-- the longest time is ejected before inserting a new session.
4742-- @
4743-- classifyKeepAliveSessions timeout pred = classifySessionsBy 1 timeout True pred
4744-- @
4746-- /Internal/
4748{-# INLINABLE classifyKeepAliveSessions #-}
4749classifyKeepAliveSessions
4750 :: (IsStream t, MonadAsync m, Ord k)
4751 => Double -- ^ session inactive timeout
4752 -> (Int -> m Bool) -- ^ predicate to eject sessions on session count
4753 -> Fold m a (Either b b) -- ^ Fold to be applied to session payload data
4754 -> t m (k, a, AbsTime) -- ^ session key, data, timestamp
4755 -> t m (k, b)
4756classifyKeepAliveSessions tmout =
4757 classifySessionsBy 1 tmout True
4759------------------------------------------------------------------------------
4760-- Keyed tumbling windows
4761------------------------------------------------------------------------------
4763-- Tumbling windows is a special case of sliding windows where the window slide
4764-- is the same as the window size. Or it can be a special case of session
4765-- windows where the reset flag is set to False.
4767-- XXX instead of using the early termination flag in the stream, we can use an
4768-- early terminating fold instead.
4771-- | Split the stream into fixed size chunks of specified size. Within each
4772-- such chunk fold the elements in buckets identified by the keys. A particular
4773-- bucket fold can be terminated early if a closing flag is encountered in an
4774-- element for that key.
4776-- @since 0.7.0
4777{-# INLINABLE classifyChunksOf #-}
4778classifyChunksOf
4779 :: (IsStream t, MonadAsync m, Ord k)
4780 => Int -- ^ window size
4781 -> Fold m a b -- ^ Fold to be applied to window events
4782 -> t m (k, a, Bool) -- ^ window key, data, close event
4783 -> t m (k, b)
4784classifyChunksOf wsize = classifyChunksBy wsize False
4787-- | Split the stream into fixed size time windows of specified interval in
4788-- seconds. Within each such window, fold the elements in sessions identified
4789-- by the session keys. The fold result is emitted in the output stream if the
4790-- fold returns a 'Left' result or if the time window ends.
4792-- Session @timestamp@ in the input stream is an absolute time from some epoch,
4793-- characterizing the time when the input element was generated. To detect
4794-- session window end, a monotonic event time clock is maintained synced with
4795-- the timestamps with a clock resolution of 1 second.
4797-- If the ejection predicate returns 'True', the session with the longest
4798-- lifetime is ejected before inserting a new session.
4800-- @
4801-- classifySessionsOf interval pred = classifySessionsBy 1 interval False pred
4802-- @
4804-- @
4805-- >>> S.mapM_ print
4806-- $ S.classifySessionsOf 3 (const (return False)) (fmap Right FL.toList)
4807-- $ S.map (\(ts,(k,a)) -> (k, a, ts))
4808-- $ S.timestamped
4809-- $ S.delay 1
4810-- $ (,) <$> S.fromList [1,2,3] <*> S.fromList [1,2,3]
4811-- @
4813-- /Internal/
4815{-# INLINABLE classifySessionsOf #-}
4816classifySessionsOf
4817 :: (IsStream t, MonadAsync m, Ord k)
4818 => Double -- ^ time window size
4819 -> (Int -> m Bool) -- ^ predicate to eject sessions on session count
4820 -> Fold m a (Either b b) -- ^ Fold to be applied to session events
4821 -> t m (k, a, AbsTime) -- ^ session key, data, timestamp
4822 -> t m (k, b)
4823classifySessionsOf interval =
4824 classifySessionsBy 1 interval False
4826------------------------------------------------------------------------------
4827-- Exceptions
4828------------------------------------------------------------------------------
4830-- | Run a side effect before the stream yields its first element.
4832-- @since 0.7.0
4833{-# INLINE before #-}
4834before :: (IsStream t, Monad m) => m b -> t m a -> t m a
4835before action xs = D.fromStreamD $ D.before action $ D.toStreamD xs
4837-- | Run a side effect whenever the stream stops normally.
4839-- Prefer 'afterIO' over this as the @after@ action in this combinator is not
4840-- executed if the unfold is partially evaluated lazily and then garbage
4841-- collected.
4843-- @since 0.7.0
4844{-# INLINE after #-}
4845after :: (IsStream t, Monad m) => m b -> t m a -> t m a
4846after action xs = D.fromStreamD $ D.after action $ D.toStreamD xs
4848-- | Run a side effect whenever the stream stops normally
4849-- or is garbage collected after a partial lazy evaluation.
4851-- /Internal/
4853{-# INLINE afterIO #-}
4854afterIO :: (IsStream t, MonadIO m, MonadBaseControl IO m) => m b -> t m a -> t m a
4855afterIO action xs = D.fromStreamD $ D.afterIO action $ D.toStreamD xs
4857-- | Run a side effect whenever the stream aborts due to an exception.
4859-- @since 0.7.0
4860{-# INLINE onException #-}
4861onException :: (IsStream t, MonadCatch m) => m b -> t m a -> t m a
4862onException action xs = D.fromStreamD $ D.onException action $ D.toStreamD xs
4864-- | Run a side effect whenever the stream stops normally or aborts due to an
4865-- exception.
4867-- Prefer 'finallyIO' over this as the @after@ action in this combinator is not
4868-- executed if the unfold is partially evaluated lazily and then garbage
4869-- collected.
4871-- @since 0.7.0
4872{-# INLINE finally #-}
4873finally :: (IsStream t, MonadCatch m) => m b -> t m a -> t m a
4874finally action xs = D.fromStreamD $ D.finally action $ D.toStreamD xs
4876-- | Run a side effect whenever the stream stops normally, aborts due to an
4877-- exception or if it is garbage collected after a partial lazy evaluation.
4879-- /Internal/
4881{-# INLINE finallyIO #-}
4882finallyIO :: (IsStream t, MonadAsync m, MonadCatch m) => m b -> t m a -> t m a
4883finallyIO action xs = D.fromStreamD $ D.finallyIO action $ D.toStreamD xs
4885-- | Run the first action before the stream starts and remember its output,
4886-- generate a stream using the output, run the second action using the
4887-- remembered value as an argument whenever the stream ends normally or due to
4888-- an exception.
4890-- Prefer 'bracketIO' over this as the @after@ action in this combinator is not
4891-- executed if the unfold is partially evaluated lazily and then garbage
4892-- collected.
4894-- @since 0.7.0
4895{-# INLINE bracket #-}
4896bracket :: (IsStream t, MonadCatch m)
4897 => m b -> (b -> m c) -> (b -> t m a) -> t m a
4898bracket bef aft bet = D.fromStreamD $
4899 D.bracket bef aft (toStreamD . bet)
4901-- | Run the first action before the stream starts and remember its output,
4902-- generate a stream using the output, run the second action using the
4903-- remembered value as an argument whenever the stream ends normally, due to
4904-- an exception or if it is garbage collected after a partial lazy evaluation.
4906-- /Internal/
4908{-# INLINE bracketIO #-}
4909bracketIO :: (IsStream t, MonadAsync m, MonadCatch m)
4910 => m b -> (b -> m c) -> (b -> t m a) -> t m a
4911bracketIO bef aft bet = D.fromStreamD $
4912 D.bracketIO bef aft (toStreamD . bet)
4914-- | When evaluating a stream if an exception occurs, stream evaluation aborts
4915-- and the specified exception handler is run with the exception as argument.
4917-- @since 0.7.0
4918{-# INLINE handle #-}
4919handle :: (IsStream t, MonadCatch m, Exception e)
4920 => (e -> t m a) -> t m a -> t m a
4921handle handler xs =
4922 D.fromStreamD $ D.handle (D.toStreamD . handler) $ D.toStreamD xs
4924------------------------------------------------------------------------------
4925-- Generalize the underlying monad
4926------------------------------------------------------------------------------
4928-- | Transform the inner monad of a stream using a natural transformation.
4930-- / Internal/
4932{-# INLINE hoist #-}
4933hoist :: (Monad m, Monad n)
4934 => (forall x. m x -> n x) -> SerialT m a -> SerialT n a
4935hoist f xs = fromStreamS $ S.hoist f (toStreamS xs)
4937-- | Generalize the inner monad of the stream from 'Identity' to any monad.
4939-- / Internal/
4941{-# INLINE generally #-}
4942generally :: (IsStream t, Monad m) => t Identity a -> t m a
4943generally xs = fromStreamS $ S.hoist (return . runIdentity) (toStreamS xs)
4945------------------------------------------------------------------------------
4946-- Add and remove a monad transformer
4947------------------------------------------------------------------------------
4949-- | Lift the inner monad of a stream using a monad transformer.
4951-- / Internal/
4953{-# INLINE liftInner #-}
4954liftInner :: (Monad m, IsStream t, MonadTrans tr, Monad (tr m))
4955 => t m a -> t (tr m) a
4956liftInner xs = fromStreamD $ D.liftInner (toStreamD xs)
4958-- | Evaluate the inner monad of a stream as 'ReaderT'.
4960-- / Internal/
4962{-# INLINE runReaderT #-}
4963runReaderT :: (IsStream t, Monad m) => s -> t (ReaderT s m) a -> t m a
4964runReaderT s xs = fromStreamD $ D.runReaderT s (toStreamD xs)
4966-- | Evaluate the inner monad of a stream as 'StateT'.
4968-- This is supported only for 'SerialT' as concurrent state updation may not be
4969-- safe.
4971-- / Internal/
4973{-# INLINE evalStateT #-}
4974evalStateT :: Monad m => s -> SerialT (StateT s m) a -> SerialT m a
4975evalStateT s xs = fromStreamD $ D.evalStateT s (toStreamD xs)
4977-- | Run a stateful (StateT) stream transformation using a given state.
4979-- This is supported only for 'SerialT' as concurrent state updation may not be
4980-- safe.
4982-- / Internal/
4984{-# INLINE usingStateT #-}
4985usingStateT
4986 :: Monad m
4987 => s
4988 -> (SerialT (StateT s m) a -> SerialT (StateT s m) a)
4989 -> SerialT m a
4990 -> SerialT m a
4991usingStateT s f xs = evalStateT s $ f $ liftInner xs
4993-- | Evaluate the inner monad of a stream as 'StateT' and emit the resulting
4994-- state and value pair after each step.
4996-- This is supported only for 'SerialT' as concurrent state updation may not be
4997-- safe.
4999-- / Internal/
5001{-# INLINE runStateT #-}
5002runStateT :: Monad m => s -> SerialT (StateT s m) a -> SerialT m (s, a)
5003runStateT s xs = fromStreamD $ D.runStateT s (toStreamD xs)
5005-- | Run a stream transformation using a given environment.
5007-- / Internal/
5009{-# INLINE usingReaderT #-}
5010usingReaderT
5011 :: (Monad m, IsStream t)
5012 => r
5013 -> (t (ReaderT r m) a -> t (ReaderT r m) a)
5014 -> t m a
5015 -> t m a
5016usingReaderT r f xs = runReaderT r $ f $ liftInner xs