on 7d00819 help sign in
5147 lines 165 kB history raw
1{-# OPTIONS_GHC -Wno-orphans #-}
3#include "inline.hs"
5-- |
6-- Module : Streamly.Internal.Data.Stream.IsStream
7-- Copyright : (c) 2017 Harendra Kumar
8--
9-- License : BSD3
10-- Maintainer : streamly@composewell.com
11-- Stability : experimental
12-- Portability : GHC
13--
14-- This is an Internal module consisting of released, unreleased and
15-- unimplemented APIs. For stable and released APIs please see
16-- "Streamly.Prelude" module. This module provides documentation only for the
17-- unreleased and unimplemented APIs. For documentation on released APIs please
18-- see "Streamly.Prelude" module.
20module Streamly.Internal.Data.Stream.IsStream
21 (
22 -- * Construction
23 -- ** Primitives
24 K.nil
25 , K.nilM
26 , K.cons
27 , (K..:)
29 , consM
30 , (|:)
32 -- ** From Values
33 , yield
34 , yieldM
35 , repeat
36 , repeatM
37 , replicate
38 , replicateM
40 -- ** Enumeration
41 , Enumerable (..)
42 , enumerate
43 , enumerateTo
45 -- ** Time Enumeration
46 , times
47 , absTimes
48 , relTimes
49 , durations
50 , ticks
51 , timeout
52 , currentTime
54 -- ** From Generators
55 , unfoldr
56 , unfoldrM
57 , unfold
58 , unfold0
59 , fromIndices
60 , fromIndicesM
62 -- ** Iteration
63 , iterate
64 , iterateM
66 -- ** Cyclic Elements
67 , K.mfix
69 -- ** From Containers
70 , P.fromList
71 , fromListM
72 , K.fromFoldable
73 , fromFoldableM
74 , fromPrimIORef
75 , fromCallback
77 -- * Elimination
79 -- ** Deconstruction
80 , uncons
81 , tail
82 , init
84 -- ** Folding
85 -- ** Right Folds
86 , foldrM
87 , foldrS
88 , foldrT
89 , foldr
91 -- ** Left Folds
92 , foldl'
93 , foldl1'
94 , foldlM'
96 -- ** Composable Left Folds
97 , fold
98 , parse
99 , parseK
100 , parseD
102 -- ** Concurrent Folds
103 , foldAsync
104 , (|$.)
105 , (|&.)
107 -- ** Full Folds
109 -- -- ** To Summary (Full Folds)
110 , drain
111 , last
112 , length
113 , sum
114 , product
115 , mconcat
117 -- -- ** To Summary (Maybe) (Full Folds)
118 , maximumBy
119 , maximum
120 , minimumBy
121 , minimum
122 , the
124 -- ** Lazy Folds
125 -- -- ** To Containers (Full Folds)
126 , toList
127 , toListRev
128 , toPure
129 , toPureRev
131 -- ** Composable Left Folds
133 , toStream -- XXX rename to write?
134 , toStreamRev -- XXX rename to writeRev?
136 -- ** Partial Folds
138 -- -- ** To Elements (Partial Folds)
139 , drainN
140 , drainWhile
142 -- -- | Folds that extract selected elements of a stream or their properties.
143 , (!!)
144 , head
145 , headElse
146 , findM
147 , find
148 , lookup
149 , findIndex
150 , elemIndex
152 -- -- ** To Boolean (Partial Folds)
153 , null
154 , elem
155 , notElem
156 , all
157 , any
158 , and
159 , or
161 -- ** Multi-Stream folds
162 -- Full equivalence
163 , eqBy
164 , cmpBy
166 -- finding subsequences
167 , isPrefixOf
168 , isSuffixOf
169 , isInfixOf
170 , isSubsequenceOf
172 -- trimming sequences
173 , stripPrefix
174 , stripSuffix
175 -- , stripInfix
176 , dropPrefix
177 , dropInfix
178 , dropSuffix
180 -- * Transformation
181 , transform
183 -- ** Mapping
184 , Serial.map
185 , sequence
186 , mapM
187 , smapM
188 -- $smapM_Notes
190 -- ** Special Maps
191 , mapM_
192 , trace
193 , trace_
194 , tap
195 , tapOffsetEvery
196 , tapAsync
197 , tapRate
198 , pollCounts
200 -- ** Scanning
201 -- ** Left scans
202 , scanl'
203 , scanlM'
204 , scanlMAfter'
205 , postscanl'
206 , postscanlM'
207 , prescanl'
208 , prescanlM'
209 , scanl1'
210 , scanl1M'
212 -- ** Scan Using Fold
213 , scan
214 , postscan
216 -- XXX Once we have pipes the contravariant transformations can be
217 -- represented by attaching pipes before a transformation.
218 --
219 -- , lscanl'
220 -- , lscanlM'
221 -- , lscanl1'
222 -- , lscanl1M'
223 --
224 -- , lpostscanl'
225 -- , lpostscanlM'
226 -- , lprescanl'
227 -- , lprescanlM'
229 -- ** Concurrent Transformation
230 , D.mkParallel
231 -- Par.mkParallel
232 , applyAsync
233 , (|$)
234 , (|&)
236 -- ** Filtering
238 , filter
239 , filterM
241 -- ** Deleting Elements
242 , deleteBy
243 , uniq
244 -- , uniqBy -- by predicate e.g. to remove duplicate "/" in a path
245 -- , uniqOn -- to remove duplicate sequences
246 -- , pruneBy -- dropAround + uniqBy - like words
248 -- ** Inserting Elements
250 , insertBy
251 , intersperseM
252 , intersperseM_
253 , intersperse
254 , intersperseSuffix
255 , intersperseSuffix_
256 , interspersePrefix_
257 , intersperseSuffixBySpan
258 -- , intersperseBySpan
259 -- , intersperseByIndices -- using an index function/stream
261 -- time domain intersperse
262 -- , intersperseByTime
263 -- , intersperseByEvent
264 , interjectSuffix
265 , delay
266 , delayPost
267 , delayPre
269 -- ** Indexing
270 , indexed
271 , indexedR
272 , timestamped
273 , timeIndexed
274 -- , timestampedR -- timer
276 -- ** Reordering
277 , reverse
278 , reverse'
280 -- ** Parsing
281 , parseMany
282 , parseManyD
283 , parseManyTill
284 , parseIterate
286 -- ** Trimming
287 , take
288 -- , takeGE
289 -- , takeBetween
290 , takeByTime
291 -- , takeEnd
292 , takeWhile
293 , takeWhileM
294 -- , takeWhileEnd
295 , drop
296 , dropByTime
297 -- , dropEnd
298 , dropWhile
299 , dropWhileM
300 -- , dropWhileEnd
301 -- , dropAround
303 -- ** Breaking
305 -- Nary
306 , chunksOf
307 , chunksOf2
308 , arraysOf
309 , intervalsOf
311 -- ** Searching
312 -- -- *** Searching Elements
313 , findIndices
314 , elemIndices
316 -- -- *** Searching Sequences
317 -- , seqIndices -- search a sequence in the stream
319 -- -- *** Searching Multiple Sequences
320 -- , seqIndicesAny -- search any of the given sequence in the stream
322 -- -- -- ** Searching Streams
323 -- -- | Finding a stream within another stream.
325 -- ** Splitting
326 -- | Streams can be sliced into segments in space or in time. We use the
327 -- term @chunk@ to refer to a spatial length of the stream (spatial window)
328 -- and the term @session@ to refer to a length in time (time window).
330 -- -- *** Using Element Separators
331 , splitOn
332 , splitOnSuffix
333 -- , splitOnPrefix
335 -- , splitBy
336 , splitWithSuffix
337 -- , splitByPrefix
338 , wordsBy -- stripAndCompactBy
340 -- -- *** Splitting By Sequences
341 , splitOnSeq
342 , splitOnSuffixSeq
343 -- , splitOnPrefixSeq
345 -- Keeping the delimiters
346 , splitBySeq
347 , splitWithSuffixSeq
348 -- , splitByPrefixSeq
349 -- , wordsBySeq
351 -- Splitting using multiple sequence separators
352 -- , splitOnAnySeq
353 -- , splitOnAnySuffixSeq
354 -- , splitOnAnyPrefixSeq
356 -- -- *** Splitting By Streams
357 -- -- | Splitting a stream using another stream as separator.
359 -- Nested splitting
360 , splitInnerBy
361 , splitInnerBySuffix
363 -- ** Grouping
364 -- In imperative terms, grouped folding can be considered as a nested loop
365 -- where we loop over the stream to group elements and then loop over
366 -- individual groups to fold them to a single value that is yielded in the
367 -- output stream.
369 -- , groupScan
371 , groups
372 , groupsBy
373 , groupsByRolling
375 -- ** Group map
376 , rollingMapM
377 , rollingMap
379 -- * Windowed Classification
381 -- | Split the stream into windows or chunks in space or time. Each window
382 -- can be associated with a key, all events associated with a particular
383 -- key in the window can be folded to a single result. The stream is split
384 -- into windows of specified size, the window can be terminated early if
385 -- the closing flag is specified in the input stream.
386 --
387 -- The term "chunk" is used for a space window and the term "session" is
388 -- used for a time window.
390 -- ** Tumbling Windows
391 -- | A new window starts after the previous window is finished.
393 -- , classifyChunksOf
394 , classifySessionsBy
395 , classifySessionsOf
397 -- ** Keep Alive Windows
398 -- | The window size is extended if an event arrives within the specified
399 -- window size. This can represent sessions with idle or inactive timeout.
401 -- , classifyKeepAliveChunks
402 , classifyKeepAliveSessions
404 {-
405 -- ** Sliding Windows
406 -- | A new window starts after the specified slide from the previous
407 -- window. Therefore windows can overlap.
408 , classifySlidingChunks
409 , classifySlidingSessions
410 -}
411 -- ** Sliding Window Buffers
412 -- , slidingChunkBuffer
413 -- , slidingSessionBuffer
415 -- * Combining Streams
417 -- ** Appending
418 , append
420 -- ** Interleaving
421 , interleave
422 , interleaveMin
423 , interleaveSuffix
424 , interleaveInfix
426 , Serial.wSerialFst
427 , Serial.wSerialMin
429 -- ** Scheduling
430 , roundrobin
432 -- ** Parallel
433 , Par.parallelFst
434 , Par.parallelMin
436 -- ** Merging
438 -- , merge
439 , mergeBy
440 , mergeByM
441 , mergeAsyncBy
442 , mergeAsyncByM
444 -- ** Zipping
445 , Z.zipWith
446 , Z.zipWithM
447 , Z.zipAsyncWith
448 , Z.zipAsyncWithM
450 -- ** Flattening a Container of Streams
451 , foldWith
452 , foldMapWith
453 , forEachWith
455 -- ** Flattening a Stream of Streams
456 , concat
457 , concatM
458 , concatMap
459 , concatMapM
460 , concatMapWith
461 , concatSmapMWith
462 -- , bindWith
464 -- ** Flattening Using Unfolds
465 , concatUnfold
466 , concatUnfoldInterleave
467 , concatUnfoldRoundrobin
469 -- ** Flattening a Tree of Streams
470 , iterateMapWith
472 -- ** Flattening a Graph of Streams
473 , iterateSmapMWith
475 -- ** Inserting Streams in Streams
476 , gintercalate
477 , gintercalateSuffix
478 , intercalate
479 , intercalateSuffix
480 , interpose
481 , interposeSuffix
482 -- , interposeBy
484 -- * Exceptions
485 , before
486 , after_
487 , after
488 , bracket_
489 , bracket
490 , onException
491 , finally_
492 , finally
493 , handle
495 -- * Generalize Inner Monad
496 , hoist
497 , generally
499 -- * Transform Inner Monad
500 , liftInner
501 , usingReaderT
502 , runReaderT
503 , evalStateT
504 , usingStateT
505 , runStateT
507 -- * Maybe Streams
508 , catMaybes
509 , mapMaybe
510 , mapMaybeM
512 -- * Either Streams
513 , lefts
514 , rights
515 , iterateMapLeftsWith
517 -- * Diagnostics
518 , inspectMode
520 -- * Deprecated
521 , K.once
522 , each
523 , scanx
524 , foldx
525 , foldxM
526 , foldr1
527 , runStream
528 , runN
529 , runWhile
530 , fromHandle
531 , toHandle
532 )
533where
535import Control.Concurrent (threadDelay)
536import Control.Exception (Exception, assert)
537import Control.Monad (void)
538import Control.Monad.Catch (MonadCatch, MonadThrow)
539import Control.Monad.IO.Class (MonadIO(..))
540import Control.Monad.Trans.Reader (ReaderT)
541import Control.Monad.Trans.State.Strict (StateT)
542import Control.Monad.Trans.Class (MonadTrans(..))
543import Control.Monad.Trans.Control (MonadBaseControl)
544import Data.Either (isLeft, isRight)
545import Data.Functor.Identity (Identity (..))
546import Data.Kind (Type)
547import Data.Heap (Entry(..))
548import Data.Maybe (isJust, fromJust, isNothing)
549import Data.Void (Void)
550import Foreign.Storable (Storable)
551import Streamly.Internal.BaseCompat (fromLeft, fromRight)
552import Streamly.Internal.Data.Stream.Enumeration
553 (Enumerable(..), enumerate, enumerateTo)
554import Streamly.Internal.Data.Fold.Types (Fold (..), Fold2 (..))
555import Streamly.Internal.Data.Parser (Parser (..))
556import Streamly.Internal.Data.Unfold.Types (Unfold)
557import Streamly.Internal.Memory.Array.Types (Array, writeNUnsafe)
558import Streamly.Internal.Data.SVar (MonadAsync, defState, Rate)
559import Streamly.Internal.Data.Stream.Combinators (inspectMode, maxYields)
560import Streamly.Internal.Data.Stream.Prelude
561 (fromStreamS, toStreamS, foldWith, foldMapWith, forEachWith)
562import Streamly.Internal.Data.Stream.StreamD (fromStreamD, toStreamD)
563import Streamly.Internal.Data.Stream.StreamK (IsStream((|:), consM))
564import Streamly.Internal.Data.Stream.Serial (SerialT, WSerialT)
565import Streamly.Internal.Data.Stream.Zip (ZipSerialM)
566import Streamly.Internal.Data.Pipe.Types (Pipe (..))
567import Streamly.Internal.Data.Time.Units
568 ( AbsTime, MilliSecond64(..), addToAbsTime, toRelTime
569 , toAbsTime, TimeUnit64, RelTime64, addToAbsTime64)
570import Streamly.Internal.Data.IORef.Prim (Prim, IORef)
571import Streamly.Internal.Data.Tuple.Strict (Tuple'(..))
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
579import qualified Streamly.Internal.Data.Stream.Serial as Serial
580import qualified Streamly.Internal.Data.Stream.Parallel as Par
581import qualified Streamly.Internal.Data.Stream.Zip as Z
582import qualified Streamly.Internal.Data.Parser.ParserK.Types as PRK
583import qualified Streamly.Internal.Data.Parser.ParserD as PRD
584import qualified Data.Heap as H
585import qualified Data.Map.Strict as Map
586import qualified Prelude
587import qualified System.IO as IO
588#ifdef USE_STREAMK_ONLY
589import qualified Streamly.Internal.Data.Stream.StreamK as S
590#else
591import qualified Streamly.Internal.Data.Stream.StreamD as S
592#endif
594import Prelude hiding
595 ( filter, drop, dropWhile, take, takeWhile, zipWith, foldr
596 , foldl, map, mapM, mapM_, sequence, all, any, sum, product, elem
597 , notElem, maximum, minimum, head, last, tail, length, null
598 , reverse, iterate, init, and, or, lookup, foldr1, (!!)
599 , scanl, scanl1, replicate, concatMap, span, splitAt, break
600 , repeat, concat, mconcat)
602------------------------------------------------------------------------------
603-- Deconstruction
604------------------------------------------------------------------------------
606-- | Decompose a stream into its head and tail. If the stream is empty, returns
607-- 'Nothing'. If the stream is non-empty, returns @Just (a, ma)@, where @a@ is
608-- the head of the stream and @ma@ its tail.
609--
610-- This is a brute force primitive. Avoid using it as long as possible, use it
611-- when no other combinator can do the job. This can be used to do pretty much
612-- anything in an imperative manner, as it just breaks down the stream into
613-- individual elements and we can loop over them as we deem fit. For example,
614-- this can be used to convert a streamly stream into other stream types.
615--
616-- @since 0.1.0
617{-# INLINE uncons #-}
618uncons :: (IsStream t, Monad m) => SerialT m a -> m (Maybe (a, t m a))
619uncons m = K.uncons (K.adapt m)
621------------------------------------------------------------------------------
622-- Generation by Unfolding
623------------------------------------------------------------------------------
625-- |
626-- @
627-- unfoldr step s =
628-- case step s of
629-- Nothing -> 'K.nil'
630-- Just (a, b) -> a \`cons` unfoldr step b
631-- @
632--
633-- Build a stream by unfolding a /pure/ step function @step@ starting from a
634-- seed @s@. The step function returns the next element in the stream and the
635-- next seed value. When it is done it returns 'Nothing' and the stream ends.
636-- For example,
637--
638-- @
639-- let f b =
640-- if b > 3
641-- then Nothing
642-- else Just (b, b + 1)
643-- in toList $ unfoldr f 0
644-- @
645-- @
646-- [0,1,2,3]
647-- @
648--
649-- @since 0.1.0
650{-# INLINE_EARLY unfoldr #-}
651unfoldr :: (Monad m, IsStream t) => (b -> Maybe (a, b)) -> b -> t m a
652unfoldr step seed = fromStreamS (S.unfoldr step seed)
653{-# RULES "unfoldr fallback to StreamK" [1]
654 forall a b. S.toStreamK (S.unfoldr a b) = K.unfoldr a b #-}
656-- | Build a stream by unfolding a /monadic/ step function starting from a
657-- seed. The step function returns the next element in the stream and the next
658-- seed value. When it is done it returns 'Nothing' and the stream ends. For
659-- example,
660--
661-- @
662-- let f b =
663-- if b > 3
664-- then return Nothing
665-- else print b >> return (Just (b, b + 1))
666-- in drain $ unfoldrM f 0
667-- @
668-- @
669-- 0
670-- 1
671-- 2
672-- 3
673-- @
674-- When run concurrently, the next unfold step can run concurrently with the
675-- processing of the output of the previous step. Note that more than one step
676-- cannot run concurrently as the next step depends on the output of the
677-- previous step.
678--
679-- @
680-- (asyncly $ S.unfoldrM (\\n -> liftIO (threadDelay 1000000) >> return (Just (n, n + 1))) 0)
681-- & S.foldlM' (\\_ a -> threadDelay 1000000 >> print a) ()
682-- @
683--
684-- /Concurrent/
685--
686-- /Since: 0.1.0/
687{-# INLINE_EARLY unfoldrM #-}
688unfoldrM :: (IsStream t, MonadAsync m) => (b -> m (Maybe (a, b))) -> b -> t m a
689unfoldrM = K.unfoldrM
691{-# RULES "unfoldrM serial" unfoldrM = unfoldrMSerial #-}
692{-# INLINE_EARLY unfoldrMSerial #-}
693unfoldrMSerial :: MonadAsync m => (b -> m (Maybe (a, b))) -> b -> SerialT m a
694unfoldrMSerial = Serial.unfoldrM
696{-# RULES "unfoldrM wSerial" unfoldrM = unfoldrMWSerial #-}
697{-# INLINE_EARLY unfoldrMWSerial #-}
698unfoldrMWSerial :: MonadAsync m => (b -> m (Maybe (a, b))) -> b -> WSerialT m a
699unfoldrMWSerial = Serial.unfoldrM
701{-# RULES "unfoldrM zipSerial" unfoldrM = unfoldrMZipSerial #-}
702{-# INLINE_EARLY unfoldrMZipSerial #-}
703unfoldrMZipSerial :: MonadAsync m => (b -> m (Maybe (a, b))) -> b -> ZipSerialM m a
704unfoldrMZipSerial = Serial.unfoldrM
706-- | Convert an 'Unfold' into a stream by supplying it an input seed.
707--
708-- >>> unfold (UF.replicateM 10) (putStrLn "hello")
709--
710-- /Since: 0.7.0/
711{-# INLINE unfold #-}
712unfold :: (IsStream t, Monad m) => Unfold m a b -> a -> t m b
713unfold unf x = fromStreamD $ D.unfold unf x
715-- | Convert an 'Unfold' with a closed input end into a stream.
716--
717-- /Internal/
718{-# INLINE unfold0 #-}
719unfold0 :: (IsStream t, Monad m) => Unfold m Void b -> t m b
720unfold0 unf = unfold unf (error "unfold0: unexpected void evaluation")
722------------------------------------------------------------------------------
723-- Specialized Generation
724------------------------------------------------------------------------------
726-- Faster than yieldM because there is no bind.
727--
728-- |
729-- @
730-- yield a = a \`cons` nil
731-- @
732--
733-- Create a singleton stream from a pure value.
734--
735-- The following holds in monadic streams, but not in Zip streams:
736--
737-- @
738-- yield = pure
739-- yield = yieldM . pure
740-- @
741--
742-- In Zip applicative streams 'yield' is not the same as 'pure' because in that
743-- case 'pure' is equivalent to 'repeat' instead. 'yield' and 'pure' are
744-- equally efficient, in other cases 'yield' may be slightly more efficient
745-- than the other equivalent definitions.
746--
747-- @since 0.4.0
748{-# INLINE yield #-}
749yield :: IsStream t => a -> t m a
750yield = K.yield
752-- |
753-- @
754-- yieldM m = m \`consM` nil
755-- @
756--
757-- Create a singleton stream from a monadic action.
758--
759-- @
760-- > toList $ yieldM getLine
761-- hello
762-- ["hello"]
763-- @
764--
765-- @since 0.4.0
766{-# INLINE yieldM #-}
767yieldM :: (Monad m, IsStream t) => m a -> t m a
768yieldM = K.yieldM
770-- |
771-- @
772-- fromIndices f = let g i = f i \`cons` g (i + 1) in g 0
773-- @
774--
775-- Generate an infinite stream, whose values are the output of a function @f@
776-- applied on the corresponding index. Index starts at 0.
777--
778-- @
779-- > S.toList $ S.take 5 $ S.fromIndices id
780-- [0,1,2,3,4]
781-- @
782--
783-- @since 0.6.0
784{-# INLINE fromIndices #-}
785fromIndices :: (IsStream t, Monad m) => (Int -> a) -> t m a
786fromIndices = fromStreamS . S.fromIndices
788--
789-- |
790-- @
791-- fromIndicesM f = let g i = f i \`consM` g (i + 1) in g 0
792-- @
793--
794-- Generate an infinite stream, whose values are the output of a monadic
795-- function @f@ applied on the corresponding index. Index starts at 0.
796--
797-- /Concurrent/
798--
799-- @since 0.6.0
800{-# INLINE_EARLY fromIndicesM #-}
801fromIndicesM :: (IsStream t, MonadAsync m) => (Int -> m a) -> t m a
802fromIndicesM = K.fromIndicesM
804{-# RULES "fromIndicesM serial" fromIndicesM = fromIndicesMSerial #-}
805{-# INLINE fromIndicesMSerial #-}
806fromIndicesMSerial :: MonadAsync m => (Int -> m a) -> SerialT m a
807fromIndicesMSerial = fromStreamS . S.fromIndicesM
809-- |
810-- @
811-- replicateM = take n . repeatM
812-- @
813--
814-- Generate a stream by performing a monadic action @n@ times. Same as:
815--
816-- @
817-- drain $ serially $ S.replicateM 10 $ (threadDelay 1000000 >> print 1)
818-- drain $ asyncly $ S.replicateM 10 $ (threadDelay 1000000 >> print 1)
819-- @
820--
821-- /Concurrent/
822--
823-- @since 0.1.1
824{-# INLINE_EARLY replicateM #-}
825replicateM :: (IsStream t, MonadAsync m) => Int -> m a -> t m a
826replicateM = K.replicateM
828{-# RULES "replicateM serial" replicateM = replicateMSerial #-}
829{-# INLINE replicateMSerial #-}
830replicateMSerial :: MonadAsync m => Int -> m a -> SerialT m a
831replicateMSerial n = fromStreamS . S.replicateM n
833-- |
834-- @
835-- replicate = take n . repeat
836-- @
837--
838-- Generate a stream of length @n@ by repeating a value @n@ times.
839--
840-- @since 0.6.0
841{-# INLINE_NORMAL replicate #-}
842replicate :: (IsStream t, Monad m) => Int -> a -> t m a
843replicate n = fromStreamS . S.replicate n
845-- |
846-- Generate an infinite stream by repeating a pure value.
847--
848-- @since 0.4.0
849{-# INLINE_NORMAL repeat #-}
850repeat :: (IsStream t, Monad m) => a -> t m a
851repeat = fromStreamS . S.repeat
853-- |
854-- @
855-- repeatM = fix . consM
856-- repeatM = cycle1 . yieldM
857-- @
858--
859-- Generate a stream by repeatedly executing a monadic action forever.
860--
861-- @
862-- drain $ serially $ S.take 10 $ S.repeatM $ (threadDelay 1000000 >> print 1)
863-- drain $ asyncly $ S.take 10 $ S.repeatM $ (threadDelay 1000000 >> print 1)
864-- @
865--
866-- /Concurrent, infinite (do not use with 'parallely')/
867--
868-- @since 0.2.0
869{-# INLINE_EARLY repeatM #-}
870repeatM :: (IsStream t, MonadAsync m) => m a -> t m a
871repeatM = K.repeatM
873{-# RULES "repeatM serial" repeatM = repeatMSerial #-}
874{-# INLINE repeatMSerial #-}
875repeatMSerial :: MonadAsync m => m a -> SerialT m a
876repeatMSerial = fromStreamS . S.repeatM
878-- |
879-- @
880-- iterate f x = x \`cons` iterate f x
881-- @
882--
883-- Generate an infinite stream with @x@ as the first element and each
884-- successive element derived by applying the function @f@ on the previous
885-- element.
886--
887-- @
888-- > S.toList $ S.take 5 $ S.iterate (+1) 1
889-- [1,2,3,4,5]
890-- @
891--
892-- @since 0.1.2
893{-# INLINE_NORMAL iterate #-}
894iterate :: (IsStream t, Monad m) => (a -> a) -> a -> t m a
895iterate step = fromStreamS . S.iterate step
897-- |
898-- @
899-- iterateM f m = m >>= \a -> return a \`consM` iterateM f (f a)
900-- @
901--
902-- Generate an infinite stream with the first element generated by the action
903-- @m@ and each successive element derived by applying the monadic function
904-- @f@ on the previous element.
905--
906-- When run concurrently, the next iteration can run concurrently with the
907-- processing of the previous iteration. Note that more than one iteration
908-- cannot run concurrently as the next iteration depends on the output of the
909-- previous iteration.
910--
911-- @
912-- drain $ serially $ S.take 10 $ S.iterateM
913-- (\\x -> threadDelay 1000000 >> print x >> return (x + 1)) (return 0)
914--
915-- drain $ asyncly $ S.take 10 $ S.iterateM
916-- (\\x -> threadDelay 1000000 >> print x >> return (x + 1)) (return 0)
917-- @
918--
919-- /Concurrent/
920--
921-- /Since: 0.7.0 (signature change)/
922--
923-- /Since: 0.1.2/
924{-# INLINE_EARLY iterateM #-}
925iterateM :: (IsStream t, MonadAsync m) => (a -> m a) -> m a -> t m a
926iterateM = K.iterateM
928{-# RULES "iterateM serial" iterateM = iterateMSerial #-}
929{-# INLINE iterateMSerial #-}
930iterateMSerial :: MonadAsync m => (a -> m a) -> m a -> SerialT m a
931iterateMSerial step = fromStreamS . S.iterateM step
933------------------------------------------------------------------------------
934-- Conversions
935------------------------------------------------------------------------------
937-- |
938-- @
939-- fromListM = 'Prelude.foldr' 'K.consM' 'K.nil'
940-- @
941--
942-- Construct a stream from a list of monadic actions. This is more efficient
943-- than 'fromFoldableM' for serial streams.
944--
945-- @since 0.4.0
946{-# INLINE_EARLY fromListM #-}
947fromListM :: (MonadAsync m, IsStream t) => [m a] -> t m a
948fromListM = fromStreamD . D.fromListM
949{-# RULES "fromListM fallback to StreamK" [1]
950 forall a. D.toStreamK (D.fromListM a) = fromFoldableM a #-}
952-- |
953-- @
954-- fromFoldableM = 'Prelude.foldr' 'consM' 'K.nil'
955-- @
956--
957-- Construct a stream from a 'Foldable' containing monadic actions.
958--
959-- @
960-- drain $ serially $ S.fromFoldableM $ replicateM 10 (threadDelay 1000000 >> print 1)
961-- drain $ asyncly $ S.fromFoldableM $ replicateM 10 (threadDelay 1000000 >> print 1)
962-- @
963--
964-- /Concurrent (do not use with 'parallely' on infinite containers)/
965--
966-- @since 0.3.0
967{-# INLINE fromFoldableM #-}
968fromFoldableM :: (IsStream t, MonadAsync m, Foldable f) => f (m a) -> t m a
969fromFoldableM = Prelude.foldr consM K.nil
971-- | Same as 'fromFoldable'.
972--
973-- @since 0.1.0
974{-# DEPRECATED each "Please use fromFoldable instead." #-}
975{-# INLINE each #-}
976each :: (IsStream t, Foldable f) => f a -> t m a
977each = K.fromFoldable
979-- | Read lines from an IO Handle into a stream of Strings.
980--
981-- @since 0.1.0
982{-# DEPRECATED fromHandle
983 "Please use Streamly.FileSystem.Handle module (see the changelog)" #-}
984fromHandle :: (IsStream t, MonadIO m) => IO.Handle -> t m String
985fromHandle h = go
986 where
987 go = K.mkStream $ \_ yld _ stp -> do
988 eof <- liftIO $ IO.hIsEOF h
989 if eof
990 then stp
991 else do
992 str <- liftIO $ IO.hGetLine h
993 yld str go
995-- | Construct a stream by reading a 'Prim' 'IORef' repeatedly.
996--
997-- /Internal/
998--
999{-# INLINE fromPrimIORef #-}
1000fromPrimIORef :: (IsStream t, MonadIO m, Prim a) => IORef a -> t m a
1001fromPrimIORef = fromStreamD . D.fromPrimIORef
1003-- | Takes a callback setter function and provides it with a callback. The
1004-- callback when invoked adds a value at the tail of the stream. Returns a
1005-- stream of values generated by the callback.
1007-- /Internal/
1009{-# INLINE fromCallback #-}
1010fromCallback :: MonadAsync m => ((a -> m ()) -> m ()) -> SerialT m a
1011fromCallback setCallback = concatM $ do
1012 (callback, stream) <- D.newCallbackStream
1013 setCallback callback
1014 return stream
1016------------------------------------------------------------------------------
1017-- Time related
1018------------------------------------------------------------------------------
1020-- | @timesWith g@ returns a stream of time value tuples. The first component
1021-- of the tuple is an absolute time reference (epoch) denoting the start of the
1022-- stream and the second component is a time relative to the reference.
1024-- The argument @g@ specifies the granularity of the relative time in seconds.
1025-- A lower granularity clock gives higher precision but is more expensive in
1026-- terms of CPU usage. Any granularity lower than 1 ms is treated as 1 ms.
1028-- @
1029-- >>> S.mapM_ (\x -> print x >> threadDelay 1000000) $ S.timesWith 0.01
1030-- > (AbsTime (TimeSpec {sec = 2496295, nsec = 536223000}),RelTime64 (NanoSecond64 0))
1031-- > (AbsTime (TimeSpec {sec = 2496295, nsec = 536223000}),RelTime64 (NanoSecond64 1002028000))
1032-- > (AbsTime (TimeSpec {sec = 2496295, nsec = 536223000}),RelTime64 (NanoSecond64 1996656000))
1033-- @
1035-- Note: This API is not safe on 32-bit machines.
1037-- /Internal/
1039{-# INLINE timesWith #-}
1040timesWith :: (IsStream t, MonadAsync m) => Double -> t m (AbsTime, RelTime64)
1041timesWith g = fromStreamD $ D.times g
1043-- | @times@ returns a stream of time value tuples with clock of 10 ms
1044-- granularity. The first component of the tuple is an absolute time reference
1045-- (epoch) denoting the start of the stream and the second component is a time
1046-- relative to the reference.
1048-- @
1049-- >>> S.mapM_ (\x -> print x >> threadDelay 1000000) $ S.times
1050-- > (AbsTime (TimeSpec {sec = 2496295, nsec = 536223000}),RelTime64 (NanoSecond64 0))
1051-- > (AbsTime (TimeSpec {sec = 2496295, nsec = 536223000}),RelTime64 (NanoSecond64 1002028000))
1052-- > (AbsTime (TimeSpec {sec = 2496295, nsec = 536223000}),RelTime64 (NanoSecond64 1996656000))
1053-- @
1055-- Note: This API is not safe on 32-bit machines.
1057-- /Internal/
1059{-# INLINE times #-}
1060times :: (IsStream t, MonadAsync m) => t m (AbsTime, RelTime64)
1061times = timesWith 0.01
1063-- | @absTimesWith g@ returns a stream of absolute timestamps using a clock of
1064-- granularity @g@ specified in seconds. A low granularity clock is more
1065-- expensive in terms of CPU usage. Any granularity lower than 1 ms is treated
1066-- as 1 ms.
1068-- @
1069-- >>> S.mapM_ print $ S.delayPre 1 $ S.absTimesWith 0.01
1070-- @
1072-- Note: This API is not safe on 32-bit machines.
1074-- /Internal/
1076{-# INLINE absTimesWith #-}
1077absTimesWith :: (IsStream t, MonadAsync m, Functor (t m))
1078 => Double -> t m AbsTime
1079absTimesWith = fmap (uncurry addToAbsTime64) . timesWith
1081-- | @absTimes@ returns a stream of absolute timestamps using a clock of 10 ms
1082-- granularity.
1084-- @
1085-- >>> S.mapM_ print $ S.delayPre 1 $ S.absTimes
1086-- @
1088-- Note: This API is not safe on 32-bit machines.
1090-- /Internal/
1092{-# INLINE absTimes #-}
1093absTimes :: (IsStream t, MonadAsync m, Functor (t m)) => t m AbsTime
1094absTimes = fmap (uncurry addToAbsTime64) times
1096{-# DEPRECATED currentTime "Please use absTimes instead" #-}
1097{-# INLINE currentTime #-}
1098currentTime :: (IsStream t, MonadAsync m, Functor (t m))
1099 => Double -> t m AbsTime
1100currentTime = absTimesWith
1102-- | @relTimesWith g@ returns a stream of relative time values starting from 0,
1103-- using a clock of granularity @g@ specified in seconds. A low granularity
1104-- clock is more expensive in terms of CPU usage. Any granularity lower than 1
1105-- ms is treated as 1 ms.
1107-- @
1108-- >>> S.mapM_ print $ S.delayPre 1 $ S.relTimesWith 0.01
1109-- > RelTime64 (NanoSecond64 0)
1110-- > RelTime64 (NanoSecond64 91139000)
1111-- > RelTime64 (NanoSecond64 204052000)
1112-- @
1114-- Note: This API is not safe on 32-bit machines.
1116-- /Internal/
1118{-# INLINE relTimesWith #-}
1119relTimesWith :: (IsStream t, MonadAsync m, Functor (t m))
1120 => Double -> t m RelTime64
1121relTimesWith = fmap snd . timesWith
1123-- | @relTimes@ returns a stream of relative time values starting from 0,
1124-- using a clock of granularity 10 ms.
1126-- @
1127-- >>> S.mapM_ print $ S.delayPre 1 $ S.relTimes
1128-- @
1130-- Note: This API is not safe on 32-bit machines.
1132-- /Internal/
1134{-# INLINE relTimes #-}
1135relTimes :: (IsStream t, MonadAsync m, Functor (t m)) => t m RelTime64
1136relTimes = fmap snd times
1138-- | @durations g@ returns a stream of relative time values measuring the time
1139-- elapsed since the immediate predecessor element of the stream was generated.
1140-- The first element of the stream is always 0. @durations@ uses a clock of
1141-- granularity @g@ specified in seconds. A low granularity clock is more
1142-- expensive in terms of CPU usage. The minimum granularity is 1 millisecond.
1143-- Durations lower than 1 ms will be 0.
1145-- Note: This API is not safe on 32-bit machines.
1147-- /Unimplemented/
1149{-# INLINE durations #-}
1150durations :: -- (IsStream t, MonadAsync m) =>
1151 Double -> t m RelTime64
1152durations = undefined
1154-- | Generate ticks at the specified rate. The rate is adaptive, the tick
1155-- generation speed can be increased or decreased at different times to achieve
1156-- the specified rate. The specific behavior for different styles of 'Rate'
1157-- specifications is documented under 'Rate'. The effective maximum rate
1158-- achieved by a stream is governed by the processor speed.
1160-- /Unimplemented/
1162{-# INLINE ticks #-}
1163ticks :: -- (IsStream t, MonadAsync m) =>
1164 Rate -> t m ()
1165ticks = undefined
1167-- | Generate a singleton event at or after the specified absolute time. Note
1168-- that this is different from a threadDelay, a threadDelay starts from the
1169-- time when the action is evaluated, whereas if we use AbsTime based timeout
1170-- it will immediately expire if the action is evaluated too late.
1172-- /Unimplemented/
1174{-# INLINE timeout #-}
1175timeout :: -- (IsStream t, MonadAsync m) =>
1176 AbsTime -> t m ()
1177timeout = undefined
1179------------------------------------------------------------------------------
1180-- Elimination by Folding
1181------------------------------------------------------------------------------
1183-- | Right associative/lazy pull fold. @foldrM build final stream@ constructs
1184-- an output structure using the step function @build@. @build@ is invoked with
1185-- the next input element and the remaining (lazy) tail of the output
1186-- structure. It builds a lazy output expression using the two. When the "tail
1187-- structure" in the output expression is evaluated it calls @build@ again thus
1188-- lazily consuming the input @stream@ until either the output expression built
1189-- by @build@ is free of the "tail" or the input is exhausted in which case
1190-- @final@ is used as the terminating case for the output structure. For more
1191-- details see the description in the previous section.
1193-- Example, determine if any element is 'odd' in a stream:
1195-- >>> S.foldrM (\x xs -> if odd x then return True else xs) (return False) $ S.fromList (2:4:5:undefined)
1196-- > True
1198-- /Since: 0.7.0 (signature changed)/
1200-- /Since: 0.2.0 (signature changed)/
1202-- /Since: 0.1.0/
1203{-# INLINE foldrM #-}
1204foldrM :: Monad m => (a -> m b -> m b) -> m b -> SerialT m a -> m b
1205foldrM = P.foldrM
1207-- | Right fold to a streaming monad.
1209-- > foldrS S.cons S.nil === id
1211-- 'foldrS' can be used to perform stateless stream to stream transformations
1212-- like map and filter in general. It can be coupled with a scan to perform
1213-- stateful transformations. However, note that the custom map and filter
1214-- routines can be much more efficient than this due to better stream fusion.
1216-- >>> S.toList $ S.foldrS S.cons S.nil $ S.fromList [1..5]
1217-- > [1,2,3,4,5]
1219-- Find if any element in the stream is 'True':
1221-- >>> 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)
1222-- > [True]
1224-- Map (+2) on odd elements and filter out the even elements:
1226-- >>> 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)
1227-- > [3,5,7]
1229-- 'foldrM' can also be represented in terms of 'foldrS', however, the former
1230-- is much more efficient:
1232-- > foldrM f z s = runIdentityT $ foldrS (\x xs -> lift $ f x (runIdentityT xs)) (lift z) s
1234-- /Internal/
1235{-# INLINE foldrS #-}
1236foldrS :: IsStream t => (a -> t m b -> t m b) -> t m b -> t m a -> t m b
1237foldrS = K.foldrS
1239-- | Right fold to a transformer monad. This is the most general right fold
1240-- function. 'foldrS' is a special case of 'foldrT', however 'foldrS'
1241-- implementation can be more efficient:
1243-- > foldrS = foldrT
1244-- > foldrM f z s = runIdentityT $ foldrT (\x xs -> lift $ f x (runIdentityT xs)) (lift z) s
1246-- 'foldrT' can be used to translate streamly streams to other transformer
1247-- monads e.g. to a different streaming type.
1249-- /Internal/
1250{-# INLINE foldrT #-}
1251foldrT :: (IsStream t, Monad m, Monad (s m), MonadTrans s)
1252 => (a -> s m b -> s m b) -> s m b -> t m a -> s m b
1253foldrT f z s = S.foldrT f z (toStreamS s)
1255-- | Right fold, lazy for lazy monads and pure streams, and strict for strict
1256-- monads.
1258-- Please avoid using this routine in strict monads like IO unless you need a
1259-- strict right fold. This is provided only for use in lazy monads (e.g.
1260-- Identity) or pure streams. Note that with this signature it is not possible
1261-- to implement a lazy foldr when the monad @m@ is strict. In that case it
1262-- would be strict in its accumulator and therefore would necessarily consume
1263-- all its input.
1265-- @since 0.1.0
1266{-# INLINE foldr #-}
1267foldr :: Monad m => (a -> b -> b) -> b -> SerialT m a -> m b
1268foldr = P.foldr
1270-- XXX This seems to be of limited use as it cannot be used to construct
1271-- recursive structures and for reduction foldl1' is better.
1273-- | Lazy right fold for non-empty streams, using first element as the starting
1274-- value. Returns 'Nothing' if the stream is empty.
1276-- @since 0.5.0
1277{-# INLINE foldr1 #-}
1278{-# DEPRECATED foldr1 "Use foldrM instead." #-}
1279foldr1 :: Monad m => (a -> a -> a) -> SerialT m a -> m (Maybe a)
1280foldr1 f m = S.foldr1 f (toStreamS m)
1282-- | Strict left fold with an extraction function. Like the standard strict
1283-- left fold, but applies a user supplied extraction function (the third
1284-- argument) to the folded value at the end. This is designed to work with the
1285-- @foldl@ library. The suffix @x@ is a mnemonic for extraction.
1287-- @since 0.2.0
1288{-# DEPRECATED foldx "Please use foldl' followed by fmap instead." #-}
1289{-# INLINE foldx #-}
1290foldx :: Monad m => (x -> a -> x) -> x -> (x -> b) -> SerialT m a -> m b
1291foldx = P.foldlx'
1293-- | Left associative/strict push fold. @foldl' reduce initial stream@ invokes
1294-- @reduce@ with the accumulator and the next input in the input stream, using
1295-- @initial@ as the initial value of the current value of the accumulator. When
1296-- the input is exhausted the current value of the accumulator is returned.
1297-- Make sure to use a strict data structure for accumulator to not build
1298-- unnecessary lazy expressions unless that's what you want. See the previous
1299-- section for more details.
1301-- @since 0.2.0
1302{-# INLINE foldl' #-}
1303foldl' :: Monad m => (b -> a -> b) -> b -> SerialT m a -> m b
1304foldl' = P.foldl'
1306-- | Strict left fold, for non-empty streams, using first element as the
1307-- starting value. Returns 'Nothing' if the stream is empty.
1309-- @since 0.5.0
1310{-# INLINE foldl1' #-}
1311foldl1' :: Monad m => (a -> a -> a) -> SerialT m a -> m (Maybe a)
1312foldl1' step m = do
1313 r <- uncons m
1314 case r of
1315 Nothing -> return Nothing
1316 Just (h, t) -> do
1317 res <- foldl' step h t
1318 return $ Just res
1320-- | Like 'foldx', but with a monadic step function.
1322-- @since 0.2.0
1323{-# DEPRECATED foldxM "Please use foldlM' followed by fmap instead." #-}
1324{-# INLINE foldxM #-}
1325foldxM :: Monad m => (x -> a -> m x) -> m x -> (x -> m b) -> SerialT m a -> m b
1326foldxM = P.foldlMx'
1328-- | Like 'foldl'' but with a monadic step function.
1330-- @since 0.2.0
1331{-# INLINE foldlM' #-}
1332foldlM' :: Monad m => (b -> a -> m b) -> m b -> SerialT m a -> m b
1333foldlM' step begin m = S.foldlM' step begin $ toStreamS m
1335------------------------------------------------------------------------------
1336-- Running a Fold
1337------------------------------------------------------------------------------
1339-- | Fold a stream using the supplied left fold.
1341-- >>> S.fold FL.sum (S.enumerateFromTo 1 100)
1342-- 5050
1344-- @since 0.7.0
1345{-# INLINE fold #-}
1346fold :: Monad m => Fold m a b -> SerialT m a -> m b
1347fold = P.runFold
1349------------------------------------------------------------------------------
1350-- Running a sink
1351------------------------------------------------------------------------------
1354-- | Drain a stream to a 'Sink'.
1355{-# INLINE runSink #-}
1356runSink :: Monad m => Sink m a -> SerialT m a -> m ()
1357runSink = fold . toFold
1360------------------------------------------------------------------------------
1361-- Running a Parser
1362------------------------------------------------------------------------------
1364-- | Parse a stream using the supplied 'Parser'.
1366-- /Internal/
1368{-# INLINE_NORMAL parseD #-}
1369parseD :: MonadThrow m => PRD.Parser m a b -> SerialT m a -> m b
1370parseD (PRD.Parser step initial extract) = P.parselMx' step initial extract
1372{-# INLINE parseK #-}
1373parseK :: MonadThrow m => PRK.Parser m a b -> SerialT m a -> m b
1374parseK = parse
1376-- | Parse a stream using the supplied 'Parser'.
1378-- /Internal/
1380{-# INLINE [3] parse #-}
1381parse :: MonadThrow m => Parser m a b -> SerialT m a -> m b
1382parse = parseD . PRK.fromParserK
1384------------------------------------------------------------------------------
1385-- Specialized folds
1386------------------------------------------------------------------------------
1388-- |
1389-- > drain = mapM_ (\_ -> return ())
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 @drain . 'asyncly'@.
1395-- @since 0.7.0
1396{-# INLINE drain #-}
1397drain :: Monad m => SerialT m a -> m ()
1398drain = P.drain
1400-- | Run a stream, discarding the results. By default it interprets the stream
1401-- as 'SerialT', to run other types of streams use the type adapting
1402-- combinators for example @runStream . 'asyncly'@.
1404-- @since 0.2.0
1405{-# DEPRECATED runStream "Please use \"drain\" instead" #-}
1406{-# INLINE runStream #-}
1407runStream :: Monad m => SerialT m a -> m ()
1408runStream = drain
1410-- |
1411-- > drainN n = drain . take n
1413-- Run maximum up to @n@ iterations of a stream.
1415-- @since 0.7.0
1416{-# INLINE drainN #-}
1417drainN :: Monad m => Int -> SerialT m a -> m ()
1418drainN n = drain . take n
1420-- |
1421-- > runN n = runStream . take n
1423-- Run maximum up to @n@ iterations of a stream.
1425-- @since 0.6.0
1426{-# DEPRECATED runN "Please use \"drainN\" instead" #-}
1427{-# INLINE runN #-}
1428runN :: Monad m => Int -> SerialT m a -> m ()
1429runN = drainN
1431-- |
1432-- > drainWhile p = drain . takeWhile p
1434-- Run a stream as long as the predicate holds true.
1436-- @since 0.7.0
1437{-# INLINE drainWhile #-}
1438drainWhile :: Monad m => (a -> Bool) -> SerialT m a -> m ()
1439drainWhile p = drain . takeWhile p
1441-- |
1442-- > runWhile p = runStream . takeWhile p
1444-- Run a stream as long as the predicate holds true.
1446-- @since 0.6.0
1447{-# DEPRECATED runWhile "Please use \"drainWhile\" instead" #-}
1448{-# INLINE runWhile #-}
1449runWhile :: Monad m => (a -> Bool) -> SerialT m a -> m ()
1450runWhile = drainWhile
1452-- | Determine whether the stream is empty.
1454-- @since 0.1.1
1455{-# INLINE null #-}
1456null :: Monad m => SerialT m a -> m Bool
1457null = S.null . toStreamS
1459-- | Extract the first element of the stream, if any.
1461-- > head = (!! 0)
1463-- @since 0.1.0
1464{-# INLINE head #-}
1465head :: Monad m => SerialT m a -> m (Maybe a)
1466head = S.head . toStreamS
1468-- | Extract the first element of the stream, if any, otherwise use the
1469-- supplied default value. It can help avoid one branch in high performance
1470-- code.
1472-- /Internal/
1473{-# INLINE headElse #-}
1474headElse :: Monad m => a -> SerialT m a -> m a
1475headElse x = D.headElse x . toStreamD
1477-- |
1478-- > tail = fmap (fmap snd) . uncons
1480-- Extract all but the first element of the stream, if any.
1482-- @since 0.1.1
1483{-# INLINE tail #-}
1484tail :: (IsStream t, Monad m) => SerialT m a -> m (Maybe (t m a))
1485tail m = K.tail (K.adapt m)
1487-- | Extract all but the last element of the stream, if any.
1489-- @since 0.5.0
1490{-# INLINE init #-}
1491init :: (IsStream t, Monad m) => SerialT m a -> m (Maybe (t m a))
1492init m = K.init (K.adapt m)
1494-- | Extract the last element of the stream, if any.
1496-- > last xs = xs !! (length xs - 1)
1498-- @since 0.1.1
1499{-# INLINE last #-}
1500last :: Monad m => SerialT m a -> m (Maybe a)
1501last m = S.last $ toStreamS m
1503-- | Determine whether an element is present in the stream.
1505-- @since 0.1.0
1506{-# INLINE elem #-}
1507elem :: (Monad m, Eq a) => a -> SerialT m a -> m Bool
1508elem e m = S.elem e (toStreamS m)
1510-- | Determine whether an element is not present in the stream.
1512-- @since 0.1.0
1513{-# INLINE notElem #-}
1514notElem :: (Monad m, Eq a) => a -> SerialT m a -> m Bool
1515notElem e m = S.notElem e (toStreamS m)
1517-- | Determine the length of the stream.
1519-- @since 0.1.0
1520{-# INLINE length #-}
1521length :: Monad m => SerialT m a -> m Int
1522length = foldl' (\n _ -> n + 1) 0
1524-- | Determine whether all elements of a stream satisfy a predicate.
1526-- @since 0.1.0
1527{-# INLINE all #-}
1528all :: Monad m => (a -> Bool) -> SerialT m a -> m Bool
1529all p m = S.all p (toStreamS m)
1531-- | Determine whether any of the elements of a stream satisfy a predicate.
1533-- @since 0.1.0
1534{-# INLINE any #-}
1535any :: Monad m => (a -> Bool) -> SerialT m a -> m Bool
1536any p m = S.any p (toStreamS m)
1538-- | Determines if all elements of a boolean stream are True.
1540-- @since 0.5.0
1541{-# INLINE and #-}
1542and :: Monad m => SerialT m Bool -> m Bool
1543and = all (==True)
1545-- | Determines whether at least one element of a boolean stream is True.
1547-- @since 0.5.0
1548{-# INLINE or #-}
1549or :: Monad m => SerialT m Bool -> m Bool
1550or = any (==True)
1552-- | Determine the sum of all elements of a stream of numbers. Returns @0@ when
1553-- the stream is empty. Note that this is not numerically stable for floating
1554-- point numbers.
1556-- @since 0.1.0
1557{-# INLINE sum #-}
1558sum :: (Monad m, Num a) => SerialT m a -> m a
1559sum = foldl' (+) 0
1561-- | Determine the product of all elements of a stream of numbers. Returns @1@
1562-- when the stream is empty.
1564-- @since 0.1.1
1565{-# INLINE product #-}
1566product :: (Monad m, Num a) => SerialT m a -> m a
1567product = foldl' (*) 1
1569-- | Fold a stream of monoid elements by appending them.
1571-- /Internal/
1572{-# INLINE mconcat #-}
1573mconcat :: (Monad m, Monoid a) => SerialT m a -> m a
1574mconcat = foldr mappend mempty
1576-- |
1577-- @
1578-- minimum = 'minimumBy' compare
1579-- @
1581-- Determine the minimum element in a stream.
1583-- @since 0.1.0
1584{-# INLINE minimum #-}
1585minimum :: (Monad m, Ord a) => SerialT m a -> m (Maybe a)
1586minimum m = S.minimum (toStreamS m)
1588-- | Determine the minimum element in a stream using the supplied comparison
1589-- function.
1591-- @since 0.6.0
1592{-# INLINE minimumBy #-}
1593minimumBy :: Monad m => (a -> a -> Ordering) -> SerialT m a -> m (Maybe a)
1594minimumBy cmp m = S.minimumBy cmp (toStreamS m)
1596-- |
1597-- @
1598-- maximum = 'maximumBy' compare
1599-- @
1601-- Determine the maximum element in a stream.
1603-- @since 0.1.0
1604{-# INLINE maximum #-}
1605maximum :: (Monad m, Ord a) => SerialT m a -> m (Maybe a)
1606maximum = P.maximum
1608-- | Determine the maximum element in a stream using the supplied comparison
1609-- function.
1611-- @since 0.6.0
1612{-# INLINE maximumBy #-}
1613maximumBy :: Monad m => (a -> a -> Ordering) -> SerialT m a -> m (Maybe a)
1614maximumBy cmp m = S.maximumBy cmp (toStreamS m)
1616-- | Lookup the element at the given index.
1618-- @since 0.6.0
1619{-# INLINE (!!) #-}
1620(!!) :: Monad m => SerialT m a -> Int -> m (Maybe a)
1621m !! i = toStreamS m S.!! i
1623-- | In a stream of (key-value) pairs @(a, b)@, return the value @b@ of the
1624-- first pair where the key equals the given value @a@.
1626-- > lookup = snd <$> find ((==) . fst)
1628-- @since 0.5.0
1629{-# INLINE lookup #-}
1630lookup :: (Monad m, Eq a) => a -> SerialT m (a, b) -> m (Maybe b)
1631lookup a m = S.lookup a (toStreamS m)
1633-- | Like 'findM' but with a non-monadic predicate.
1635-- > find p = findM (return . p)
1637-- @since 0.5.0
1638{-# INLINE find #-}
1639find :: Monad m => (a -> Bool) -> SerialT m a -> m (Maybe a)
1640find p m = S.find p (toStreamS m)
1642-- | Returns the first element that satisfies the given predicate.
1644-- @since 0.6.0
1645{-# INLINE findM #-}
1646findM :: Monad m => (a -> m Bool) -> SerialT m a -> m (Maybe a)
1647findM p m = S.findM p (toStreamS m)
1649-- | Find all the indices where the element in the stream satisfies the given
1650-- predicate.
1652-- @since 0.5.0
1653{-# INLINE findIndices #-}
1654findIndices :: (IsStream t, Monad m) => (a -> Bool) -> t m a -> t m Int
1655findIndices p m = fromStreamS $ S.findIndices p (toStreamS m)
1657-- | Returns the first index that satisfies the given predicate.
1659-- @since 0.5.0
1660{-# INLINE findIndex #-}
1661findIndex :: Monad m => (a -> Bool) -> SerialT m a -> m (Maybe Int)
1662findIndex p = head . findIndices p
1664-- | Find all the indices where the value of the element in the stream is equal
1665-- to the given value.
1667-- @since 0.5.0
1668{-# INLINE elemIndices #-}
1669elemIndices :: (IsStream t, Eq a, Monad m) => a -> t m a -> t m Int
1670elemIndices a = findIndices (==a)
1672-- | Returns the first index where a given value is found in the stream.
1674-- > elemIndex a = findIndex (== a)
1676-- @since 0.5.0
1677{-# INLINE elemIndex #-}
1678elemIndex :: (Monad m, Eq a) => a -> SerialT m a -> m (Maybe Int)
1679elemIndex a = findIndex (== a)
1681------------------------------------------------------------------------------
1682-- Substreams
1683------------------------------------------------------------------------------
1685-- | Returns 'True' if the first stream is the same as or a prefix of the
1686-- second. A stream is a prefix of itself.
1688-- @
1689-- > S.isPrefixOf (S.fromList "hello") (S.fromList "hello" :: SerialT IO Char)
1690-- True
1691-- @
1693-- @since 0.6.0
1694{-# INLINE isPrefixOf #-}
1695isPrefixOf :: (Eq a, IsStream t, Monad m) => t m a -> t m a -> m Bool
1696isPrefixOf m1 m2 = D.isPrefixOf (toStreamD m1) (toStreamD m2)
1698-- Note: isPrefixOf uses the prefix stream only once. In contrast, isSuffixOf
1699-- may use the suffix stream many times. To run in optimal memory we do not
1700-- want to buffer the suffix stream in memory therefore we need an ability to
1701-- clone (or consume it multiple times) the suffix stream without any side
1702-- effects so that multiple potential suffix matches can proceed in parallel
1703-- without buffering the suffix stream. For example, we may create the suffix
1704-- stream from a file handle, however, if we evaluate the stream multiple
1705-- times, once for each match, we will need a different file handle each time
1706-- which may exhaust the file descriptors. Instead, we want to share the same
1707-- underlying file descriptor, use pread on it to generate the stream and clone
1708-- the stream for each match. Therefore the suffix stream should be built in
1709-- such a way that it can be consumed multiple times without any problems.
1711-- XXX Can be implemented with better space/time complexity.
1712-- Space: @O(n)@ worst case where @n@ is the length of the suffix.
1714-- | Returns 'True' if the first stream is a suffix of the second. A stream is
1715-- considered a suffix of itself.
1717-- @
1718-- > S.isSuffixOf (S.fromList "hello") (S.fromList "hello" :: SerialT IO Char)
1719-- True
1720-- @
1722-- Space: @O(n)@, buffers entire input stream and the suffix.
1724-- /Internal/
1726-- /Suboptimal/ - Help wanted.
1728{-# INLINE isSuffixOf #-}
1729isSuffixOf :: (Monad m, Eq a) => SerialT m a -> SerialT m a -> m Bool
1730isSuffixOf suffix stream = reverse suffix `isPrefixOf` reverse stream
1732-- | Returns 'True' if the first stream is an infix of the second. A stream is
1733-- considered an infix of itself.
1735-- @
1736-- > S.isInfixOf (S.fromList "hello") (S.fromList "hello" :: SerialT IO Char)
1737-- True
1738-- @
1740-- Space: @O(n)@ worst case where @n@ is the length of the infix.
1742-- /Internal/
1744-- /Requires 'Storable' constraint/ - Help wanted.
1746{-# INLINE isInfixOf #-}
1747isInfixOf :: (MonadIO m, Eq a, Enum a, Storable a)
1748 => SerialT m a -> SerialT m a -> m Bool
1749isInfixOf infx stream = do
1750 arr <- fold A.write infx
1751 -- XXX can use breakOnSeq instead (when available)
1752 r <- null $ drop 1 $ splitOnSeq arr FL.drain stream
1753 return (not r)
1755-- | Returns 'True' if all the elements of the first stream occur, in order, in
1756-- the second stream. The elements do not have to occur consecutively. A stream
1757-- is a subsequence of itself.
1759-- @
1760-- > S.isSubsequenceOf (S.fromList "hlo") (S.fromList "hello" :: SerialT IO Char)
1761-- True
1762-- @
1764-- @since 0.6.0
1765{-# INLINE isSubsequenceOf #-}
1766isSubsequenceOf :: (Eq a, IsStream t, Monad m) => t m a -> t m a -> m Bool
1767isSubsequenceOf m1 m2 = D.isSubsequenceOf (toStreamD m1) (toStreamD m2)
1769-- | Strip prefix if present and tell whether it was stripped or not. Returns
1770-- 'Nothing' if the stream does not start with the given prefix, stripped
1771-- stream otherwise. Returns @Just nil@ when the prefix is the same as the
1772-- stream.
1774-- Space: @O(1)@
1776-- @since 0.6.0
1777{-# INLINE stripPrefix #-}
1778stripPrefix
1779 :: (Eq a, IsStream t, Monad m)
1780 => t m a -> t m a -> m (Maybe (t m a))
1781stripPrefix m1 m2 = fmap fromStreamD <$>
1782 D.stripPrefix (toStreamD m1) (toStreamD m2)
1784-- Note: If we want to return a Maybe value to know whether the
1785-- suffix/infix was present or not along with the stripped stream then
1786-- we need to buffer the whole input stream.
1788-- | Drops the given suffix from a stream. Returns 'Nothing' if the stream does
1789-- not end with the given suffix. Returns @Just nil@ when the suffix is the
1790-- same as the stream.
1792-- It may be more efficient to convert the stream to an Array and use
1793-- stripSuffix on that especially if the elements have a Storable or Prim
1794-- instance.
1796-- Space: @O(n)@, buffers the entire input stream as well as the suffix
1798-- /Internal/
1799{-# INLINE stripSuffix #-}
1800stripSuffix
1801 :: (Monad m, Eq a)
1802 => SerialT m a -> SerialT m a -> m (Maybe (SerialT m a))
1803stripSuffix m1 m2 = fmap reverse <$> stripPrefix (reverse m1) (reverse m2)
1805-- | Drop prefix from the input stream if present.
1807-- Space: @O(1)@
1809-- /Unimplemented/ - Help wanted.
1810{-# INLINE dropPrefix #-}
1811dropPrefix ::
1812 -- (Eq a, IsStream t, Monad m) =>
1813 t m a -> t m a -> t m a
1814dropPrefix = error "Not implemented yet!"
1816-- | Drop all matching infix from the input stream if present. Infix stream
1817-- may be consumed multiple times.
1819-- Space: @O(n)@ where n is the length of the infix.
1821-- /Unimplemented/ - Help wanted.
1822{-# INLINE dropInfix #-}
1823dropInfix ::
1824 -- (Eq a, IsStream t, Monad m) =>
1825 t m a -> t m a -> t m a
1826dropInfix = error "Not implemented yet!"
1828-- | Drop suffix from the input stream if present. Suffix stream may be
1829-- consumed multiple times.
1831-- Space: @O(n)@ where n is the length of the suffix.
1833-- /Unimplemented/ - Help wanted.
1834{-# INLINE dropSuffix #-}
1835dropSuffix ::
1836 -- (Eq a, IsStream t, Monad m) =>
1837 t m a -> t m a -> t m a
1838dropSuffix = error "Not implemented yet!"
1840------------------------------------------------------------------------------
1841-- Map and Fold
1842------------------------------------------------------------------------------
1844-- XXX this can utilize parallel mapping if we implement it as drain . mapM
1845-- |
1846-- > mapM_ = drain . mapM
1848-- Apply a monadic action to each element of the stream and discard the output
1849-- of the action. This is not really a pure transformation operation but a
1850-- transformation followed by fold.
1852-- @since 0.1.0
1853{-# INLINE mapM_ #-}
1854mapM_ :: Monad m => (a -> m b) -> SerialT m a -> m ()
1855mapM_ f m = S.mapM_ f $ toStreamS m
1857------------------------------------------------------------------------------
1858-- Conversions
1859------------------------------------------------------------------------------
1861-- |
1862-- @
1863-- toList = S.foldr (:) []
1864-- @
1866-- Convert a stream into a list in the underlying monad. The list can be
1867-- consumed lazily in a lazy monad (e.g. 'Identity'). In a strict monad (e.g.
1868-- IO) the whole list is generated and buffered before it can be consumed.
1870-- /Warning!/ working on large lists accumulated as buffers in memory could be
1871-- very inefficient, consider using "Streamly.Array" instead.
1873-- @since 0.1.0
1874{-# INLINE toList #-}
1875toList :: Monad m => SerialT m a -> m [a]
1876toList = P.toList
1878-- |
1879-- @
1880-- toListRev = S.foldl' (flip (:)) []
1881-- @
1883-- Convert a stream into a list in reverse order in the underlying monad.
1885-- /Warning!/ working on large lists accumulated as buffers in memory could be
1886-- very inefficient, consider using "Streamly.Array" instead.
1888-- /Internal/
1889{-# INLINE toListRev #-}
1890toListRev :: Monad m => SerialT m a -> m [a]
1891toListRev = D.toListRev . toStreamD
1893-- |
1894-- @
1895-- toHandle h = S.mapM_ $ hPutStrLn h
1896-- @
1898-- Write a stream of Strings to an IO Handle.
1900-- @since 0.1.0
1901{-# DEPRECATED toHandle
1902 "Please use Streamly.FileSystem.Handle module (see the changelog)" #-}
1903toHandle :: MonadIO m => IO.Handle -> SerialT m String -> m ()
1904toHandle h = go
1905 where
1906 go m1 =
1907 let stop = return ()
1908 single a = liftIO (IO.hPutStrLn h a)
1909 yieldk a r = liftIO (IO.hPutStrLn h a) >> go r
1910 in K.foldStream defState yieldk single stop m1
1912-- XXX rename these to write/writeRev to make the naming consistent with folds
1913-- in other modules.
1915-- | A fold that buffers its input to a pure stream.
1917-- /Warning!/ working on large streams accumulated as buffers in memory could
1918-- be very inefficient, consider using "Streamly.Data.Array" instead.
1920-- /Internal/
1921{-# INLINE toStream #-}
1922toStream :: Monad m => Fold m a (SerialT Identity a)
1923toStream = Fold (\f x -> return $ f . (x `K.cons`))
1924 (return id)
1925 (return . ($ K.nil))
1927-- This is more efficient than 'toStream'. toStream is exactly the same as
1928-- reversing the stream after toStreamRev.
1930-- | Buffers the input stream to a pure stream in the reverse order of the
1931-- input.
1933-- /Warning!/ working on large streams accumulated as buffers in memory could
1934-- be very inefficient, consider using "Streamly.Data.Array" instead.
1936-- /Internal/
1938-- xn : ... : x2 : x1 : []
1939{-# INLINABLE toStreamRev #-}
1940toStreamRev :: Monad m => Fold m a (SerialT Identity a)
1941toStreamRev = Fold (\xs x -> return $ x `K.cons` xs) (return K.nil) return
1943-- | Convert a stream to a pure stream.
1945-- @
1946-- toPure = foldr cons nil
1947-- @
1949-- /Internal/
1951{-# INLINE toPure #-}
1952toPure :: Monad m => SerialT m a -> m (SerialT Identity a)
1953toPure = foldr K.cons K.nil
1955-- | Convert a stream to a pure stream in reverse order.
1957-- @
1958-- toPureRev = foldl' (flip cons) nil
1959-- @
1961-- /Internal/
1963{-# INLINE toPureRev #-}
1964toPureRev :: Monad m => SerialT m a -> m (SerialT Identity a)
1965toPureRev = foldl' (flip K.cons) K.nil
1967------------------------------------------------------------------------------
1968-- Concurrent Application
1969------------------------------------------------------------------------------
1971infixr 0 |$
1972infixr 0 |$.
1974infixl 1 |&
1975infixl 1 |&.
1977-- | Parallel transform application operator; applies a stream transformation
1978-- function @t m a -> t m b@ to a stream @t m a@ concurrently; the input stream
1979-- is evaluated asynchronously in an independent thread yielding elements to a
1980-- buffer and the transformation function runs in another thread consuming the
1981-- input from the buffer. '|$' is just like regular function application
1982-- operator '$' except that it is concurrent.
1984-- If you read the signature as @(t m a -> t m b) -> (t m a -> t m b)@ you can
1985-- look at it as a transformation that converts a transform function to a
1986-- buffered concurrent transform function.
1988-- The following code prints a value every second even though each stage adds a
1989-- 1 second delay.
1992-- @
1993-- drain $
1994-- S.mapM (\\x -> threadDelay 1000000 >> print x)
1995-- |$ S.repeatM (threadDelay 1000000 >> return 1)
1996-- @
1998-- /Concurrent/
2000-- @since 0.3.0
2001{-# INLINE (|$) #-}
2002(|$) :: (IsStream t, MonadAsync m) => (t m a -> t m b) -> (t m a -> t m b)
2003-- (|$) f = f . Async.mkAsync
2004(|$) f = f . D.mkParallel
2006-- | Same as '|$'.
2008-- /Internal/
2010{-# INLINE applyAsync #-}
2011applyAsync :: (IsStream t, MonadAsync m)
2012 => (t m a -> t m b) -> (t m a -> t m b)
2013applyAsync = (|$)
2015-- | Parallel reverse function application operator for streams; just like the
2016-- regular reverse function application operator '&' except that it is
2017-- concurrent.
2019-- @
2020-- drain $
2021-- S.repeatM (threadDelay 1000000 >> return 1)
2022-- |& S.mapM (\\x -> threadDelay 1000000 >> print x)
2023-- @
2025-- /Concurrent/
2027-- @since 0.3.0
2028{-# INLINE (|&) #-}
2029(|&) :: (IsStream t, MonadAsync m) => t m a -> (t m a -> t m b) -> t m b
2030x |& f = f |$ x
2032-- | Parallel fold application operator; applies a fold function @t m a -> m b@
2033-- to a stream @t m a@ concurrently; The the input stream is evaluated
2034-- asynchronously in an independent thread yielding elements to a buffer and
2035-- the folding action runs in another thread consuming the input from the
2036-- buffer.
2038-- If you read the signature as @(t m a -> m b) -> (t m a -> m b)@ you can look
2039-- at it as a transformation that converts a fold function to a buffered
2040-- concurrent fold function.
2042-- The @.@ at the end of the operator is a mnemonic for termination of the
2043-- stream.
2045-- @
2046-- S.foldlM' (\\_ a -> threadDelay 1000000 >> print a) ()
2047-- |$. S.repeatM (threadDelay 1000000 >> return 1)
2048-- @
2050-- /Concurrent/
2052-- @since 0.3.0
2053{-# INLINE (|$.) #-}
2054(|$.) :: (IsStream t, MonadAsync m) => (t m a -> m b) -> (t m a -> m b)
2055-- (|$.) f = f . Async.mkAsync
2056(|$.) f = f . D.mkParallel
2058-- | Same as '|$.'.
2060-- /Internal/
2062{-# INLINE foldAsync #-}
2063foldAsync :: (IsStream t, MonadAsync m) => (t m a -> m b) -> (t m a -> m b)
2064foldAsync = (|$.)
2066-- | Parallel reverse function application operator for applying a run or fold
2067-- functions to a stream. Just like '|$.' except that the operands are reversed.
2069-- @
2070-- S.repeatM (threadDelay 1000000 >> return 1)
2071-- |&. S.foldlM' (\\_ a -> threadDelay 1000000 >> print a) ()
2072-- @
2074-- /Concurrent/
2076-- @since 0.3.0
2077{-# INLINE (|&.) #-}
2078(|&.) :: (IsStream t, MonadAsync m) => t m a -> (t m a -> m b) -> m b
2079x |&. f = f |$. x
2081------------------------------------------------------------------------------
2082-- General Transformation
2083------------------------------------------------------------------------------
2085-- | Use a 'Pipe' to transform a stream.
2087-- /Internal/
2089{-# INLINE transform #-}
2090transform :: (IsStream t, Monad m) => Pipe m a b -> t m a -> t m b
2091transform pipe xs = fromStreamD $ D.transform pipe (toStreamD xs)
2093------------------------------------------------------------------------------
2094-- Transformation by Folding (Scans)
2095------------------------------------------------------------------------------
2097-- XXX It may be useful to have a version of scan where we can keep the
2098-- accumulator independent of the value emitted. So that we do not necessarily
2099-- have to keep a value in the accumulator which we are not using. We can pass
2100-- an extraction function that will take the accumulator and the current value
2101-- of the element and emit the next value in the stream. That will also make it
2102-- possible to modify the accumulator after using it. In fact, the step function
2103-- can return new accumulator and the value to be emitted. The signature would
2104-- be more like mapAccumL. Or we can change the signature of scanx to
2105-- accommodate this.
2107-- | Strict left scan with an extraction function. Like 'scanl'', but applies a
2108-- user supplied extraction function (the third argument) at each step. This is
2109-- designed to work with the @foldl@ library. The suffix @x@ is a mnemonic for
2110-- extraction.
2112-- /Since: 0.7.0 (Monad m constraint)/
2114-- /Since 0.2.0/
2115{-# DEPRECATED scanx "Please use scanl followed by map instead." #-}
2116{-# INLINE scanx #-}
2117scanx :: (IsStream t, Monad m) => (x -> a -> x) -> x -> (x -> b) -> t m a -> t m b
2118scanx = P.scanlx'
2120-- XXX this needs to be concurrent
2121-- XXX because of the use of D.cons for appending, scanlM' has quadratic
2122-- complexity when iterated over a stream. We should use StreamK style scanlM'
2123-- for linear performance on iteration.
2125-- | Like 'scanl'' but with a monadic fold function.
2127-- @since 0.4.0
2128{-# INLINE scanlM' #-}
2129scanlM' :: (IsStream t, Monad m) => (b -> a -> m b) -> b -> t m a -> t m b
2130scanlM' step begin m = fromStreamD $ D.scanlM' step begin $ toStreamD m
2132-- | @scanlMAfter' accumulate initial done stream@ is like 'scanlM'' except
2133-- that it provides an additional @done@ function to be applied on the
2134-- accumulator when the stream stops. The result of @done@ is also emitted in
2135-- the stream.
2137-- This function can be used to allocate a resource in the beginning of the
2138-- scan and release it when the stream ends or to flush the internal state of
2139-- the scan at the end.
2141-- /Internal/
2143{-# INLINE scanlMAfter' #-}
2144scanlMAfter' :: (IsStream t, Monad m)
2145 => (b -> a -> m b) -> m b -> (b -> m b) -> t m a -> t m b
2146scanlMAfter' step initial done stream =
2147 fromStreamD $ D.scanlMAfter' step initial done $ toStreamD stream
2149-- XXX because of the use of D.cons for appending, scanl' has quadratic
2150-- complexity when iterated over a stream. We should use StreamK style scanlM'
2151-- for linear performance on iteration.
2153-- | Strict left scan. Like 'map', 'scanl'' too is a one to one transformation,
2154-- however it adds an extra element.
2156-- @
2157-- > S.toList $ S.scanl' (+) 0 $ fromList [1,2,3,4]
2158-- [0,1,3,6,10]
2159-- @
2161-- @
2162-- > S.toList $ S.scanl' (flip (:)) [] $ S.fromList [1,2,3,4]
2163-- [[],[1],[2,1],[3,2,1],[4,3,2,1]]
2164-- @
2166-- The output of 'scanl'' is the initial value of the accumulator followed by
2167-- all the intermediate steps and the final result of 'foldl''.
2169-- By streaming the accumulated state after each fold step, we can share the
2170-- state across multiple stages of stream composition. Each stage can modify or
2171-- extend the state, do some processing with it and emit it for the next stage,
2172-- thus modularizing the stream processing. This can be useful in
2173-- stateful or event-driven programming.
2175-- Consider the following monolithic example, computing the sum and the product
2176-- of the elements in a stream in one go using a @foldl'@:
2178-- @
2179-- > S.foldl' (\\(s, p) x -> (s + x, p * x)) (0,1) $ S.fromList \[1,2,3,4]
2180-- (10,24)
2181-- @
2183-- Using @scanl'@ we can make it modular by computing the sum in the first
2184-- stage and passing it down to the next stage for computing the product:
2186-- @
2187-- > S.foldl' (\\(_, p) (s, x) -> (s, p * x)) (0,1)
2188-- $ S.scanl' (\\(s, _) x -> (s + x, x)) (0,1)
2189-- $ S.fromList \[1,2,3,4]
2190-- (10,24)
2191-- @
2193-- IMPORTANT: 'scanl'' evaluates the accumulator to WHNF. To avoid building
2194-- lazy expressions inside the accumulator, it is recommended that a strict
2195-- data structure is used for accumulator.
2197-- See also: 'usingStateT'
2199-- @since 0.2.0
2200{-# INLINE scanl' #-}
2201scanl' :: (IsStream t, Monad m) => (b -> a -> b) -> b -> t m a -> t m b
2202scanl' step z m = fromStreamS $ S.scanl' step z $ toStreamS m
2204-- | Like 'scanl'' but does not stream the initial value of the accumulator.
2206-- > postscanl' f z xs = S.drop 1 $ S.scanl' f z xs
2208-- @since 0.7.0
2209{-# INLINE postscanl' #-}
2210postscanl' :: (IsStream t, Monad m) => (b -> a -> b) -> b -> t m a -> t m b
2211postscanl' step z m = fromStreamD $ D.postscanl' step z $ toStreamD m
2213-- XXX this needs to be concurrent
2214-- | Like 'postscanl'' but with a monadic step function.
2216-- @since 0.7.0
2217{-# INLINE postscanlM' #-}
2218postscanlM' :: (IsStream t, Monad m) => (b -> a -> m b) -> b -> t m a -> t m b
2219postscanlM' step z m = fromStreamD $ D.postscanlM' step z $ toStreamD m
2221-- XXX prescanl does not sound very useful, enable only if there is a
2222-- compelling use case.
2224-- | Like scanl' but does not stream the final value of the accumulator.
2226-- /Internal/
2227{-# INLINE prescanl' #-}
2228prescanl' :: (IsStream t, Monad m) => (b -> a -> b) -> b -> t m a -> t m b
2229prescanl' step z m = fromStreamD $ D.prescanl' step z $ toStreamD m
2231-- XXX this needs to be concurrent
2232-- | Like postscanl' but with a monadic step function.
2234-- /Internal/
2235{-# INLINE prescanlM' #-}
2236prescanlM' :: (IsStream t, Monad m) => (b -> a -> m b) -> m b -> t m a -> t m b
2237prescanlM' step z m = fromStreamD $ D.prescanlM' step z $ toStreamD m
2239-- XXX this needs to be concurrent
2240-- | Like 'scanl1'' but with a monadic step function.
2242-- @since 0.6.0
2243{-# INLINE scanl1M' #-}
2244scanl1M' :: (IsStream t, Monad m) => (a -> a -> m a) -> t m a -> t m a
2245scanl1M' step m = fromStreamD $ D.scanl1M' step $ toStreamD m
2247-- | Like 'scanl'' but for a non-empty stream. The first element of the stream
2248-- is used as the initial value of the accumulator. Does nothing if the stream
2249-- is empty.
2251-- @
2252-- > S.toList $ S.scanl1 (+) $ fromList [1,2,3,4]
2253-- [1,3,6,10]
2254-- @
2256-- @since 0.6.0
2257{-# INLINE scanl1' #-}
2258scanl1' :: (IsStream t, Monad m) => (a -> a -> a) -> t m a -> t m a
2259scanl1' step m = fromStreamD $ D.scanl1' step $ toStreamD m
2261------------------------------------------------------------------------------
2262-- Scanning with a Fold
2263------------------------------------------------------------------------------
2265-- | Scan a stream using the given monadic fold.
2267-- @since 0.7.0
2268{-# INLINE scan #-}
2269scan :: (IsStream t, Monad m) => Fold m a b -> t m a -> t m b
2270scan (Fold step begin done) = P.scanlMx' step begin done
2272-- | Postscan a stream using the given monadic fold.
2274-- @since 0.7.0
2275{-# INLINE postscan #-}
2276postscan :: (IsStream t, Monad m) => Fold m a b -> t m a -> t m b
2277postscan (Fold step begin done) = P.postscanlMx' step begin done
2279------------------------------------------------------------------------------
2280-- Stateful Transformations
2281------------------------------------------------------------------------------
2283-- XXX this is not a one-to-one map so calling it map may not be right.
2284-- We can perhaps call it zipWithTail or rollWith.
2286-- | Apply a function on every two successive elements of a stream. If the
2287-- stream consists of a single element the output is an empty stream.
2289-- This is the stream equivalent of the list idiom @zipWith f xs (tail xs)@.
2291-- /Internal/
2293{-# INLINE rollingMap #-}
2294rollingMap :: (IsStream t, Monad m) => (a -> a -> b) -> t m a -> t m b
2295rollingMap f m = fromStreamD $ D.rollingMap f $ toStreamD m
2297-- | Like 'rollingMap' but with an effectful map function.
2299-- /Internal/
2301{-# INLINE rollingMapM #-}
2302rollingMapM :: (IsStream t, Monad m) => (a -> a -> m b) -> t m a -> t m b
2303rollingMapM f m = fromStreamD $ D.rollingMapM f $ toStreamD m
2305------------------------------------------------------------------------------
2306-- Transformation by Filtering
2307------------------------------------------------------------------------------
2309-- | Include only those elements that pass a predicate.
2311-- @since 0.1.0
2312{-# INLINE filter #-}
2313#if __GLASGOW_HASKELL__ != 802
2314-- GHC 8.2.2 crashes with this code, when used with "stack"
2315filter :: (IsStream t, Monad m) => (a -> Bool) -> t m a -> t m a
2316filter p m = fromStreamS $ S.filter p $ toStreamS m
2317#else
2318filter :: IsStream t => (a -> Bool) -> t m a -> t m a
2319filter = K.filter
2320#endif
2322-- | Same as 'filter' but with a monadic predicate.
2324-- @since 0.4.0
2325{-# INLINE filterM #-}
2326filterM :: (IsStream t, Monad m) => (a -> m Bool) -> t m a -> t m a
2327filterM p m = fromStreamD $ D.filterM p $ toStreamD m
2329-- | Drop repeated elements that are adjacent to each other.
2331-- @since 0.6.0
2332{-# INLINE uniq #-}
2333uniq :: (Eq a, IsStream t, Monad m) => t m a -> t m a
2334uniq = fromStreamD . D.uniq . toStreamD
2336-- | Ensures that all the elements of the stream are identical and then returns
2337-- that unique element.
2339-- @since 0.6.0
2340{-# INLINE the #-}
2341the :: (Eq a, Monad m) => SerialT m a -> m (Maybe a)
2342the m = S.the (toStreamS m)
2344-- | Take first 'n' elements from the stream and discard the rest.
2346-- @since 0.1.0
2347{-# INLINE take #-}
2348take :: (IsStream t, Monad m) => Int -> t m a -> t m a
2349take n m = fromStreamS $ S.take n $ toStreamS
2350 (maxYields (Just (fromIntegral n)) m)
2352-- | End the stream as soon as the predicate fails on an element.
2354-- @since 0.1.0
2355{-# INLINE takeWhile #-}
2356takeWhile :: (IsStream t, Monad m) => (a -> Bool) -> t m a -> t m a
2357takeWhile p m = fromStreamS $ S.takeWhile p $ toStreamS m
2359-- | Same as 'takeWhile' but with a monadic predicate.
2361-- @since 0.4.0
2362{-# INLINE takeWhileM #-}
2363takeWhileM :: (IsStream t, Monad m) => (a -> m Bool) -> t m a -> t m a
2364takeWhileM p m = fromStreamD $ D.takeWhileM p $ toStreamD m
2366-- | @takeByTime duration@ yields stream elements upto specified time
2367-- @duration@. The duration starts when the stream is evaluated for the first
2368-- time, before the first element is yielded. The time duration is checked
2369-- before generating each element, if the duration has expired the stream
2370-- stops.
2372-- The total time taken in executing the stream is guaranteed to be /at least/
2373-- @duration@, however, because the duration is checked before generating an
2374-- element, the upper bound is indeterminate and depends on the time taken in
2375-- generating and processing the last element.
2377-- No element is yielded if the duration is zero. At least one element is
2378-- yielded if the duration is non-zero.
2380-- /Internal/
2382{-# INLINE takeByTime #-}
2383takeByTime ::(MonadIO m, IsStream t, TimeUnit64 d) => d -> t m a -> t m a
2384takeByTime d = fromStreamD . D.takeByTime d . toStreamD
2386-- | Discard first 'n' elements from the stream and take the rest.
2388-- @since 0.1.0
2389{-# INLINE drop #-}
2390drop :: (IsStream t, Monad m) => Int -> t m a -> t m a
2391drop n m = fromStreamS $ S.drop n $ toStreamS m
2393-- | Drop elements in the stream as long as the predicate succeeds and then
2394-- take the rest of the stream.
2396-- @since 0.1.0
2397{-# INLINE dropWhile #-}
2398dropWhile :: (IsStream t, Monad m) => (a -> Bool) -> t m a -> t m a
2399dropWhile p m = fromStreamS $ S.dropWhile p $ toStreamS m
2401-- | Same as 'dropWhile' but with a monadic predicate.
2403-- @since 0.4.0
2404{-# INLINE dropWhileM #-}
2405dropWhileM :: (IsStream t, Monad m) => (a -> m Bool) -> t m a -> t m a
2406dropWhileM p m = fromStreamD $ D.dropWhileM p $ toStreamD m
2408-- | @dropByTime duration@ drops stream elements until specified @duration@ has
2409-- passed. The duration begins when the stream is evaluated for the first
2410-- time. The time duration is checked /after/ generating a stream element, the
2411-- element is yielded if the duration has expired otherwise it is dropped.
2413-- The time elapsed before starting to generate the first element is /at most/
2414-- @duration@, however, because the duration expiry is checked after the
2415-- element is generated, the lower bound is indeterminate and depends on the
2416-- time taken in generating an element.
2418-- All elements are yielded if the duration is zero.
2420-- /Internal/
2422{-# INLINE dropByTime #-}
2423dropByTime ::(MonadIO m, IsStream t, TimeUnit64 d) => d -> t m a -> t m a
2424dropByTime d = fromStreamD . D.dropByTime d . toStreamD
2426------------------------------------------------------------------------------
2427-- Transformation by Mapping
2428------------------------------------------------------------------------------
2430-- |
2431-- @
2432-- mapM f = sequence . map f
2433-- @
2435-- Apply a monadic function to each element of the stream and replace it with
2436-- the output of the resulting action.
2438-- @
2439-- > drain $ S.mapM putStr $ S.fromList ["a", "b", "c"]
2440-- abc
2442-- drain $ S.replicateM 10 (return 1)
2443-- & (serially . S.mapM (\\x -> threadDelay 1000000 >> print x))
2445-- drain $ S.replicateM 10 (return 1)
2446-- & (asyncly . S.mapM (\\x -> threadDelay 1000000 >> print x))
2447-- @
2449-- /Concurrent (do not use with 'parallely' on infinite streams)/
2451-- @since 0.1.0
2452{-# INLINE_EARLY mapM #-}
2453mapM :: (IsStream t, MonadAsync m) => (a -> m b) -> t m a -> t m b
2454mapM = K.mapM
2456{-# RULES "mapM serial" mapM = mapMSerial #-}
2457{-# INLINE mapMSerial #-}
2458mapMSerial :: Monad m => (a -> m b) -> SerialT m a -> SerialT m b
2459mapMSerial = Serial.mapM
2461-- |
2462-- @
2463-- sequence = mapM id
2464-- @
2466-- Replace the elements of a stream of monadic actions with the outputs of
2467-- those actions.
2469-- @
2470-- > drain $ S.sequence $ S.fromList [putStr "a", putStr "b", putStrLn "c"]
2471-- abc
2473-- drain $ S.replicateM 10 (return $ threadDelay 1000000 >> print 1)
2474-- & (serially . S.sequence)
2476-- drain $ S.replicateM 10 (return $ threadDelay 1000000 >> print 1)
2477-- & (asyncly . S.sequence)
2478-- @
2480-- /Concurrent (do not use with 'parallely' on infinite streams)/
2482-- @since 0.1.0
2483{-# INLINE sequence #-}
2484sequence :: (IsStream t, MonadAsync m) => t m (m a) -> t m a
2485sequence m = fromStreamS $ S.sequence (toStreamS m)
2487-- $smapM_Notes
2489-- The stateful step function can be simplified to @(s -> a -> m b)@ to provide
2490-- a read-only environment. However, that would just be 'mapM'.
2492-- The initial action could be @m (s, Maybe b)@, and we can also add a final
2493-- action @s -> m (Maybe b)@. This can be used to get pre/post scan like
2494-- functionality and also to flush the state in the end like scanlMAfter'.
2495-- We can also use it along with a fusible version of bracket to get
2496-- scanlMAfter' like functionality. See issue #677.
2498-- This can be further generalized to a type similar to Fold/Parser, giving it
2499-- filtering and parsing capability as well (this is in fact equivalent to
2500-- parseMany):
2502-- smapM :: (s -> a -> m (Step s b)) -> m s -> t m a -> t m b
2505-- | A stateful 'mapM', equivalent to a left scan, more like mapAccumL.
2506-- Hopefully, this is a better alternative to @scan@. Separation of state from
2507-- the output makes it easier to think in terms of a shared state, and also
2508-- makes it easier to keep the state fully strict and the output lazy.
2510-- See also: 'scanlM''
2512-- /Internal/
2514{-# INLINE smapM #-}
2515smapM :: (IsStream t, Monad m) =>
2516 (s -> a -> m (s, b))
2517 -> m s
2518 -> t m a
2519 -> t m b
2520smapM step initial stream =
2521 -- XXX implement this directly instead of using scanlM'
2522 -- Once we have scanlM' with monadic initial we can use this code
2523 -- let r = scanlM'
2524 -- (\(s, _) a -> step s a)
2525 -- (fmap (,undefined) initial)
2526 -- stream
2527 let r = concatMap
2528 (\s0 -> scanlM' (\(s, _) a -> step s a) (s0, undefined) stream)
2529 (yieldM initial)
2530 in Serial.map snd r
2532------------------------------------------------------------------------------
2533-- Maybe Streams
2534------------------------------------------------------------------------------
2536-- | Map a 'Maybe' returning function to a stream, filter out the 'Nothing'
2537-- elements, and return a stream of values extracted from 'Just'.
2539-- Equivalent to:
2541-- @
2542-- mapMaybe f = S.map 'fromJust' . S.filter 'isJust' . S.map f
2543-- @
2545-- @since 0.3.0
2546{-# INLINE mapMaybe #-}
2547mapMaybe :: (IsStream t, Monad m) => (a -> Maybe b) -> t m a -> t m b
2548mapMaybe f m = fromStreamS $ S.mapMaybe f $ toStreamS m
2550-- | Like 'mapMaybe' but maps a monadic function.
2552-- Equivalent to:
2554-- @
2555-- mapMaybeM f = S.map 'fromJust' . S.filter 'isJust' . S.mapM f
2556-- @
2558-- /Concurrent (do not use with 'parallely' on infinite streams)/
2560-- @since 0.3.0
2561{-# INLINE_EARLY mapMaybeM #-}
2562mapMaybeM :: (IsStream t, MonadAsync m, Functor (t m))
2563 => (a -> m (Maybe b)) -> t m a -> t m b
2564mapMaybeM f = fmap fromJust . filter isJust . K.mapM f
2566{-# RULES "mapMaybeM serial" mapMaybeM = mapMaybeMSerial #-}
2567{-# INLINE mapMaybeMSerial #-}
2568mapMaybeMSerial :: Monad m => (a -> m (Maybe b)) -> SerialT m a -> SerialT m b
2569mapMaybeMSerial f m = fromStreamD $ D.mapMaybeM f $ toStreamD m
2571-- | In a stream of 'Maybe's, discard 'Nothing's and unwrap 'Just's.
2573-- /Internal/
2575catMaybes :: (IsStream t, Monad m, Functor (t m)) => t m (Maybe a) -> t m a
2576catMaybes = fmap fromJust . filter isJust
2578------------------------------------------------------------------------------
2579-- Transformation by Reordering
2580------------------------------------------------------------------------------
2582-- XXX Use a compact region list to temporarily store the list, in both reverse
2583-- as well as in reverse'.
2585-- /Note:/ 'reverse'' is much faster than this, use that when performance
2586-- matters.
2588-- > reverse = S.foldlT (flip S.cons) S.nil
2590-- | Returns the elements of the stream in reverse order. The stream must be
2591-- finite. Note that this necessarily buffers the entire stream in memory.
2593-- /Since 0.7.0 (Monad m constraint)/
2595-- /Since: 0.1.1/
2596{-# INLINE reverse #-}
2597reverse :: (IsStream t, Monad m) => t m a -> t m a
2598reverse s = fromStreamS $ S.reverse $ toStreamS s
2600-- | Like 'reverse' but several times faster, requires a 'Storable' instance.
2602-- /Internal/
2603{-# INLINE reverse' #-}
2604reverse' :: (IsStream t, MonadIO m, Storable a) => t m a -> t m a
2605reverse' s = fromStreamD $ D.reverse' $ toStreamD s
2607------------------------------------------------------------------------------
2608-- Transformation by Inserting
2609------------------------------------------------------------------------------
2611-- intersperseM = intersperseBySpan 1
2613-- | Insert an effect and its output before consuming an element of a stream
2614-- except the first one.
2616-- @
2617-- >>> S.toList $ S.trace putChar $ S.intersperseM (putChar '.' >> return ',') $ S.fromList "hello"
2618-- > h.,e.,l.,l.,o"h,e,l,l,o"
2619-- @
2621-- @since 0.5.0
2622{-# INLINE intersperseM #-}
2623intersperseM :: (IsStream t, MonadAsync m) => m a -> t m a -> t m a
2624intersperseM m = fromStreamS . S.intersperseM m . toStreamS
2626-- | Insert a side effect before consuming an element of a stream except the
2627-- first one.
2629-- @
2630-- >>> S.drain $ S.trace putChar $ S.intersperseM_ (putChar '.') $ S.fromList "hello"
2631-- > h.e.l.l.o
2632-- @
2634-- /Internal/
2635{-# INLINE intersperseM_ #-}
2636intersperseM_ :: (IsStream t, Monad m) => m b -> t m a -> t m a
2637intersperseM_ m = fromStreamD . D.intersperseM_ m . toStreamD
2639-- | Insert a pure value between successive elements of a stream.
2641-- @
2642-- > S.toList $ S.intersperse ',' $ S.fromList "hello"
2643-- "h,e,l,l,o"
2644-- @
2646-- @since 0.7.0
2647{-# INLINE intersperse #-}
2648intersperse :: (IsStream t, MonadAsync m) => a -> t m a -> t m a
2649intersperse a = fromStreamS . S.intersperse a . toStreamS
2651-- | Insert an effect and its output after consuming an element of a stream.
2653-- @
2654-- >>> S.toList $ S.trace putChar $ S.intersperseSuffix (putChar '.' >> return ',') $ S.fromList "hello"
2655-- > h.,e.,l.,l.,o.,"h,e,l,l,o,"
2656-- @
2658-- /Internal/
2659{-# INLINE intersperseSuffix #-}
2660intersperseSuffix :: (IsStream t, MonadAsync m) => m a -> t m a -> t m a
2661intersperseSuffix m = fromStreamD . D.intersperseSuffix m . toStreamD
2663-- | Insert a side effect after consuming an element of a stream.
2665-- @
2666-- > S.mapM_ putChar $ S.intersperseSuffix_ (threadDelay 1000000) $ S.fromList "hello"
2667-- @
2669-- /Internal/
2671{-# INLINE intersperseSuffix_ #-}
2672intersperseSuffix_ :: (IsStream t, Monad m) => m b -> t m a -> t m a
2673intersperseSuffix_ m = fromStreamD . D.intersperseSuffix_ m . toStreamD
2675-- | Insert a side effect before consuming an element of a stream.
2677-- @
2678-- >>> S.toList $ S.trace putChar $ S.interspersePrefix_ (putChar '.' >> return ',') $ S.fromList "hello"
2679-- > .h.e.l.l.o"hello"
2680-- @
2682-- See also: 'trace_'
2684-- /Concurrent/
2686-- /Internal/
2688{-# INLINE interspersePrefix_ #-}
2689interspersePrefix_ :: (IsStream t, MonadAsync m) => m b -> t m a -> t m a
2690interspersePrefix_ m = mapM (\x -> void m >> return x)
2692-- Note: delay must be serial.
2694-- | Introduce a delay of specified seconds before consuming an element of the
2695-- stream except the first one.
2697-- @
2698-- >>> S.mapM_ print $ S.timestamped $ S.delay 1 $ S.enumerateFromTo 1 3
2699-- > (AbsTime (TimeSpec {sec = 2502706, nsec = 751137000}),1)
2700-- > (AbsTime (TimeSpec {sec = 2502707, nsec = 743535000}),2)
2701-- > (AbsTime (TimeSpec {sec = 2502708, nsec = 749758000}),3)
2702-- @
2704-- /Internal/
2706{-# INLINE delay #-}
2707delay :: (IsStream t, MonadIO m) => Double -> t m a -> t m a
2708delay n = intersperseM_ $ liftIO $ threadDelay $ round $ n * 1000000
2710-- Note: delay must be serial.
2712-- | Introduce a delay of specified seconds after consuming an element of a
2713-- stream.
2715-- @
2716-- >>> S.mapM_ print $ S.timestamped $ S.delayPost 1 $ S.enumerateFromTo 1 3
2717-- > (AbsTime (TimeSpec {sec = 2502826, nsec = 119030000}),1)
2718-- > (AbsTime (TimeSpec {sec = 2502827, nsec = 111393000}),2)
2719-- > (AbsTime (TimeSpec {sec = 2502828, nsec = 112221000}),3)
2720-- @
2722-- /Internal/
2724{-# INLINE delayPost #-}
2725delayPost :: (IsStream t, MonadIO m) => Double -> t m a -> t m a
2726delayPost n = intersperseSuffix_ $ liftIO $ threadDelay $ round $ n * 1000000
2728-- Note: delay must be serial, that's why 'trace_' is used.
2730-- | Introduce a delay of specified seconds before consuming an element of a
2731-- stream.
2733-- @
2734-- >>> S.mapM_ print $ S.timestamped $ S.delayPre 1 $ S.enumerateFromTo 1 3
2735-- > (AbsTime (TimeSpec {sec = 2502207, nsec = 533177000}),1)
2736-- > (AbsTime (TimeSpec {sec = 2502208, nsec = 530859000}),2)
2737-- > (AbsTime (TimeSpec {sec = 2502209, nsec = 531619000}),3)
2738-- @
2740-- /Internal/
2742{-# INLINE delayPre #-}
2743delayPre :: (IsStream t, MonadIO m) => Double -> t m a -> t m a
2744delayPre n = trace_ $ liftIO $ threadDelay $ round $ n * 1000000
2746-- | Like 'intersperseSuffix' but intersperses an effectful action into the
2747-- input stream after every @n@ elements and after the last element.
2749-- @
2750-- > S.toList $ S.intersperseSuffixBySpan 2 (return ',') $ S.fromList "hello"
2751-- "he,ll,o,"
2752-- @
2754-- /Internal/
2756{-# INLINE intersperseSuffixBySpan #-}
2757intersperseSuffixBySpan :: (IsStream t, MonadAsync m)
2758 => Int -> m a -> t m a -> t m a
2759intersperseSuffixBySpan n eff =
2760 fromStreamD . D.intersperseSuffixBySpan n eff . toStreamD
2763-- | Intersperse a monadic action into the input stream after every @n@
2764-- elements.
2766-- @
2767-- > S.toList $ S.intersperseBySpan 2 (return ',') $ S.fromList "hello"
2768-- "he,ll,o"
2769-- @
2771-- @since 0.7.0
2772{-# INLINE intersperseBySpan #-}
2773intersperseBySpan :: IsStream t => Int -> m a -> t m a -> t m a
2774intersperseBySpan _n _f _xs = undefined
2777-- | Intersperse a monadic action into the input stream after every @n@
2778-- seconds.
2780-- @
2781-- > S.drain $ S.interjectSuffix 1 (putChar ',') $ S.mapM (\\x -> threadDelay 1000000 >> putChar x) $ S.fromList "hello"
2782-- "h,e,l,l,o"
2783-- @
2785-- /Internal/
2786{-# INLINE interjectSuffix #-}
2787interjectSuffix
2788 :: (IsStream t, MonadAsync m)
2789 => Double -> m a -> t m a -> t m a
2790interjectSuffix n f xs = xs `Par.parallelFst` repeatM timed
2791 where timed = liftIO (threadDelay (round $ n * 1000000)) >> f
2793-- | @insertBy cmp elem stream@ inserts @elem@ before the first element in
2794-- @stream@ that is less than @elem@ when compared using @cmp@.
2796-- @
2797-- insertBy cmp x = 'mergeBy' cmp ('yield' x)
2798-- @
2800-- @
2801-- > S.toList $ S.insertBy compare 2 $ S.fromList [1,3,5]
2802-- [1,2,3,5]
2803-- @
2805-- @since 0.6.0
2806{-# INLINE insertBy #-}
2807insertBy ::
2808 (IsStream t, Monad m) => (a -> a -> Ordering) -> a -> t m a -> t m a
2809insertBy cmp x m = fromStreamS $ S.insertBy cmp x (toStreamS m)
2811------------------------------------------------------------------------------
2812-- Deleting
2813------------------------------------------------------------------------------
2815-- | Deletes the first occurrence of the element in the stream that satisfies
2816-- the given equality predicate.
2818-- @
2819-- > S.toList $ S.deleteBy (==) 3 $ S.fromList [1,3,3,5]
2820-- [1,3,5]
2821-- @
2823-- @since 0.6.0
2824{-# INLINE deleteBy #-}
2825deleteBy :: (IsStream t, Monad m) => (a -> a -> Bool) -> a -> t m a -> t m a
2826deleteBy cmp x m = fromStreamS $ S.deleteBy cmp x (toStreamS m)
2828------------------------------------------------------------------------------
2829-- Zipping
2830------------------------------------------------------------------------------
2832-- |
2833-- > indexed = S.postscanl' (\(i, _) x -> (i + 1, x)) (-1,undefined)
2834-- > indexed = S.zipWith (,) (S.enumerateFrom 0)
2836-- Pair each element in a stream with its index, starting from index 0.
2838-- @
2839-- > S.toList $ S.indexed $ S.fromList "hello"
2840-- [(0,'h'),(1,'e'),(2,'l'),(3,'l'),(4,'o')]
2841-- @
2843-- @since 0.6.0
2844{-# INLINE indexed #-}
2845indexed :: (IsStream t, Monad m) => t m a -> t m (Int, a)
2846indexed = fromStreamD . D.indexed . toStreamD
2848-- |
2849-- > indexedR n = S.postscanl' (\(i, _) x -> (i - 1, x)) (n + 1,undefined)
2850-- > indexedR n = S.zipWith (,) (S.enumerateFromThen n (n - 1))
2852-- Pair each element in a stream with its index, starting from the
2853-- given index @n@ and counting down.
2855-- @
2856-- > S.toList $ S.indexedR 10 $ S.fromList "hello"
2857-- [(10,'h'),(9,'e'),(8,'l'),(7,'l'),(6,'o')]
2858-- @
2860-- @since 0.6.0
2861{-# INLINE indexedR #-}
2862indexedR :: (IsStream t, Monad m) => Int -> t m a -> t m (Int, a)
2863indexedR n = fromStreamD . D.indexedR n . toStreamD
2865-- Note: The timestamp stream must be the second stream in the zip so that the
2866-- timestamp is generated after generating the stream element and not before.
2867-- If we do not do that then the following example will generate the same
2868-- timestamp for first two elements:
2870-- S.mapM_ print $ S.timestamped $ S.delay $ S.enumerateFromTo 1 3
2872-- | Pair each element in a stream with an absolute timestamp, using a clock of
2873-- specified granularity. The timestamp is generated just before the element
2874-- is consumed.
2876-- @
2877-- >>> S.mapM_ print $ S.timestampWith 0.01 $ S.delay 1 $ S.enumerateFromTo 1 3
2878-- @
2880-- /Internal/
2882{-# INLINE timestampWith #-}
2883timestampWith :: (IsStream t, MonadAsync m, Functor (t m))
2884 => Double -> t m a -> t m (AbsTime, a)
2885timestampWith g stream = Z.zipWith (flip (,)) stream (absTimesWith g)
2887-- TBD: check performance vs a custom implementation without using zipWith.
2889-- | Pair each element in a stream with an absolute timestamp, using a clock of
2890-- 10 ms granularity. The timestamp is generated just before the element is
2891-- consumed.
2893-- @
2894-- >>> S.mapM_ print $ S.timestamped $ S.delay 1 $ S.enumerateFromTo 1 3
2895-- (AbsTime (TimeSpec {sec = 2460689, nsec = 641121000}),1)
2896-- (AbsTime (TimeSpec {sec = 2460690, nsec = 639334000}),2)
2897-- (AbsTime (TimeSpec {sec = 2460691, nsec = 644479000}),3)
2898-- @
2900-- /Internal/
2902{-# INLINE timestamped #-}
2903timestamped :: (IsStream t, MonadAsync m, Functor (t m))
2904 => t m a -> t m (AbsTime, a)
2905timestamped = timestampWith 0.01
2907-- | Pair each element in a stream with relative times starting from 0, using a
2908-- clock with the specified granularity. The time is measured just before the
2909-- element is consumed.
2911-- @
2912-- >>> S.mapM_ print $ S.timeIndexWith 0.01 $ S.delay 1 $ S.enumerateFromTo 1 3
2913-- @
2915-- /Internal/
2917{-# INLINE timeIndexWith #-}
2918timeIndexWith :: (IsStream t, MonadAsync m, Functor (t m))
2919 => Double -> t m a -> t m (RelTime64, a)
2920timeIndexWith g stream = Z.zipWith (flip (,)) stream (relTimesWith g)
2922-- | Pair each element in a stream with relative times starting from 0, using a
2923-- 10 ms granularity clock. The time is measured just before the element is
2924-- consumed.
2926-- @
2927-- >>> S.mapM_ print $ S.timeIndexed $ S.delay 1 $ S.enumerateFromTo 1 3
2928-- (RelTime64 (NanoSecond64 0),1)
2929-- (RelTime64 (NanoSecond64 996239000),2)
2930-- (RelTime64 (NanoSecond64 1996712000),3)
2931-- @
2933-- /Internal/
2935{-# INLINE timeIndexed #-}
2936timeIndexed :: (IsStream t, MonadAsync m, Functor (t m))
2937 => t m a -> t m (RelTime64, a)
2938timeIndexed = timeIndexWith 0.01
2940------------------------------------------------------------------------------
2941-- Comparison
2942------------------------------------------------------------------------------
2944-- | Compare two streams for equality using an equality function.
2946-- @since 0.6.0
2947{-# INLINABLE eqBy #-}
2948eqBy :: (IsStream t, Monad m) => (a -> b -> Bool) -> t m a -> t m b -> m Bool
2949eqBy = P.eqBy
2951-- | Compare two streams lexicographically using a comparison function.
2953-- @since 0.6.0
2954{-# INLINABLE cmpBy #-}
2955cmpBy
2956 :: (IsStream t, Monad m)
2957 => (a -> b -> Ordering) -> t m a -> t m b -> m Ordering
2958cmpBy = P.cmpBy
2960------------------------------------------------------------------------------
2961-- Merge
2962------------------------------------------------------------------------------
2964-- | Merge two streams using a comparison function. The head elements of both
2965-- the streams are compared and the smaller of the two elements is emitted, if
2966-- both elements are equal then the element from the first stream is used
2967-- first.
2969-- If the streams are sorted in ascending order, the resulting stream would
2970-- also remain sorted in ascending order.
2972-- @
2973-- > S.toList $ S.mergeBy compare (S.fromList [1,3,5]) (S.fromList [2,4,6,8])
2974-- [1,2,3,4,5,6,8]
2975-- @
2977-- @since 0.6.0
2978{-# INLINABLE mergeBy #-}
2979mergeBy ::
2980 (IsStream t, Monad m) => (a -> a -> Ordering) -> t m a -> t m a -> t m a
2981mergeBy f m1 m2 = fromStreamS $ S.mergeBy f (toStreamS m1) (toStreamS m2)
2983-- | Like 'mergeBy' but with a monadic comparison function.
2985-- Merge two streams randomly:
2987-- @
2988-- > randomly _ _ = randomIO >>= \x -> return $ if x then LT else GT
2989-- > S.toList $ S.mergeByM randomly (S.fromList [1,1,1,1]) (S.fromList [2,2,2,2])
2990-- [2,1,2,2,2,1,1,1]
2991-- @
2993-- Merge two streams in a proportion of 2:1:
2995-- @
2996-- proportionately m n = do
2997-- ref <- newIORef $ cycle $ concat [replicate m LT, replicate n GT]
2998-- return $ \\_ _ -> do
2999-- r <- readIORef ref
3000-- writeIORef ref $ tail r
3001-- return $ head r
3003-- main = do
3004-- f <- proportionately 2 1
3005-- xs <- S.toList $ S.mergeByM f (S.fromList [1,1,1,1,1,1]) (S.fromList [2,2,2])
3006-- print xs
3007-- @
3008-- @
3009-- [1,1,2,1,1,2,1,1,2]
3010-- @
3012-- @since 0.6.0
3013{-# INLINABLE mergeByM #-}
3014mergeByM
3015 :: (IsStream t, Monad m)
3016 => (a -> a -> m Ordering) -> t m a -> t m a -> t m a
3017mergeByM f m1 m2 = fromStreamS $ S.mergeByM f (toStreamS m1) (toStreamS m2)
3020-- | Like 'mergeByM' but stops merging as soon as any of the two streams stops.
3021{-# INLINABLE mergeEndByAny #-}
3022mergeEndByAny
3023 :: (IsStream t, Monad m)
3024 => (a -> a -> m Ordering) -> t m a -> t m a -> t m a
3025mergeEndByAny f m1 m2 = fromStreamD $
3026 D.mergeEndByAny f (toStreamD m1) (toStreamD m2)
3028-- Like 'mergeByM' but stops merging as soon as the first stream stops.
3029{-# INLINABLE mergeEndByFirst #-}
3030mergeEndByFirst
3031 :: (IsStream t, Monad m)
3032 => (a -> a -> m Ordering) -> t m a -> t m a -> t m a
3033mergeEndByFirst f m1 m2 = fromStreamS $
3034 D.mergeEndByFirst f (toStreamD m1) (toStreamD m2)
3037-- Holding this back for now, we may want to use the name "merge" differently
3039-- | Same as @'mergeBy' 'compare'@.
3041-- @
3042-- > S.toList $ S.merge (S.fromList [1,3,5]) (S.fromList [2,4,6,8])
3043-- [1,2,3,4,5,6,8]
3044-- @
3046-- @since 0.6.0
3047{-# INLINABLE merge #-}
3048merge ::
3049 (IsStream t, Monad m, Ord a) => t m a -> t m a -> t m a
3050merge = mergeBy compare
3053-- | Like 'mergeBy' but merges concurrently (i.e. both the elements being
3054-- merged are generated concurrently).
3056-- @since 0.6.0
3057{-# INLINE mergeAsyncBy #-}
3058mergeAsyncBy :: (IsStream t, MonadAsync m)
3059 => (a -> a -> Ordering) -> t m a -> t m a -> t m a
3060mergeAsyncBy f = mergeAsyncByM (\a b -> return $ f a b)
3062-- | Like 'mergeByM' but merges concurrently (i.e. both the elements being
3063-- merged are generated concurrently).
3065-- @since 0.6.0
3066{-# INLINE mergeAsyncByM #-}
3067mergeAsyncByM :: (IsStream t, MonadAsync m)
3068 => (a -> a -> m Ordering) -> t m a -> t m a -> t m a
3069mergeAsyncByM f m1 m2 = fromStreamD $
3070 D.mergeByM f (D.mkParallelD $ toStreamD m1) (D.mkParallelD $ toStreamD m2)
3072------------------------------------------------------------------------------
3073-- Flattening Lists
3074------------------------------------------------------------------------------
3076-- | @concatMapWith merge map stream@ is a two dimensional looping combinator.
3077-- The first argument specifies a merge or concat function that is used to
3078-- merge the streams generated by applying the second argument i.e. the @map@
3079-- function to each element of the input stream. The concat function could be
3080-- 'serial', 'parallel', 'async', 'ahead' or any other zip or merge function
3081-- and the second argument could be any stream generation function using a
3082-- seed.
3084-- /Compare 'foldMapWith'/
3086-- @since 0.7.0
3087{-# INLINE concatMapWith #-}
3088concatMapWith
3089 :: IsStream t
3090 => (t m b -> t m b -> t m b)
3091 -> (a -> t m b)
3092 -> t m a
3093 -> t m b
3094concatMapWith = K.concatMapBy
3096-- | Like 'concatMapWith' but carries a state which can be used to share
3097-- information across multiple steps of concat.
3099-- @
3100-- concatSmapMWith combine f initial = concatMapWith combine id . smapM f initial
3101-- @
3103-- /Internal/
3105{-# INLINE concatSmapMWith #-}
3106concatSmapMWith
3107 :: (IsStream t, Monad m)
3108 => (t m b -> t m b -> t m b)
3109 -> (s -> a -> m (s, t m b))
3110 -> m s
3111 -> t m a
3112 -> t m b
3113concatSmapMWith combine f initial = concatMapWith combine id . smapM f initial
3115-- | Map a stream producing function on each element of the stream and then
3116-- flatten the results into a single stream.
3118-- @
3119-- concatMap f = 'concat . map f'
3120-- concatMap = 'concatMapWith' 'Serial.serial'
3121-- concatMap f = 'concatMapM' (return . f)
3122-- concatMap f = 'concatUnfold' (UF.lmap f UF.fromStream)
3123-- @
3125-- @since 0.6.0
3126{-# INLINE concatMap #-}
3127concatMap ::(IsStream t, Monad m) => (a -> t m b) -> t m a -> t m b
3128concatMap f m = fromStreamD $ D.concatMap (toStreamD . f) (toStreamD m)
3130-- | Flatten a stream of streams to a single stream.
3132-- @
3133-- concat = concatMap id
3134-- @
3136-- /Internal/
3137{-# INLINE concat #-}
3138concat :: (IsStream t, Monad m) => t m (t m a) -> t m a
3139concat = concatMap id
3141-- | Append the outputs of two streams, yielding all the elements from the
3142-- first stream and then yielding all the elements from the second stream.
3144-- IMPORTANT NOTE: This could be 100x faster than @serial/<>@ for appending a
3145-- few (say 100) streams because it can fuse via stream fusion. However, it
3146-- does not scale for a large number of streams (say 1000s) and becomes
3147-- qudartically slow. Therefore use this for custom appending of a few streams
3148-- but use 'concatMap' or 'concatMapWith serial' for appending @n@ streams or
3149-- infinite containers of streams.
3151-- /Internal/
3152{-# INLINE append #-}
3153append ::(IsStream t, Monad m) => t m b -> t m b -> t m b
3154append m1 m2 = fromStreamD $ D.append (toStreamD m1) (toStreamD m2)
3156-- XXX Same as 'wSerial'. We should perhaps rename wSerial to interleave.
3157-- XXX Document the interleaving behavior of side effects in all the
3158-- interleaving combinators.
3159-- XXX Write time-domain equivalents of these. In the time domain we can
3160-- interleave two streams such that the value of second stream is always taken
3161-- from its last value even if no new value is being yielded, like
3162-- zipWithLatest. It would be something like interleaveWithLatest.
3164-- | Interleaves the outputs of two streams, yielding elements from each stream
3165-- alternately, starting from the first stream. If any of the streams finishes
3166-- early the other stream continues alone until it too finishes.
3168-- >>> :set -XOverloadedStrings
3169-- >>> interleave "ab" ",,,," :: SerialT Identity Char
3170-- fromList "a,b,,,"
3171-- >>> interleave "abcd" ",," :: SerialT Identity Char
3172-- fromList "a,b,cd"
3174-- 'interleave' is dual to 'interleaveMin', it can be called @interleaveMax@.
3176-- Do not use at scale in concatMapWith.
3178-- /Internal/
3179{-# INLINE interleave #-}
3180interleave ::(IsStream t, Monad m) => t m b -> t m b -> t m b
3181interleave m1 m2 = fromStreamD $ D.interleave (toStreamD m1) (toStreamD m2)
3183-- | Interleaves the outputs of two streams, yielding elements from each stream
3184-- alternately, starting from the first stream. As soon as the first stream
3185-- finishes, the output stops, discarding the remaining part of the second
3186-- stream. In this case, the last element in the resulting stream would be from
3187-- the second stream. If the second stream finishes early then the first stream
3188-- still continues to yield elements until it finishes.
3190-- >>> :set -XOverloadedStrings
3191-- >>> interleaveSuffix "abc" ",,,," :: SerialT Identity Char
3192-- fromList "a,b,c,"
3193-- >>> interleaveSuffix "abc" "," :: SerialT Identity Char
3194-- fromList "a,bc"
3196-- 'interleaveSuffix' is a dual of 'interleaveInfix'.
3198-- Do not use at scale in concatMapWith.
3200-- /Internal/
3201{-# INLINE interleaveSuffix #-}
3202interleaveSuffix ::(IsStream t, Monad m) => t m b -> t m b -> t m b
3203interleaveSuffix m1 m2 =
3204 fromStreamD $ D.interleaveSuffix (toStreamD m1) (toStreamD m2)
3206-- | Interleaves the outputs of two streams, yielding elements from each stream
3207-- alternately, starting from the first stream and ending at the first stream.
3208-- If the second stream is longer than the first, elements from the second
3209-- stream are infixed with elements from the first stream. If the first stream
3210-- is longer then it continues yielding elements even after the second stream
3211-- has finished.
3213-- >>> :set -XOverloadedStrings
3214-- >>> interleaveInfix "abc" ",,,," :: SerialT Identity Char
3215-- fromList "a,b,c"
3216-- >>> interleaveInfix "abc" "," :: SerialT Identity Char
3217-- fromList "a,bc"
3219-- 'interleaveInfix' is a dual of 'interleaveSuffix'.
3221-- Do not use at scale in concatMapWith.
3223-- /Internal/
3224{-# INLINE interleaveInfix #-}
3225interleaveInfix ::(IsStream t, Monad m) => t m b -> t m b -> t m b
3226interleaveInfix m1 m2 =
3227 fromStreamD $ D.interleaveInfix (toStreamD m1) (toStreamD m2)
3229-- | Interleaves the outputs of two streams, yielding elements from each stream
3230-- alternately, starting from the first stream. The output stops as soon as any
3231-- of the two streams finishes, discarding the remaining part of the other
3232-- stream. The last element of the resulting stream would be from the longer
3233-- stream.
3235-- >>> :set -XOverloadedStrings
3236-- >>> interleaveMin "ab" ",,,," :: SerialT Identity Char
3237-- fromList "a,b,"
3238-- >>> interleaveMin "abcd" ",," :: SerialT Identity Char
3239-- fromList "a,b,c"
3241-- 'interleaveMin' is dual to 'interleave'.
3243-- Do not use at scale in concatMapWith.
3245-- /Internal/
3246{-# INLINE interleaveMin #-}
3247interleaveMin ::(IsStream t, Monad m) => t m b -> t m b -> t m b
3248interleaveMin m1 m2 = fromStreamD $ D.interleaveMin (toStreamD m1) (toStreamD m2)
3250-- | Schedule the execution of two streams in a fair round-robin manner,
3251-- executing each stream once, alternately. Execution of a stream may not
3252-- necessarily result in an output, a stream may chose to @Skip@ producing an
3253-- element until later giving the other stream a chance to run. Therefore, this
3254-- combinator fairly interleaves the execution of two streams rather than
3255-- fairly interleaving the output of the two streams. This can be useful in
3256-- co-operative multitasking without using explicit threads. This can be used
3257-- as an alternative to `async`.
3259-- Do not use at scale in concatMapWith.
3261-- /Internal/
3262{-# INLINE roundrobin #-}
3263roundrobin ::(IsStream t, Monad m) => t m b -> t m b -> t m b
3264roundrobin m1 m2 = fromStreamD $ D.roundRobin (toStreamD m1) (toStreamD m2)
3266-- | Map a stream producing monadic function on each element of the stream
3267-- and then flatten the results into a single stream. Since the stream
3268-- generation function is monadic, unlike 'concatMap', it can produce an
3269-- effect at the beginning of each iteration of the inner loop.
3271-- @since 0.6.0
3272{-# INLINE concatMapM #-}
3273concatMapM :: (IsStream t, Monad m) => (a -> m (t m b)) -> t m a -> t m b
3274concatMapM f m = fromStreamD $ D.concatMapM (fmap toStreamD . f) (toStreamD m)
3276-- | Given a stream value in the underlying monad, lift and join the underlying
3277-- monad with the stream monad.
3279-- @
3280-- concatM = concat . yieldM
3281-- concatM = concat . lift -- requires @(MonadTrans t)@
3282-- concatM = join . lift -- requires @(MonadTrans t@, @Monad (t m))@
3283-- @
3285-- See also: 'concat', 'sequence'
3287-- /Internal/
3289{-# INLINE concatM #-}
3290concatM :: (IsStream t, Monad m) => m (t m a) -> t m a
3291concatM generator = concatMapM (\() -> generator) (yield ())
3293-- | Like 'concatMap' but uses an 'Unfold' for stream generation. Unlike
3294-- 'concatMap' this can fuse the 'Unfold' code with the inner loop and
3295-- therefore provide many times better performance.
3297-- @since 0.7.0
3298{-# INLINE concatUnfold #-}
3299concatUnfold ::(IsStream t, Monad m) => Unfold m a b -> t m a -> t m b
3300concatUnfold u m = fromStreamD $ D.concatMapU u (toStreamD m)
3302-- | Like 'concatUnfold' but interleaves the streams in the same way as
3303-- 'interleave' behaves instead of appending them.
3305-- /Internal/
3306{-# INLINE concatUnfoldInterleave #-}
3307concatUnfoldInterleave ::(IsStream t, Monad m)
3308 => Unfold m a b -> t m a -> t m b
3309concatUnfoldInterleave u m =
3310 fromStreamD $ D.concatUnfoldInterleave u (toStreamD m)
3312-- | Like 'concatUnfold' but executes the streams in the same way as
3313-- 'roundrobin'.
3315-- /Internal/
3316{-# INLINE concatUnfoldRoundrobin #-}
3317concatUnfoldRoundrobin ::(IsStream t, Monad m)
3318 => Unfold m a b -> t m a -> t m b
3319concatUnfoldRoundrobin u m =
3320 fromStreamD $ D.concatUnfoldRoundrobin u (toStreamD m)
3322-- XXX we can swap the order of arguments to gintercalate so that the
3323-- definition of concatUnfold becomes simpler? The first stream should be
3324-- infixed inside the second one. However, if we change the order in
3325-- "interleave" as well similarly, then that will make it a bit unintuitive.
3327-- > concatUnfold unf str =
3328-- > gintercalate unf str (UF.nilM (\_ -> return ())) (repeat ())
3330-- | 'interleaveInfix' followed by unfold and concat.
3332-- /Internal/
3333{-# INLINE gintercalate #-}
3334gintercalate
3335 :: (IsStream t, Monad m)
3336 => Unfold m a c -> t m a -> Unfold m b c -> t m b -> t m c
3337gintercalate unf1 str1 unf2 str2 =
3338 D.fromStreamD $ D.gintercalate
3339 unf1 (D.toStreamD str1)
3340 unf2 (D.toStreamD str2)
3342-- XXX The order of arguments in "intercalate" is consistent with the list
3343-- intercalate but inconsistent with gintercalate and other stream interleaving
3344-- combinators. We can change the order of the arguments in other combinators
3345-- but then 'interleave' combinator may become a bit unintuitive because we
3346-- will be starting with the second stream.
3348-- > intercalate seed unf str = gintercalate unf str unf (repeatM seed)
3349-- > intercalate a unf str = concatUnfold unf $ intersperse a str
3351-- | 'intersperse' followed by unfold and concat.
3353-- > unwords = intercalate " " UF.fromList
3355-- >>> intercalate " " UF.fromList ["abc", "def", "ghi"]
3356-- > "abc def ghi"
3358-- /Internal/
3359{-# INLINE intercalate #-}
3360intercalate :: (IsStream t, Monad m)
3361 => b -> Unfold m b c -> t m b -> t m c
3362intercalate seed unf str = D.fromStreamD $
3363 D.concatMapU unf $ D.intersperse seed (toStreamD str)
3365-- > interpose x unf str = gintercalate unf str UF.identity (repeat x)
3367-- | Unfold the elements of a stream, intersperse the given element between the
3368-- unfolded streams and then concat them into a single stream.
3370-- > unwords = S.interpose ' '
3372-- /Internal/
3373{-# INLINE interpose #-}
3374interpose :: (IsStream t, Monad m)
3375 => c -> Unfold m b c -> t m b -> t m c
3376interpose x unf str =
3377 D.fromStreamD $ D.interpose (return x) unf (D.toStreamD str)
3379-- | 'interleaveSuffix' followed by unfold and concat.
3381-- /Internal/
3382{-# INLINE gintercalateSuffix #-}
3383gintercalateSuffix
3384 :: (IsStream t, Monad m)
3385 => Unfold m a c -> t m a -> Unfold m b c -> t m b -> t m c
3386gintercalateSuffix unf1 str1 unf2 str2 =
3387 D.fromStreamD $ D.gintercalateSuffix
3388 unf1 (D.toStreamD str1)
3389 unf2 (D.toStreamD str2)
3391-- > intercalateSuffix seed unf str = gintercalateSuffix unf str unf (repeatM seed)
3392-- > intercalateSuffix a unf str = concatUnfold unf $ intersperseSuffix a str
3394-- | 'intersperseSuffix' followed by unfold and concat.
3396-- > unlines = intercalateSuffix "\n" UF.fromList
3398-- >>> intercalate "\n" UF.fromList ["abc", "def", "ghi"]
3399-- > "abc\ndef\nghi\n"
3401-- /Internal/
3402{-# INLINE intercalateSuffix #-}
3403intercalateSuffix :: (IsStream t, Monad m)
3404 => b -> Unfold m b c -> t m b -> t m c
3405intercalateSuffix seed unf str = fromStreamD $ D.concatMapU unf
3406 $ D.intersperseSuffix (return seed) (D.toStreamD str)
3408-- interposeSuffix x unf str = gintercalateSuffix unf str UF.identity (repeat x)
3410-- | Unfold the elements of a stream, append the given element after each
3411-- unfolded stream and then concat them into a single stream.
3413-- > unlines = S.interposeSuffix '\n'
3415-- /Internal/
3416{-# INLINE interposeSuffix #-}
3417interposeSuffix :: (IsStream t, Monad m)
3418 => c -> Unfold m b c -> t m b -> t m c
3419interposeSuffix x unf str =
3420 D.fromStreamD $ D.interposeSuffix (return x) unf (D.toStreamD str)
3422------------------------------------------------------------------------------
3423-- Flattening Trees
3424------------------------------------------------------------------------------
3426-- | Like 'iterateM' but iterates after mapping a stream generator on the
3427-- output.
3429-- Yield an input element in the output stream, map a stream generator on it
3430-- and then do the same on the resulting stream. This can be used for a depth
3431-- first traversal of a tree like structure.
3433-- Note that 'iterateM' is a special case of 'iterateMapWith':
3435-- @
3436-- iterateM f = iterateMapWith serial (yieldM . f) . yieldM
3437-- @
3439-- It can be used to traverse a tree structure. For example, to list a
3440-- directory tree:
3442-- @
3443-- Stream.iterateMapWith Stream.serial
3444-- (either Dir.toEither (const nil))
3445-- (yield (Left "tmp"))
3446-- @
3448-- /Internal/
3450{-# INLINE iterateMapWith #-}
3451iterateMapWith
3452 :: IsStream t
3453 => (t m a -> t m a -> t m a)
3454 -> (a -> t m a)
3455 -> t m a
3456 -> t m a
3457iterateMapWith combine f = concatMapWith combine go
3458 where
3459 go x = yield x `combine` concatMapWith combine go (f x)
3462{-# INLINE iterateUnfold #-}
3463iterateUnfold :: (IsStream t, MonadAsync m)
3464 => Unfold m a a -> t m a -> t m a
3465iterateUnfold unf xs = undefined
3468------------------------------------------------------------------------------
3469-- Flattening Graphs
3470------------------------------------------------------------------------------
3472-- To traverse graphs we need a state to be carried around in the traversal.
3473-- For example, we can use a hashmap to store the visited status of nodes.
3475-- | Like 'iterateMap' but carries a state in the stream generation function.
3476-- This can be used to traverse graph like structures, we can remember the
3477-- visited nodes in the state to avoid cycles.
3479-- Note that a combination of 'iterateMap' and 'usingState' can also be used to
3480-- traverse graphs. However, this function provides a more localized state
3481-- instead of using a global state.
3483-- See also: 'mfix'
3485-- /Internal/
3487{-# INLINE iterateSmapMWith #-}
3488iterateSmapMWith
3489 :: (IsStream t, Monad m)
3490 => (t m a -> t m a -> t m a)
3491 -> (b -> a -> m (b, t m a))
3492 -> m b
3493 -> t m a
3494 -> t m a
3495iterateSmapMWith combine f initial stream =
3496 concatMap (\b -> concatMapWith combine (go b) stream) (yieldM initial)
3498 where
3500 go b a = yield a `combine` feedback b a
3502 feedback b a =
3503 concatMap
3504 (\(b1, s) -> concatMapWith combine (go b1) s)
3505 (yieldM $ f b a)
3507------------------------------------------------------------------------------
3508-- Either streams
3509------------------------------------------------------------------------------
3511-- | Discard 'Right's and unwrap 'Left's in an 'Either' stream.
3513-- /Internal/
3515lefts :: (IsStream t, Monad m, Functor (t m)) => t m (Either a b) -> t m a
3516lefts = fmap (fromLeft undefined) . filter isLeft
3518-- | Discard 'Left's and unwrap 'Right's in an 'Either' stream.
3520-- /Internal/
3522rights :: (IsStream t, Monad m, Functor (t m)) => t m (Either a b) -> t m b
3523rights = fmap (fromRight undefined) . filter isRight
3525-- | In an 'Either' stream iterate on 'Left's. This is a special case of
3526-- 'iterateMapWith':
3528-- @
3529-- iterateMapLeftsWith combine f = iterateMapWith combine (either f (const nil))
3530-- @
3532-- To traverse a directory tree:
3534-- @
3535-- iterateMapLeftsWith serial Dir.toEither (yield (Left "tmp"))
3536-- @
3538-- /Internal/
3540{-# INLINE iterateMapLeftsWith #-}
3541iterateMapLeftsWith
3542 :: IsStream t
3543 => (t m (Either a b) -> t m (Either a b) -> t m (Either a b))
3544 -> (a -> t m (Either a b))
3545 -> t m (Either a b)
3546 -> t m (Either a b)
3547iterateMapLeftsWith combine f = iterateMapWith combine (either f (const K.nil))
3549------------------------------------------------------------------------------
3550-- Parsing
3551------------------------------------------------------------------------------
3553-- Splitting operations that take a predicate and a Fold can be
3554-- expressed using parseMany. Operations like chunksOf, intervalsOf, split*,
3555-- can be expressed using parseMany when used with an appropriate Parser.
3557-- XXX We need takeGE/takeBetween to implement "some" using "many".
3559-- | Apply a 'Parser' repeatedly on a stream and emit the parsed values in the
3560-- output stream.
3562-- This is the streaming equivalent of the 'Streamly.Internal.Data.Parser.many'
3563-- parse combinator.
3565-- >>> S.toList $ S.parseMany (PR.take 2 $ PR.fromFold FL.sum) $ S.fromList [1..10]
3566-- > [3,7,11,15,19]
3568-- >>> S.toList $ S.parseMany (PR.line FL.toList) $ S.fromList "hello\nworld"
3569-- > ["hello\n","world"]
3571-- /Internal
3573{-# INLINE parseMany #-}
3574parseMany
3575 :: (IsStream t, MonadThrow m)
3576 => Parser m a b
3577 -> t m a
3578 -> t m b
3579parseMany p m =
3580 D.fromStreamD $ D.parseMany (PRK.fromParserK p) (D.toStreamD m)
3582{-# INLINE parseManyD #-}
3583parseManyD
3584 :: (IsStream t, MonadThrow m)
3585 => PRD.Parser m a b
3586 -> t m a
3587 -> t m b
3588parseManyD p m =
3589 D.fromStreamD $ D.parseMany p (D.toStreamD m)
3591-- | @parseManyTill collect test stream@ tries the parser @test@ on the input,
3592-- if @test@ fails it backtracks and tries @collect@, after @collect@ succeeds
3593-- @test@ is tried again and so on. The parser stops when @test@ succeeds. The
3594-- output of @test@ is discarded and the output of @collect@ is emitted in the
3595-- output stream. The parser fails if @collect@ fails.
3597-- /Unimplemented/
3599{-# INLINE parseManyTill #-}
3600parseManyTill ::
3601 -- (IsStream t, MonadThrow m) =>
3602 Parser m a b
3603 -> Parser m a x
3604 -> t m a
3605 -> t m b
3606parseManyTill = undefined
3608-- | Iterate a parser generating function on a stream. The initial value @b@ is
3609-- used to generate the first parser, the parser is applied on the stream and
3610-- the result is used to generate the next parser and so on.
3612-- >>> S.toList $ S.map getSum $ S.parseIterate (\b -> PR.take 2 (FL.mconcatTo b)) 0 $ S.map Sum $ S.fromList [1..10]
3613-- > [3,10,21,36,55,55]
3615-- This is the streaming equivalent of monad like sequenced application of
3616-- parsers where next parser is dependent on the previous parser.
3618-- /Internal/
3620{-# INLINE parseIterate #-}
3621parseIterate
3622 :: (IsStream t, MonadThrow m)
3623 => (b -> Parser m a b)
3624 -> b
3625 -> t m a
3626 -> t m b
3627parseIterate f i m = D.fromStreamD $
3628 D.parseIterate (PRK.fromParserK . f) i (D.toStreamD m)
3630------------------------------------------------------------------------------
3631-- Grouping/Splitting
3632------------------------------------------------------------------------------
3634------------------------------------------------------------------------------
3635-- Grouping without looking at elements
3636------------------------------------------------------------------------------
3638------------------------------------------------------------------------------
3639-- Binary APIs
3640------------------------------------------------------------------------------
3643------------------------------------------------------------------------------
3644-- N-ary APIs
3645------------------------------------------------------------------------------
3647------------------------------------------------------------------------------
3648-- Generalized grouping
3649------------------------------------------------------------------------------
3651-- This combinator is the most general grouping combinator and can be used to
3652-- implement all other grouping combinators.
3654-- XXX check if this can implement the splitOn combinator i.e. we can slide in
3655-- new elements, slide out old elements and incrementally compute the hash.
3656-- Also, can we implement the windowed classification combinators using this?
3658-- In fact this is a parse. Instead of using a special return value in the fold
3659-- we are using a mapping function.
3661-- Note that 'scanl'' (usually followed by a map to extract the desired value
3662-- from the accumulator) can be used to realize many implementations e.g. a
3663-- sliding window implementation. A scan followed by a mapMaybe is also a good
3664-- pattern to express many problems where we want to emit a filtered output and
3665-- not emit an output on every input.
3667-- Passing on of the initial accumulator value to the next fold is equivalent
3668-- to returning the leftover concept.
3671-- | @groupScan splitter fold stream@ folds the input stream using @fold@.
3672-- @splitter@ is applied on the accumulator of the fold every time an item is
3673-- consumed by the fold. The fold continues until @splitter@ returns a 'Just'
3674-- value. A 'Just' result from the @splitter@ specifies a result to be emitted
3675-- in the output stream and the initial value of the accumulator for the next
3676-- group's fold. This allows us to control whether to start fresh for the next
3677-- fold or to continue from the previous fold's output.
3679{-# INLINE groupScan #-}
3680groupScan
3681 :: (IsStream t, Monad m)
3682 => (x -> m (Maybe (b, x))) -> Fold m a x -> t m a -> t m b
3683groupScan split fold m = undefined
3686-- | Group the input stream into groups of @n@ elements each and then fold each
3687-- group using the provided fold function.
3689-- >> S.toList $ S.chunksOf 2 FL.sum (S.enumerateFromTo 1 10)
3690-- > [3,7,11,15,19]
3692-- This can be considered as an n-fold version of 'ltake' where we apply
3693-- 'ltake' repeatedly on the leftover stream until the stream exhausts.
3695-- @since 0.7.0
3696{-# INLINE chunksOf #-}
3697chunksOf
3698 :: (IsStream t, Monad m)
3699 => Int -> Fold m a b -> t m a -> t m b
3700chunksOf n f m = D.fromStreamD $ D.groupsOf n f (D.toStreamD m)
3702-- |
3704-- /Internal/
3705{-# INLINE chunksOf2 #-}
3706chunksOf2
3707 :: (IsStream t, Monad m)
3708 => Int -> m c -> Fold2 m c a b -> t m a -> t m b
3709chunksOf2 n action f m = D.fromStreamD $ D.groupsOf2 n action f (D.toStreamD m)
3711-- | @arraysOf n stream@ groups the elements in the input stream into arrays of
3712-- @n@ elements each.
3714-- Same as the following but may be more efficient:
3716-- > arraysOf n = S.chunksOf n (A.writeN n)
3718-- /Internal/
3719{-# INLINE arraysOf #-}
3720arraysOf :: (IsStream t, MonadIO m, Storable a)
3721 => Int -> t m a -> t m (Array a)
3722arraysOf n = chunksOf n (writeNUnsafe n)
3724-- XXX we can implement this by repeatedly applying the 'lrunFor' fold.
3725-- XXX add this example after fixing the serial stream rate control
3726-- >>> S.toList $ S.take 5 $ intervalsOf 1 FL.sum $ constRate 2 $ S.enumerateFrom 1
3727-- > [3,7,11,15,19]
3729-- | Group the input stream into windows of @n@ second each and then fold each
3730-- group using the provided fold function.
3732-- @since 0.7.0
3733{-# INLINE intervalsOf #-}
3734intervalsOf
3735 :: (IsStream t, MonadAsync m)
3736 => Double -> Fold m a b -> t m a -> t m b
3737intervalsOf n f xs =
3738 splitWithSuffix isNothing (FL.lcatMaybes f)
3739 (interjectSuffix n (return Nothing) (Serial.map Just xs))
3741------------------------------------------------------------------------------
3742-- N-ary APIs
3743------------------------------------------------------------------------------
3745-- | @groupsBy cmp f $ S.fromList [a,b,c,...]@ assigns the element @a@ to the
3746-- first group, if @b \`cmp` a@ is 'True' then @b@ is also assigned to the same
3747-- group. If @c \`cmp` a@ is 'True' then @c@ is also assigned to the same
3748-- group and so on. When the comparison fails a new group is started. Each
3749-- group is folded using the fold @f@ and the result of the fold is emitted in
3750-- the output stream.
3752-- >>> S.toList $ S.groupsBy (>) FL.toList $ S.fromList [1,3,7,0,2,5]
3753-- > [[1,3,7],[0,2,5]]
3755-- @since 0.7.0
3756{-# INLINE groupsBy #-}
3757groupsBy
3758 :: (IsStream t, Monad m)
3759 => (a -> a -> Bool)
3760 -> Fold m a b
3761 -> t m a
3762 -> t m b
3763groupsBy cmp f m = D.fromStreamD $ D.groupsBy cmp f (D.toStreamD m)
3765-- | Unlike @groupsBy@ this function performs a rolling comparison of two
3766-- successive elements in the input stream. @groupsByRolling cmp f $ S.fromList
3767-- [a,b,c,...]@ assigns the element @a@ to the first group, if @a \`cmp` b@ is
3768-- 'True' then @b@ is also assigned to the same group. If @b \`cmp` c@ is
3769-- 'True' then @c@ is also assigned to the same group and so on. When the
3770-- comparison fails a new group is started. Each group is folded using the fold
3771-- @f@.
3773-- >>> S.toList $ S.groupsByRolling (\a b -> a + 1 == b) FL.toList $ S.fromList [1,2,3,7,8,9]
3774-- > [[1,2,3],[7,8,9]]
3776-- @since 0.7.0
3777{-# INLINE groupsByRolling #-}
3778groupsByRolling
3779 :: (IsStream t, Monad m)
3780 => (a -> a -> Bool)
3781 -> Fold m a b
3782 -> t m a
3783 -> t m b
3784groupsByRolling cmp f m = D.fromStreamD $ D.groupsRollingBy cmp f (D.toStreamD m)
3786-- |
3787-- > groups = groupsBy (==)
3788-- > groups = groupsByRolling (==)
3790-- Groups contiguous spans of equal elements together in individual groups.
3792-- >>> S.toList $ S.groups FL.toList $ S.fromList [1,1,2,2]
3793-- > [[1,1],[2,2]]
3795-- @since 0.7.0
3796groups :: (IsStream t, Monad m, Eq a) => Fold m a b -> t m a -> t m b
3797groups = groupsBy (==)
3799------------------------------------------------------------------------------
3800-- N-ary split on a predicate
3801------------------------------------------------------------------------------
3803-- TODO: Use a Splitter configuration similar to the "split" package to make it
3804-- possible to express all splitting combinations. In general, we can have
3805-- infix/suffix/prefix/condensing of separators, dropping both leading/trailing
3806-- separators. We can have a single split operation taking the splitter config
3807-- as argument.
3809-- | Split on an infixed separator element, dropping the separator. Splits the
3810-- stream on separator elements determined by the supplied predicate, separator
3811-- is considered as infixed between two segments, if one side of the separator
3812-- is missing then it is parsed as an empty stream. The supplied 'Fold' is
3813-- applied on the split segments. With '-' representing non-separator elements
3814-- and '.' as separator, 'splitOn' splits as follows:
3816-- @
3817-- "--.--" => "--" "--"
3818-- "--." => "--" ""
3819-- ".--" => "" "--"
3820-- @
3822-- @splitOn (== x)@ is an inverse of @intercalate (S.yield x)@
3824-- Let's use the following definition for illustration:
3826-- > splitOn' p xs = S.toList $ S.splitOn p (FL.toList) (S.fromList xs)
3828-- >>> splitOn' (== '.') ""
3829-- [""]
3831-- >>> splitOn' (== '.') "."
3832-- ["",""]
3834-- >>> splitOn' (== '.') ".a"
3835-- > ["","a"]
3837-- >>> splitOn' (== '.') "a."
3838-- > ["a",""]
3840-- >>> splitOn' (== '.') "a.b"
3841-- > ["a","b"]
3843-- >>> splitOn' (== '.') "a..b"
3844-- > ["a","","b"]
3846-- @since 0.7.0
3848-- This can be considered as an n-fold version of 'breakOn' where we apply
3849-- 'breakOn' successively on the input stream, dropping the first element
3850-- of the second segment after each break.
3852{-# INLINE splitOn #-}
3853splitOn
3854 :: (IsStream t, Monad m)
3855 => (a -> Bool) -> Fold m a b -> t m a -> t m b
3856splitOn predicate f m =
3857 D.fromStreamD $ D.splitBy predicate f (D.toStreamD m)
3859-- | Like 'splitOn' but the separator is considered as suffixed to the segments
3860-- in the stream. A missing suffix at the end is allowed. A separator at the
3861-- beginning is parsed as empty segment. With '-' representing elements and
3862-- '.' as separator, 'splitOnSuffix' splits as follows:
3864-- @
3865-- "--.--." => "--" "--"
3866-- "--.--" => "--" "--"
3867-- ".--." => "" "--"
3868-- @
3870-- > splitOnSuffix' p xs = S.toList $ S.splitSuffixBy p (FL.toList) (S.fromList xs)
3872-- >>> splitOnSuffix' (== '.') ""
3873-- []
3875-- >>> splitOnSuffix' (== '.') "."
3876-- [""]
3878-- >>> splitOnSuffix' (== '.') "a"
3879-- ["a"]
3881-- >>> splitOnSuffix' (== '.') ".a"
3882-- > ["","a"]
3884-- >>> splitOnSuffix' (== '.') "a."
3885-- > ["a"]
3887-- >>> splitOnSuffix' (== '.') "a.b"
3888-- > ["a","b"]
3890-- >>> splitOnSuffix' (== '.') "a.b."
3891-- > ["a","b"]
3893-- >>> splitOnSuffix' (== '.') "a..b.."
3894-- > ["a","","b",""]
3896-- > lines = splitOnSuffix (== '\n')
3898-- @since 0.7.0
3900-- This can be considered as an n-fold version of 'breakPost' where we apply
3901-- 'breakPost' successively on the input stream, dropping the first element
3902-- of the second segment after each break.
3904{-# INLINE splitOnSuffix #-}
3905splitOnSuffix
3906 :: (IsStream t, Monad m)
3907 => (a -> Bool) -> Fold m a b -> t m a -> t m b
3908splitOnSuffix predicate f m =
3909 D.fromStreamD $ D.splitSuffixBy predicate f (D.toStreamD m)
3911-- | Like 'splitOn' after stripping leading, trailing, and repeated separators.
3912-- Therefore, @".a..b."@ with '.' as the separator would be parsed as
3913-- @["a","b"]@. In other words, its like parsing words from whitespace
3914-- separated text.
3916-- > wordsBy' p xs = S.toList $ S.wordsBy p (FL.toList) (S.fromList xs)
3918-- >>> wordsBy' (== ',') ""
3919-- > []
3921-- >>> wordsBy' (== ',') ","
3922-- > []
3924-- >>> wordsBy' (== ',') ",a,,b,"
3925-- > ["a","b"]
3927-- > words = wordsBy isSpace
3929-- @since 0.7.0
3931-- It is equivalent to splitting in any of the infix/prefix/suffix styles
3932-- followed by removal of empty segments.
3933{-# INLINE wordsBy #-}
3934wordsBy
3935 :: (IsStream t, Monad m)
3936 => (a -> Bool) -> Fold m a b -> t m a -> t m b
3937wordsBy predicate f m =
3938 D.fromStreamD $ D.wordsBy predicate f (D.toStreamD m)
3940-- | Like 'splitOnSuffix' but keeps the suffix attached to the resulting
3941-- splits.
3943-- > splitWithSuffix' p xs = S.toList $ S.splitWithSuffix p (FL.toList) (S.fromList xs)
3945-- >>> splitWithSuffix' (== '.') ""
3946-- []
3948-- >>> splitWithSuffix' (== '.') "."
3949-- ["."]
3951-- >>> splitWithSuffix' (== '.') "a"
3952-- ["a"]
3954-- >>> splitWithSuffix' (== '.') ".a"
3955-- > [".","a"]
3957-- >>> splitWithSuffix' (== '.') "a."
3958-- > ["a."]
3960-- >>> splitWithSuffix' (== '.') "a.b"
3961-- > ["a.","b"]
3963-- >>> splitWithSuffix' (== '.') "a.b."
3964-- > ["a.","b."]
3966-- >>> splitWithSuffix' (== '.') "a..b.."
3967-- > ["a.",".","b.","."]
3969-- @since 0.7.0
3971-- This can be considered as an n-fold version of 'breakPost' where we apply
3972-- 'breakPost' successively on the input stream.
3974{-# INLINE splitWithSuffix #-}
3975splitWithSuffix
3976 :: (IsStream t, Monad m)
3977 => (a -> Bool) -> Fold m a b -> t m a -> t m b
3978splitWithSuffix predicate f m =
3979 D.fromStreamD $ D.splitSuffixBy' predicate f (D.toStreamD m)
3981------------------------------------------------------------------------------
3982-- Split on a delimiter sequence
3983------------------------------------------------------------------------------
3985-- Int list examples for splitOn:
3987-- >>> splitList [] [1,2,3,3,4]
3988-- > [[1],[2],[3],[3],[4]]
3990-- >>> splitList [5] [1,2,3,3,4]
3991-- > [[1,2,3,3,4]]
3993-- >>> splitList [1] [1,2,3,3,4]
3994-- > [[],[2,3,3,4]]
3996-- >>> splitList [4] [1,2,3,3,4]
3997-- > [[1,2,3,3],[]]
3999-- >>> splitList [2] [1,2,3,3,4]
4000-- > [[1],[3,3,4]]
4002-- >>> splitList [3] [1,2,3,3,4]
4003-- > [[1,2],[],[4]]
4005-- >>> splitList [3,3] [1,2,3,3,4]
4006-- > [[1,2],[4]]
4008-- >>> splitList [1,2,3,3,4] [1,2,3,3,4]
4009-- > [[],[]]
4011-- | Like 'splitOn' but the separator is a sequence of elements instead of a
4012-- single element.
4014-- For illustration, let's define a function that operates on pure lists:
4016-- @
4017-- splitOnSeq' pat xs = S.toList $ S.splitOnSeq (A.fromList pat) (FL.toList) (S.fromList xs)
4018-- @
4020-- >>> splitOnSeq' "" "hello"
4021-- > ["h","e","l","l","o"]
4023-- >>> splitOnSeq' "hello" ""
4024-- > [""]
4026-- >>> splitOnSeq' "hello" "hello"
4027-- > ["",""]
4029-- >>> splitOnSeq' "x" "hello"
4030-- > ["hello"]
4032-- >>> splitOnSeq' "h" "hello"
4033-- > ["","ello"]
4035-- >>> splitOnSeq' "o" "hello"
4036-- > ["hell",""]
4038-- >>> splitOnSeq' "e" "hello"
4039-- > ["h","llo"]
4041-- >>> splitOnSeq' "l" "hello"
4042-- > ["he","","o"]
4044-- >>> splitOnSeq' "ll" "hello"
4045-- > ["he","o"]
4047-- 'splitOnSeq' is an inverse of 'intercalate'. The following law always holds:
4049-- > intercalate . splitOn == id
4051-- The following law holds when the separator is non-empty and contains none of
4052-- the elements present in the input lists:
4054-- > splitOn . intercalate == id
4056-- /Internal/
4058-- XXX We can use a polymorphic vector implemented by Array# to represent the
4059-- sequence, that way we can avoid the Storable constraint. If we still need
4060-- Storable Array for performance, we can use a separate splitOnArray API for
4061-- that. We can also have an API where the sequence itself is a lazy stream, so
4062-- that we can search files in files for example.
4063{-# INLINE splitOnSeq #-}
4064splitOnSeq
4065 :: (IsStream t, MonadIO m, Storable a, Enum a, Eq a)
4066 => Array a -> Fold m a b -> t m a -> t m b
4067splitOnSeq patt f m = D.fromStreamD $ D.splitOn patt f (D.toStreamD m)
4070-- This can be implemented easily using Rabin Karp
4071-- | Split on any one of the given patterns.
4072{-# INLINE splitOnAny #-}
4073splitOnAny
4074 :: (IsStream t, Monad m, Storable a, Integral a)
4075 => [Array a] -> Fold m a b -> t m a -> t m b
4076splitOnAny subseq f m = undefined -- D.fromStreamD $ D.splitOnAny f subseq (D.toStreamD m)
4079-- | Like 'splitSuffixBy' but the separator is a sequence of elements, instead
4080-- of a predicate for a single element.
4082-- > splitSuffixOn_ pat xs = S.toList $ S.splitSuffixOn (A.fromList pat) (FL.toList) (S.fromList xs)
4084-- >>> splitSuffixOn_ "." ""
4085-- [""]
4087-- >>> splitSuffixOn_ "." "."
4088-- [""]
4090-- >>> splitSuffixOn_ "." "a"
4091-- ["a"]
4093-- >>> splitSuffixOn_ "." ".a"
4094-- > ["","a"]
4096-- >>> splitSuffixOn_ "." "a."
4097-- > ["a"]
4099-- >>> splitSuffixOn_ "." "a.b"
4100-- > ["a","b"]
4102-- >>> splitSuffixOn_ "." "a.b."
4103-- > ["a","b"]
4105-- >>> splitSuffixOn_ "." "a..b.."
4106-- > ["a","","b",""]
4108-- > lines = splitSuffixOn "\n"
4110-- /Internal/
4111{-# INLINE splitOnSuffixSeq #-}
4112splitOnSuffixSeq
4113 :: (IsStream t, MonadIO m, Storable a, Enum a, Eq a)
4114 => Array a -> Fold m a b -> t m a -> t m b
4115splitOnSuffixSeq patt f m =
4116 D.fromStreamD $ D.splitSuffixOn False patt f (D.toStreamD m)
4119-- | Like 'splitOn' but drops any empty splits.
4121{-# INLINE wordsOn #-}
4122wordsOn
4123 :: (IsStream t, Monad m, Storable a, Eq a)
4124 => Array a -> Fold m a b -> t m a -> t m b
4125wordsOn subseq f m = undefined -- D.fromStreamD $ D.wordsOn f subseq (D.toStreamD m)
4128-- XXX use a non-monadic intersperse to remove the MonadAsync constraint.
4130-- | Like 'splitOnSeq' but splits the separator as well, as an infix token.
4132-- > splitOn'_ pat xs = S.toList $ S.splitOn' (A.fromList pat) (FL.toList) (S.fromList xs)
4134-- >>> splitOn'_ "" "hello"
4135-- > ["h","","e","","l","","l","","o"]
4137-- >>> splitOn'_ "hello" ""
4138-- > [""]
4140-- >>> splitOn'_ "hello" "hello"
4141-- > ["","hello",""]
4143-- >>> splitOn'_ "x" "hello"
4144-- > ["hello"]
4146-- >>> splitOn'_ "h" "hello"
4147-- > ["","h","ello"]
4149-- >>> splitOn'_ "o" "hello"
4150-- > ["hell","o",""]
4152-- >>> splitOn'_ "e" "hello"
4153-- > ["h","e","llo"]
4155-- >>> splitOn'_ "l" "hello"
4156-- > ["he","l","","l","o"]
4158-- >>> splitOn'_ "ll" "hello"
4159-- > ["he","ll","o"]
4161-- /Internal/
4162{-# INLINE splitBySeq #-}
4163splitBySeq
4164 :: (IsStream t, MonadAsync m, Storable a, Enum a, Eq a)
4165 => Array a -> Fold m a b -> t m a -> t m b
4166splitBySeq patt f m =
4167 intersperseM (fold f (A.toStream patt)) $ splitOnSeq patt f m
4169-- | Like 'splitSuffixOn' but keeps the suffix intact in the splits.
4171-- > splitSuffixOn'_ pat xs = S.toList $ FL.splitSuffixOn' (A.fromList pat) (FL.toList) (S.fromList xs)
4173-- >>> splitSuffixOn'_ "." ""
4174-- [""]
4176-- >>> splitSuffixOn'_ "." "."
4177-- ["."]
4179-- >>> splitSuffixOn'_ "." "a"
4180-- ["a"]
4182-- >>> splitSuffixOn'_ "." ".a"
4183-- > [".","a"]
4185-- >>> splitSuffixOn'_ "." "a."
4186-- > ["a."]
4188-- >>> splitSuffixOn'_ "." "a.b"
4189-- > ["a.","b"]
4191-- >>> splitSuffixOn'_ "." "a.b."
4192-- > ["a.","b."]
4194-- >>> splitSuffixOn'_ "." "a..b.."
4195-- > ["a.",".","b.","."]
4197-- /Internal/
4198{-# INLINE splitWithSuffixSeq #-}
4199splitWithSuffixSeq
4200 :: (IsStream t, MonadIO m, Storable a, Enum a, Eq a)
4201 => Array a -> Fold m a b -> t m a -> t m b
4202splitWithSuffixSeq patt f m =
4203 D.fromStreamD $ D.splitSuffixOn True patt f (D.toStreamD m)
4206-- This can be implemented easily using Rabin Karp
4207-- | Split post any one of the given patterns.
4208{-# INLINE splitSuffixOnAny #-}
4209splitSuffixOnAny
4210 :: (IsStream t, Monad m, Storable a, Integral a)
4211 => [Array a] -> Fold m a b -> t m a -> t m b
4212splitSuffixOnAny subseq f m = undefined
4213 -- D.fromStreamD $ D.splitPostAny f subseq (D.toStreamD m)
4216------------------------------------------------------------------------------
4217-- Nested Split
4218------------------------------------------------------------------------------
4220-- | @splitInnerBy splitter joiner stream@ splits the inner containers @f a@ of
4221-- an input stream @t m (f a)@ using the @splitter@ function. Container
4222-- elements @f a@ are collected until a split occurs, then all the elements
4223-- before the split are joined using the @joiner@ function.
4225-- For example, if we have a stream of @Array Word8@, we may want to split the
4226-- stream into arrays representing lines separated by '\n' byte such that the
4227-- resulting stream after a split would be one array for each line.
4229-- CAUTION! This is not a true streaming function as the container size after
4230-- the split and merge may not be bounded.
4232-- /Internal/
4233{-# INLINE splitInnerBy #-}
4234splitInnerBy
4235 :: (IsStream t, Monad m)
4236 => (f a -> m (f a, Maybe (f a))) -- splitter
4237 -> (f a -> f a -> m (f a)) -- joiner
4238 -> t m (f a)
4239 -> t m (f a)
4240splitInnerBy splitter joiner xs =
4241 D.fromStreamD $ D.splitInnerBy splitter joiner $ D.toStreamD xs
4243-- | Like 'splitInnerBy' but splits assuming the separator joins the segment in
4244-- a suffix style.
4246-- /Internal/
4247{-# INLINE splitInnerBySuffix #-}
4248splitInnerBySuffix
4249 :: (IsStream t, Monad m, Eq (f a), Monoid (f a))
4250 => (f a -> m (f a, Maybe (f a))) -- splitter
4251 -> (f a -> f a -> m (f a)) -- joiner
4252 -> t m (f a)
4253 -> t m (f a)
4254splitInnerBySuffix splitter joiner xs =
4255 D.fromStreamD $ D.splitInnerBySuffix splitter joiner $ D.toStreamD xs
4257------------------------------------------------------------------------------
4258-- Reorder in sequence
4259------------------------------------------------------------------------------
4262-- Buffer until the next element in sequence arrives. The function argument
4263-- determines the difference in sequence numbers. This could be useful in
4264-- implementing sequenced streams, for example, TCP reassembly.
4265{-# INLINE reassembleBy #-}
4266reassembleBy
4267 :: (IsStream t, Monad m)
4268 => Fold m a b
4269 -> (a -> a -> Int)
4270 -> t m a
4271 -> t m b
4272reassembleBy = undefined
4275------------------------------------------------------------------------------
4276-- Distributing
4277------------------------------------------------------------------------------
4279-- | Tap the data flowing through a stream into a 'Fold'. For example, you may
4280-- add a tap to log the contents flowing through the stream. The fold is used
4281-- only for effects, its result is discarded.
4283-- @
4284-- Fold m a b
4285-- |
4286-- -----stream m a ---------------stream m a-----
4288-- @
4290-- @
4291-- > S.drain $ S.tap (FL.drainBy print) (S.enumerateFromTo 1 2)
4292-- 1
4293-- 2
4294-- @
4296-- Compare with 'trace'.
4298-- @since 0.7.0
4299{-# INLINE tap #-}
4300tap :: (IsStream t, Monad m) => FL.Fold m a b -> t m a -> t m a
4301tap f xs = D.fromStreamD $ D.tap f (D.toStreamD xs)
4303-- | @tapOffsetEvery offset n@ taps every @n@th element in the stream
4304-- starting at @offset@. @offset@ can be between @0@ and @n - 1@. Offset 0
4305-- means start at the first element in the stream. If the offset is outside
4306-- this range then @offset `mod` n@ is used as offset.
4308-- @
4309-- >>> S.drain $ S.tapOffsetEvery 0 2 (FL.mapM print FL.toList) $ S.enumerateFromTo 0 10
4310-- > [0,2,4,6,8,10]
4311-- @
4313-- /Internal/
4315{-# INLINE tapOffsetEvery #-}
4316tapOffsetEvery :: (IsStream t, Monad m)
4317 => Int -> Int -> FL.Fold m a b -> t m a -> t m a
4318tapOffsetEvery offset n f xs =
4319 D.fromStreamD $ D.tapOffsetEvery offset n f (D.toStreamD xs)
4321-- | Redirect a copy of the stream to a supplied fold and run it concurrently
4322-- in an independent thread. The fold may buffer some elements. The buffer size
4323-- is determined by the prevailing 'maxBuffer' setting.
4325-- @
4326-- Stream m a -> m b
4327-- |
4328-- -----stream m a ---------------stream m a-----
4330-- @
4332-- @
4333-- > S.drain $ S.tapAsync (S.mapM_ print) (S.enumerateFromTo 1 2)
4334-- 1
4335-- 2
4336-- @
4338-- Exceptions from the concurrently running fold are propagated to the current
4339-- computation. Note that, because of buffering in the fold, exceptions may be
4340-- delayed and may not correspond to the current element being processed in the
4341-- parent stream, but we guarantee that before the parent stream stops the tap
4342-- finishes and all exceptions from it are drained.
4345-- Compare with 'tap'.
4347-- /Internal/
4348{-# INLINE tapAsync #-}
4349tapAsync :: (IsStream t, MonadAsync m) => FL.Fold m a b -> t m a -> t m a
4350tapAsync f xs = D.fromStreamD $ D.tapAsync f (D.toStreamD xs)
4352-- | @pollCounts predicate transform fold stream@ counts those elements in the
4353-- stream that pass the @predicate@. The resulting count stream is sent to
4354-- another thread which transforms it using @transform@ and then folds it using
4355-- @fold@. The thread is automatically cleaned up if the stream stops or
4356-- aborts due to exception.
4358-- For example, to print the count of elements processed every second:
4360-- @
4361-- > S.drain $ S.pollCounts (const True) (S.rollingMap (-) . S.delayPost 1) (FL.drainBy print)
4362-- $ S.enumerateFrom 0
4363-- @
4365-- Note: This may not work correctly on 32-bit machines.
4367-- /Internal/
4369{-# INLINE pollCounts #-}
4370pollCounts ::
4371 (IsStream t, MonadAsync m)
4372 => (a -> Bool)
4373 -> (t m Int -> t m Int)
4374 -> Fold m Int b
4375 -> t m a
4376 -> t m a
4377pollCounts predicate transf f xs =
4378 D.fromStreamD
4379 $ D.pollCounts predicate (D.toStreamD . transf . D.fromStreamD) f
4380 $ D.toStreamD xs
4382-- | Calls the supplied function with the number of elements consumed
4383-- every @n@ seconds. The given function is run in a separate thread
4384-- until the end of the stream. In case there is an exception in the
4385-- stream the thread is killed during the next major GC.
4387-- Note: The action is not guaranteed to run if the main thread exits.
4389-- @
4390-- > delay n = threadDelay (round $ n * 1000000) >> return n
4391-- > S.drain $ S.tapRate 2 (\\n -> print $ show n ++ " elements processed") (delay 1 S.|: delay 0.5 S.|: delay 0.5 S.|: S.nil)
4392-- 2 elements processed
4393-- 1 elements processed
4394-- @
4396-- Note: This may not work correctly on 32-bit machines.
4398-- /Internal/
4399{-# INLINE tapRate #-}
4400tapRate ::
4401 (IsStream t, MonadAsync m, MonadCatch m)
4402 => Double
4403 -> (Int -> m b)
4404 -> t m a
4405 -> t m a
4406tapRate n f xs = D.fromStreamD $ D.tapRate n f $ D.toStreamD xs
4408-- | Apply a monadic function to each element flowing through the stream and
4409-- discard the results.
4411-- @
4412-- > S.drain $ S.trace print (S.enumerateFromTo 1 2)
4413-- 1
4414-- 2
4415-- @
4417-- Compare with 'tap'.
4419-- @since 0.7.0
4420{-# INLINE trace #-}
4421trace :: (IsStream t, MonadAsync m) => (a -> m b) -> t m a -> t m a
4422trace f = mapM (\x -> void (f x) >> return x)
4424-- | Perform a side effect before yielding each element of the stream and
4425-- discard the results.
4427-- @
4428-- > S.drain $ S.trace_ (print "got here") (S.enumerateFromTo 1 2)
4429-- "got here"
4430-- "got here"
4431-- @
4433-- See also: 'trace', 'interspersePrefix_'
4435-- /Internal/
4436{-# INLINE trace_ #-}
4437trace_ :: (IsStream t, Monad m) => m b -> t m a -> t m a
4438trace_ eff = Serial.mapM (\x -> eff >> return x)
4440------------------------------------------------------------------------------
4441-- Windowed classification
4442------------------------------------------------------------------------------
4444-- We divide the stream into windows or chunks in space or time and each window
4445-- can be associated with a key, all events associated with a particular key in
4446-- the window can be folded to a single result. The stream can be split into
4447-- windows by size or by using a split predicate on the elements in the stream.
4448-- For example, when we receive a closing flag, we can close the window.
4450-- A "chunk" is a space window and a "session" is a time window. Are there any
4451-- other better short words to describe them. An alternative is to use
4452-- "swindow" and "twindow". Another word for "session" could be "spell".
4454-- TODO: To mark the position in space or time we can have Indexed or
4455-- TimeStamped types. That can make it easy to deal with the position indices
4456-- or timestamps.
4458------------------------------------------------------------------------------
4459-- Keyed Sliding Windows
4460------------------------------------------------------------------------------
4463{-# INLINABLE classifySlidingChunks #-}
4464classifySlidingChunks
4465 :: (IsStream t, MonadAsync m, Ord k)
4466 => Int -- ^ window size
4467 -> Int -- ^ window slide
4468 -> Fold m a b -- ^ Fold to be applied to window events
4469 -> t m (k, a, Bool) -- ^ window key, data, close event
4470 -> t m (k, b)
4471classifySlidingChunks wsize wslide (Fold step initial extract) str
4472 = undefined
4474-- XXX Another variant could be to slide the window on an event, e.g. in TCP we
4475-- slide the send window when an ack is received and we slide the receive
4476-- window when a sequence is complete. Sliding is stateful in case of TCP,
4477-- sliding releases the send buffer or makes data available to the user from
4478-- the receive buffer.
4479{-# INLINABLE classifySlidingSessions #-}
4480classifySlidingSessions
4481 :: (IsStream t, MonadAsync m, Ord k)
4482 => Double -- ^ timer tick in seconds
4483 -> Double -- ^ time window size
4484 -> Double -- ^ window slide
4485 -> Fold m a b -- ^ Fold to be applied to window events
4486 -> t m (k, a, Bool, AbsTime) -- ^ window key, data, close flag, timestamp
4487 -> t m (k, b)
4488classifySlidingSessions tick interval slide (Fold step initial extract) str
4489 = undefined
4492------------------------------------------------------------------------------
4493-- Sliding Window Buffers
4494------------------------------------------------------------------------------
4496-- These buffered versions could be faster than concurrent incremental folds of
4497-- all overlapping windows as in many cases we may not need all the values to
4498-- compute the fold, we can just compute the result using the old value and new
4499-- value. However, we may need the buffer once in a while, for example for
4500-- string search we usually compute the hash incrementally but when the hash
4501-- matches the hash of the pattern we need to compare the whole string.
4503-- XXX we should be able to implement sequence based splitting combinators
4504-- using this combinator.
4507-- | Buffer n elements of the input in a ring buffer. When t new elements are
4508-- collected, slide the window to remove the same number of oldest elements,
4509-- insert the new elements, and apply an incremental fold on the sliding
4510-- window, supplying the outgoing elements, the new ring buffer as arguments.
4511slidingChunkBuffer
4512 :: (IsStream t, Monad m, Ord a, Storable a)
4513 => Int -- window size
4514 -> Int -- window slide
4515 -> Fold m (Ring a, Array a) b
4516 -> t m a
4517 -> t m b
4518slidingChunkBuffer = undefined
4520-- Buffer n seconds worth of stream elements of the input in a radix tree.
4521-- Every t seconds, remove the items that are older than n seconds, and apply
4522-- an incremental fold on the sliding window, supplying the outgoing elements,
4523-- and the new radix tree buffer as arguments.
4524slidingSessionBuffer
4525 :: (IsStream t, Monad m, Ord a, Storable a)
4526 => Int -- window size
4527 -> Int -- tick size
4528 -> Fold m (RTree a, Array a) b
4529 -> t m a
4530 -> t m b
4531slidingSessionBuffer = undefined
4534------------------------------------------------------------------------------
4535-- Keyed Session Windows
4536------------------------------------------------------------------------------
4539-- | Keyed variable size space windows. Close the window if we do not receive a
4540-- window event in the next "spaceout" elements.
4541{-# INLINABLE classifyChunksBy #-}
4542classifyChunksBy
4543 :: (IsStream t, MonadAsync m, Ord k)
4544 => Int -- ^ window spaceout (spread)
4545 -> Bool -- ^ reset the spaceout when a chunk window element is received
4546 -> Fold m a b -- ^ Fold to be applied to chunk window elements
4547 -> t m (k, a, Bool) -- ^ chunk key, data, last element
4548 -> t m (k, b)
4549classifyChunksBy spanout reset (Fold step initial extract) str = undefined
4551-- | Like 'classifyChunksOf' but the chunk size is reset if an element is
4552-- received within the chunk size window. The chunk gets closed only if no
4553-- element is received within the chunk window.
4555{-# INLINABLE classifyKeepAliveChunks #-}
4556classifyKeepAliveChunks
4557 :: (IsStream t, MonadAsync m, Ord k)
4558 => Int -- ^ window spaceout (spread)
4559 -> Fold m a b -- ^ Fold to be applied to chunk window elements
4560 -> t m (k, a, Bool) -- ^ chunk key, data, last element
4561 -> t m (k, b)
4562classifyKeepAliveChunks spanout = classifyChunksBy spanout True
4565data SessionState t m k a b = SessionState
4566 { sessionCurTime :: !AbsTime -- ^ time since last event
4567 , sessionEventTime :: !AbsTime -- ^ time as per last event
4568 , sessionCount :: !Int -- ^ total number sessions in progress
4569 , sessionTimerHeap :: H.Heap (H.Entry AbsTime k) -- ^ heap for timeouts
4570 , sessionKeyValueMap :: Map.Map k a -- ^ Stored sessions for keys
4571 , sessionOutputStream :: t (m :: Type -> Type) (k, b) -- ^ Completed sessions
4574#undef Type
4576-- | @classifySessionsBy tick timeout idle pred f stream@ groups timestamped
4577-- events in an input event stream into sessions based on a session key. Each
4578-- element in the stream is an event consisting of a triple @(session key,
4579-- sesssion data, timestamp)@. @session key@ is a key that uniquely identifies
4580-- the session. All the events belonging to a session are folded using the
4581-- fold @f@ until the fold returns a 'Left' result or a timeout has occurred.
4582-- The session key and the result of the fold are emitted in the output stream
4583-- when the session is purged.
4585-- When @idle@ is 'False', @timeout@ is the maximum lifetime of a session in
4586-- seconds, measured from the @timestamp@ of the first event in that session.
4587-- When @idle@ is 'True' then the timeout is an idle timeout, it is reset after
4588-- every event received in the session.
4590-- @timestamp@ in an event characterizes the time when the input event was
4591-- generated, this is an absolute time measured from some @Epoch@. The notion
4592-- of current time is maintained by a monotonic event time clock using the
4593-- timestamps seen in the input stream. The latest timestamp seen till now is
4594-- used as the base for the current time. When no new events are seen, a timer
4595-- is started with a tick duration specified by @tick@. This timer is used to
4596-- detect session timeouts in the absence of new events.
4598-- The predicate @pred@ is invoked with the current session count, if it
4599-- returns 'True' a session is ejected from the session cache before inserting
4600-- a new session. This could be useful to alert or eject sessions when the
4601-- number of sessions becomes too high.
4603-- /Internal/
4606-- XXX Perhaps we should use an "Event a" type to represent timestamped data.
4607{-# INLINABLE classifySessionsBy #-}
4608classifySessionsBy
4609 :: (IsStream t, MonadAsync m, Ord k)
4610 => Double -- ^ timer tick in seconds
4611 -> Double -- ^ session timeout in seconds
4612 -> Bool -- ^ reset the timeout when an event is received
4613 -> (Int -> m Bool) -- ^ predicate to eject sessions based on session count
4614 -> Fold m a (Either b b) -- ^ Fold to be applied to session events
4615 -> t m (k, a, AbsTime) -- ^ session key, data, timestamp
4616 -> t m (k, b) -- ^ session key, fold result
4617classifySessionsBy tick tmout reset ejectPred
4618 (Fold step initial extract) str =
4619 concatMap sessionOutputStream $
4620 scanlMAfter' sstep (return szero) flush stream
4622 where
4624 timeoutMs = toRelTime (round (tmout * 1000) :: MilliSecond64)
4625 tickMs = toRelTime (round (tick * 1000) :: MilliSecond64)
4626 szero = SessionState
4627 { sessionCurTime = toAbsTime (0 :: MilliSecond64)
4628 , sessionEventTime = toAbsTime (0 :: MilliSecond64)
4629 , sessionCount = 0
4630 , sessionTimerHeap = H.empty
4631 , sessionKeyValueMap = Map.empty
4632 , sessionOutputStream = K.nil
4635 -- We can eject sessions based on the current session count to limit
4636 -- memory consumption. There are two possible strategies:
4637 --
4638 -- 1) Eject old sessions or sessions beyond a certain/lower timeout
4639 -- threshold even before timeout, effectively reduce the timeout.
4640 -- 2) Drop creation of new sessions but keep accepting new events for the
4641 -- old ones.
4642 --
4643 -- We use the first strategy as of now.
4645 -- Got a new stream input element
4646 sstep session@SessionState{..} (Just (key, value, timestamp)) = do
4647 -- XXX we should use a heap in pinned memory to scale it to a large
4648 -- size
4649 --
4650 -- To detect session inactivity we keep a timestamp of the latest event
4651 -- in the Map along with the fold result. When we purge the session
4652 -- from the heap we match the timestamp in the heap with the timestamp
4653 -- in the Map, if the latest timestamp is newer and has not expired we
4654 -- reinsert the key in the heap.
4655 --
4656 -- XXX if the key is an Int, we can also use an IntMap for slightly
4657 -- better performance.
4658 --
4659 let curTime = max sessionEventTime timestamp
4660 accumulate v = do
4661 old <- case v of
4662 Nothing -> initial
4663 Just (Tuple' _ acc) -> return acc
4664 new <- step old value
4665 return $ Tuple' timestamp new
4666 mOld = Map.lookup key sessionKeyValueMap
4668 acc@(Tuple' _ fres) <- accumulate mOld
4669 res <- extract fres
4670 case res of
4671 Left x -> do
4672 -- deleting a key from the heap is expensive, so we never
4673 -- delete a key from heap, we just purge it from the Map and it
4674 -- gets purged from the heap on timeout. We just need an extra
4675 -- lookup in the Map when the key is purged from the heap, that
4676 -- should not be expensive.
4677 --
4678 let (mp, cnt) = case mOld of
4679 Nothing -> (sessionKeyValueMap, sessionCount)
4680 Just _ -> (Map.delete key sessionKeyValueMap
4681 , sessionCount - 1)
4682 return $ session
4683 { sessionCurTime = curTime
4684 , sessionEventTime = curTime
4685 , sessionCount = cnt
4686 , sessionKeyValueMap = mp
4687 , sessionOutputStream = yield (key, x)
4689 Right _ -> do
4690 (hp1, mp1, out1, cnt1) <- do
4691 let vars = (sessionTimerHeap, sessionKeyValueMap,
4692 K.nil, sessionCount)
4693 case mOld of
4694 -- inserting new entry
4695 Nothing -> do
4696 -- Eject a session from heap and map is needed
4697 eject <- ejectPred sessionCount
4698 (hp, mp, out, cnt) <-
4699 if eject
4700 then ejectOne vars
4701 else return vars
4703 -- Insert the new session in heap
4704 let expiry = addToAbsTime timestamp timeoutMs
4705 hp' = H.insert (Entry expiry key) hp
4706 in return (hp', mp, out, cnt + 1)
4707 -- updating old entry
4708 Just _ -> return vars
4710 let mp2 = Map.insert key acc mp1
4711 return $ SessionState
4712 { sessionCurTime = curTime
4713 , sessionEventTime = curTime
4714 , sessionCount = cnt1
4715 , sessionTimerHeap = hp1
4716 , sessionKeyValueMap = mp2
4717 , sessionOutputStream = out1
4720 -- Got a timer tick event
4721 sstep sessionState@SessionState{..} Nothing =
4722 let curTime = addToAbsTime sessionCurTime tickMs
4723 in ejectExpired sessionState curTime
4725 flush session@SessionState{..} = do
4726 (hp', mp', out, count) <-
4727 ejectAll
4728 ( sessionTimerHeap
4729 , sessionKeyValueMap
4730 , K.nil
4731 , sessionCount
4733 return $ session
4734 { sessionCount = count
4735 , sessionTimerHeap = hp'
4736 , sessionKeyValueMap = mp'
4737 , sessionOutputStream = out
4740 fromEither e =
4741 case e of
4742 Left x -> x
4743 Right x -> x
4745 -- delete from map and output the fold accumulator
4746 ejectEntry hp mp out cnt acc key = do
4747 sess <- extract acc
4748 let out1 = (key, fromEither sess) `K.cons` out
4749 let mp1 = Map.delete key mp
4750 return (hp, mp1, out1, cnt - 1)
4752 ejectAll (hp, mp, out, !cnt) = do
4753 let hres = H.uncons hp
4754 case hres of
4755 Just (Entry _ key, hp1) -> do
4756 r <- case Map.lookup key mp of
4757 Nothing -> return (hp1, mp, out, cnt)
4758 Just (Tuple' _ acc) -> ejectEntry hp1 mp out cnt acc key
4759 ejectAll r
4760 Nothing -> do
4761 assert (Map.null mp) (return ())
4762 return (hp, mp, out, cnt)
4764 ejectOne (hp, mp, out, !cnt) = do
4765 let hres = H.uncons hp
4766 case hres of
4767 Just (Entry expiry key, hp1) ->
4768 case Map.lookup key mp of
4769 Nothing -> ejectOne (hp1, mp, out, cnt)
4770 Just (Tuple' latestTS acc) -> do
4771 let expiry1 = addToAbsTime latestTS timeoutMs
4772 if not reset || expiry1 <= expiry
4773 then ejectEntry hp1 mp out cnt acc key
4774 else
4775 -- reset the session timeout and continue
4776 let hp2 = H.insert (Entry expiry1 key) hp1
4777 in ejectOne (hp2, mp, out, cnt)
4778 Nothing -> do
4779 assert (Map.null mp) (return ())
4780 return (hp, mp, out, cnt)
4782 ejectExpired session@SessionState{..} curTime = do
4783 (hp', mp', out, count) <-
4784 ejectLoop sessionTimerHeap sessionKeyValueMap K.nil sessionCount
4785 return $ session
4786 { sessionCurTime = curTime
4787 , sessionCount = count
4788 , sessionTimerHeap = hp'
4789 , sessionKeyValueMap = mp'
4790 , sessionOutputStream = out
4793 where
4795 ejectLoop hp mp out !cnt = do
4796 let hres = H.uncons hp
4797 case hres of
4798 Just (Entry expiry key, hp1) -> do
4799 (eject, force) <-
4800 if curTime >= expiry
4801 then return (True, False)
4802 else do
4803 r <- ejectPred cnt
4804 return (r, r)
4805 if eject
4806 then
4807 case Map.lookup key mp of
4808 Nothing -> ejectLoop hp1 mp out cnt
4809 Just (Tuple' latestTS acc) -> do
4810 let expiry1 = addToAbsTime latestTS timeoutMs
4811 if expiry1 <= curTime || not reset || force
4812 then do
4813 (hp2,mp1,out1,cnt1) <-
4814 ejectEntry hp1 mp out cnt acc key
4815 ejectLoop hp2 mp1 out1 cnt1
4816 else
4817 -- reset the session timeout and continue
4818 let hp2 = H.insert (Entry expiry1 key) hp1
4819 in ejectLoop hp2 mp out cnt
4820 else return (hp, mp, out, cnt)
4821 Nothing -> do
4822 assert (Map.null mp) (return ())
4823 return (hp, mp, out, cnt)
4825 -- merge timer events in the stream
4826 stream = Serial.map Just str `Par.parallelFst` repeatM timer
4827 timer = do
4828 liftIO $ threadDelay (round $ tick * 1000000)
4829 return Nothing
4831-- | Like 'classifySessionsOf' but the session is kept alive if an event is
4832-- received within the session window. The session times out and gets closed
4833-- only if no event is received within the specified session window size.
4835-- If the ejection predicate returns 'True', the session that was idle for
4836-- the longest time is ejected before inserting a new session.
4838-- @
4839-- classifyKeepAliveSessions timeout pred = classifySessionsBy 1 timeout True pred
4840-- @
4842-- /Internal/
4844{-# INLINABLE classifyKeepAliveSessions #-}
4845classifyKeepAliveSessions
4846 :: (IsStream t, MonadAsync m, Ord k)
4847 => Double -- ^ session inactive timeout
4848 -> (Int -> m Bool) -- ^ predicate to eject sessions on session count
4849 -> Fold m a (Either b b) -- ^ Fold to be applied to session payload data
4850 -> t m (k, a, AbsTime) -- ^ session key, data, timestamp
4851 -> t m (k, b)
4852classifyKeepAliveSessions tmout =
4853 classifySessionsBy 1 tmout True
4855------------------------------------------------------------------------------
4856-- Keyed tumbling windows
4857------------------------------------------------------------------------------
4859-- Tumbling windows is a special case of sliding windows where the window slide
4860-- is the same as the window size. Or it can be a special case of session
4861-- windows where the reset flag is set to False.
4863-- XXX instead of using the early termination flag in the stream, we can use an
4864-- early terminating fold instead.
4867-- | Split the stream into fixed size chunks of specified size. Within each
4868-- such chunk fold the elements in buckets identified by the keys. A particular
4869-- bucket fold can be terminated early if a closing flag is encountered in an
4870-- element for that key.
4872-- @since 0.7.0
4873{-# INLINABLE classifyChunksOf #-}
4874classifyChunksOf
4875 :: (IsStream t, MonadAsync m, Ord k)
4876 => Int -- ^ window size
4877 -> Fold m a b -- ^ Fold to be applied to window events
4878 -> t m (k, a, Bool) -- ^ window key, data, close event
4879 -> t m (k, b)
4880classifyChunksOf wsize = classifyChunksBy wsize False
4883-- | Split the stream into fixed size time windows of specified interval in
4884-- seconds. Within each such window, fold the elements in sessions identified
4885-- by the session keys. The fold result is emitted in the output stream if the
4886-- fold returns a 'Left' result or if the time window ends.
4888-- Session @timestamp@ in the input stream is an absolute time from some epoch,
4889-- characterizing the time when the input element was generated. To detect
4890-- session window end, a monotonic event time clock is maintained synced with
4891-- the timestamps with a clock resolution of 1 second.
4893-- If the ejection predicate returns 'True', the session with the longest
4894-- lifetime is ejected before inserting a new session.
4896-- @
4897-- classifySessionsOf interval pred = classifySessionsBy 1 interval False pred
4898-- @
4900-- @
4901-- >>> S.mapM_ print
4902-- $ S.classifySessionsOf 3 (const (return False)) (fmap Right FL.toList)
4903-- $ S.map (\(ts,(k,a)) -> (k, a, ts))
4904-- $ S.timestamped
4905-- $ S.delay 1
4906-- $ (,) <$> S.fromList [1,2,3] <*> S.fromList [1,2,3]
4907-- @
4909-- /Internal/
4911{-# INLINABLE classifySessionsOf #-}
4912classifySessionsOf
4913 :: (IsStream t, MonadAsync m, Ord k)
4914 => Double -- ^ time window size
4915 -> (Int -> m Bool) -- ^ predicate to eject sessions on session count
4916 -> Fold m a (Either b b) -- ^ Fold to be applied to session events
4917 -> t m (k, a, AbsTime) -- ^ session key, data, timestamp
4918 -> t m (k, b)
4919classifySessionsOf interval =
4920 classifySessionsBy 1 interval False
4922------------------------------------------------------------------------------
4923-- Exceptions
4924------------------------------------------------------------------------------
4926-- | Run a side effect before the stream yields its first element.
4928-- > before action xs = 'nilM' action <> xs
4930-- @since 0.7.0
4931{-# INLINE before #-}
4932before :: (IsStream t, Monad m) => m b -> t m a -> t m a
4933before action xs = D.fromStreamD $ D.before action $ D.toStreamD xs
4935-- | Run a side effect at the end of the stream. The side effect won't run if
4936-- the stream is garbage collected before it reached the end.
4938-- > after_ action xs = xs <> 'nilM' action
4940-- This has slightly better performance than 'after'.
4942-- /Internal/
4944{-# INLINE after_ #-}
4945after_ :: (IsStream t, Monad m) => m b -> t m a -> t m a
4946after_ action xs = D.fromStreamD $ D.after_ action $ D.toStreamD xs
4948-- | Run a side effect at the end of the stream or if it is garbage collected
4949-- even before reaching the end.
4951-- @since 0.7.0
4953{-# INLINE after #-}
4954after :: (IsStream t, MonadIO m, MonadBaseControl IO m)
4955 => m b -> t m a -> t m a
4956after action xs = D.fromStreamD $ D.after action $ D.toStreamD xs
4958-- | Run a side effect whenever the stream aborts due to an exception.
4960-- @since 0.7.0
4961{-# INLINE onException #-}
4962onException :: (IsStream t, MonadCatch m) => m b -> t m a -> t m a
4963onException action xs = D.fromStreamD $ D.onException action $ D.toStreamD xs
4965-- | Run a side effect at the end of the stream or if it aborts due to an
4966-- exception before it could reach the end. The side effect is not run if the
4967-- stream is garbage collected before reaching the end.
4969-- This has slightly better performance than 'finally'.
4971-- /Internal/
4973{-# INLINE finally_ #-}
4974finally_ :: (IsStream t, MonadCatch m) => m b -> t m a -> t m a
4975finally_ action xs = D.fromStreamD $ D.finally_ action $ D.toStreamD xs
4977-- | Run a side effect at the end of the stream, or if it aborts due to an
4978-- exception or if it is garbage collected before it could reach the end.
4980-- @since 0.7.0
4982{-# INLINE finally #-}
4983finally :: (IsStream t, MonadAsync m, MonadCatch m) => m b -> t m a -> t m a
4984finally action xs = D.fromStreamD $ D.finally action $ D.toStreamD xs
4986-- | Run the first action before the stream starts and remember its output,
4987-- generate a stream using the output, run the second action using the
4988-- remembered value as an argument whenever the stream ends normally or due to
4989-- an exception. The second action won't run if the stream is garbage collected
4990-- before it could reach the end.
4992-- This has slightly better performance than 'bracket'.
4994-- /Internal/
4996{-# INLINE bracket_ #-}
4997bracket_ :: (IsStream t, MonadCatch m)
4998 => m b -> (b -> m c) -> (b -> t m a) -> t m a
4999bracket_ bef aft bet = D.fromStreamD $
5000 D.bracket_ bef aft (toStreamD . bet)
5002-- | Run the first action before the stream starts and remember its output,
5003-- generate a stream using the output, run the second action using the
5004-- remembered value as an argument whenever the stream ends normally, due to
5005-- an exception or if it is garbage collected after a partial lazy evaluation.
5007-- @since 0.7.0
5009{-# INLINE bracket #-}
5010bracket :: (IsStream t, MonadAsync m, MonadCatch m)
5011 => m b -> (b -> m c) -> (b -> t m a) -> t m a
5012bracket bef aft bet = D.fromStreamD $
5013 D.bracket bef aft (toStreamD . bet)
5015-- | When evaluating a stream if an exception occurs, stream evaluation aborts
5016-- and the specified exception handler is run with the exception as argument.
5018-- @since 0.7.0
5019{-# INLINE handle #-}
5020handle :: (IsStream t, MonadCatch m, Exception e)
5021 => (e -> t m a) -> t m a -> t m a
5022handle handler xs =
5023 D.fromStreamD $ D.handle (D.toStreamD . handler) $ D.toStreamD xs
5025-- Keep concating either streams as long as rights are generated, stop as soon
5026-- as a left is generated and concat the left stream.
5028-- See also: 'handle'
5030-- /Unimplemented/
5033concatMapEitherWith
5034 :: -- (IsStream t, MonadAsync m) =>
5035 (forall x. t m x -> t m x -> t m x)
5036 -> (a -> t m (Either (t m b) b))
5037 -> t m a
5038 -> t m b
5039concatMapEitherWith = undefined
5042------------------------------------------------------------------------------
5043-- Generalize the underlying monad
5044------------------------------------------------------------------------------
5046-- | Transform the inner monad of a stream using a natural transformation.
5048-- / Internal/
5050{-# INLINE hoist #-}
5051hoist :: (Monad m, Monad n)
5052 => (forall x. m x -> n x) -> SerialT m a -> SerialT n a
5053hoist f xs = fromStreamS $ S.hoist f (toStreamS xs)
5055-- | Generalize the inner monad of the stream from 'Identity' to any monad.
5057-- / Internal/
5059{-# INLINE generally #-}
5060generally :: (IsStream t, Monad m) => t Identity a -> t m a
5061generally xs = fromStreamS $ S.hoist (return . runIdentity) (toStreamS xs)
5063------------------------------------------------------------------------------
5064-- Add and remove a monad transformer
5065------------------------------------------------------------------------------
5067-- | Lift the inner monad @m@ of a stream @t m a@ to @tr m@ using the monad
5068-- transformer @tr@.
5070-- / Internal/
5072{-# INLINE liftInner #-}
5073liftInner :: (Monad m, IsStream t, MonadTrans tr, Monad (tr m))
5074 => t m a -> t (tr m) a
5075liftInner xs = fromStreamD $ D.liftInner (toStreamD xs)
5077------------------------------------------------------------------------------
5078-- Sharing read only state in a stream
5079------------------------------------------------------------------------------
5081-- | Evaluate the inner monad of a stream as 'ReaderT'.
5083-- / Internal/
5085{-# INLINE runReaderT #-}
5086runReaderT :: (IsStream t, Monad m) => m s -> t (ReaderT s m) a -> t m a
5087runReaderT s xs = fromStreamD $ D.runReaderT s (toStreamD xs)
5089-- | Run a stream transformation using a given environment.
5091-- See also: 'Serial.map'
5093-- / Internal/
5095{-# INLINE usingReaderT #-}
5096usingReaderT
5097 :: (Monad m, IsStream t)
5098 => m r
5099 -> (t (ReaderT r m) a -> t (ReaderT r m) a)
5100 -> t m a
5101 -> t m a
5102usingReaderT r f xs = runReaderT r $ f $ liftInner xs
5104------------------------------------------------------------------------------
5105-- Sharing read write state in a stream
5106------------------------------------------------------------------------------
5108-- | Evaluate the inner monad of a stream as 'StateT'.
5110-- This is supported only for 'SerialT' as concurrent state updation may not be
5111-- safe.
5113-- / Internal/
5115{-# INLINE evalStateT #-}
5116evalStateT :: Monad m => m s -> SerialT (StateT s m) a -> SerialT m a
5117evalStateT s xs = fromStreamD $ D.evalStateT s (toStreamD xs)
5119-- | Run a stateful (StateT) stream transformation using a given state.
5121-- This is supported only for 'SerialT' as concurrent state updation may not be
5122-- safe.
5124-- See also: 'scanl''
5126-- / Internal/
5128{-# INLINE usingStateT #-}
5129usingStateT
5130 :: Monad m
5131 => m s
5132 -> (SerialT (StateT s m) a -> SerialT (StateT s m) a)
5133 -> SerialT m a
5134 -> SerialT m a
5135usingStateT s f xs = evalStateT s $ f $ liftInner xs
5137-- | Evaluate the inner monad of a stream as 'StateT' and emit the resulting
5138-- state and value pair after each step.
5140-- This is supported only for 'SerialT' as concurrent state updation may not be
5141-- safe.
5143-- / Internal/
5145{-# INLINE runStateT #-}
5146runStateT :: Monad m => m s -> SerialT (StateT s m) a -> SerialT m (s, a)
5147runStateT s xs = fromStreamD $ D.runStateT s (toStreamD xs)