on 4e604ef help sign in
1665 lines 53 kB history raw
1-- |
2-- Module : Streamly.Internal.Data.Stream.IsStream.Transform
3-- Copyright : (c) 2017 Composewell Technologies
4-- License : BSD-3-Clause
5-- Maintainer : streamly@composewell.com
6-- Stability : experimental
7-- Portability : GHC
9module Streamly.Internal.Data.Stream.IsStream.Transform
10 (
11 -- * Piping
12 -- | Pass through a 'Pipe'.
13 transform
15 -- * Folding
16 , foldrS
17 , foldrSShared
18 , foldrT
20 -- * Mapping
21 -- | Stateless one-to-one maps.
22 , map
23 , sequence
24 , mapM
25 , smapM
27 -- * Mapping Side Effects (Observation)
28 -- | See also the intersperse*_ combinators.
29 , trace
30 , trace_
31 , tap
32 , tapOffsetEvery
33 , tapAsync
34 , tapAsyncK
35 , distributeAsync_
36 , tapRate
37 , pollCounts
39 -- * Scanning By 'Fold'
40 , scan
41 , postscan
43 -- * Scanning
44 -- | Left scans. Stateful, mostly one-to-one maps.
45 , scanl'
46 , scanlM'
47 , scanlMAfter'
48 , postscanlMAfter'
49 , postscanl'
50 , postscanlM'
51 , prescanl'
52 , prescanlM'
53 , scanl1'
54 , scanl1M'
56 -- XXX Once we have pipes the contravariant transformations can be
57 -- represented by attaching pipes before a transformation.
58 --
59 -- , lscanl'
60 -- , lscanlM'
61 -- , lscanl1'
62 -- , lscanl1M'
63 --
64 -- , lpostscanl'
65 -- , lpostscanlM'
66 -- , lprescanl'
67 -- , lprescanlM'
69 -- * Filtering
70 -- | Produce a subset of the stream using criteria based on the values of
71 -- the elements. We can use a concatMap and scan for filtering but these
72 -- combinators are more efficient and convenient.
74 , with
75 , deleteBy
76 , filter
77 , filterM
78 , uniq
79 , uniqBy
80 , nubBy
81 , nubWindowBy
82 , prune
83 , repeated
85 -- * Trimming
86 -- | Produce a subset of the stream trimmed at ends.
88 , take
89 , takeInterval
90 , takeLast
91 , takeLastInterval
92 , takeWhile
93 , takeWhileM
94 , takeWhileLast
95 , takeWhileAround
96 , drop
97 , dropInterval
98 , dropLast
99 , dropLastInterval
100 , dropWhile
101 , dropWhileM
102 , dropWhileLast
103 , dropWhileAround
105 -- * Inserting Elements
106 -- | Produce a superset of the stream. This is the opposite of
107 -- filtering/sampling. We can always use concatMap and scan for inserting
108 -- but these combinators are more efficient and convenient.
110 -- Element agnostic (Opposite of sampling)
111 , intersperse
112 , intersperseM -- XXX naming
113 , intersperseBySpan
115 , intersperseSuffix
116 , intersperseSuffixBySpan
117 , interjectSuffix
119 -- , interspersePrefix
120 -- , interspersePrefixBySpan
122 -- * Inserting Side Effects/Time
123 , intersperseM_ -- XXX naming
124 , delay
125 , intersperseSuffix_
126 , delayPost
127 , interspersePrefix_
128 , delayPre
130 -- * Element Aware Insertion
131 -- | Opposite of filtering
132 , insertBy
133 -- , intersperseByBefore
134 -- , intersperseByAfter
136 -- * Reordering
137 , reverse
138 , reverse'
139 , reassembleBy
141 -- * Position Indexing
142 , indexed
143 , indexedR
145 -- * Time Indexing
146 , timestamped
147 , timestampWith
148 -- , timestampedR -- timer
149 , timeIndexed
150 , timeIndexWith
152 -- * Searching
153 , findIndices -- XXX indicesBy
154 , elemIndices -- XXX indicesOf
156 -- * Rolling map
157 -- | Map using the previous element.
158 , rollingMapM
159 , rollingMap
160 , rollingMap2
162 -- * Maybe Streams
163 -- Move these to Streamly.Data.Maybe.Stream?
164 , catMaybes -- XXX justs (like lefts/rights)
165 , mapMaybe
166 , mapMaybeM
168 -- * Either Streams
169 -- Move these to Streamly.Data.Either.Stream?
170 , lefts
171 , rights
172 , both
174 -- * Concurrent Evaluation
175 -- ** Concurrent Pipelines
176 -- | Run streaming stages concurrently.
178 , mkAsync
179 , mkParallel
180 , applyAsync
181 , (|$)
182 , (|&)
184 -- ** Concurrency Control
185 , maxThreads
187 -- ** Buffering and Sampling
188 -- | Evaluate strictly using a buffer of results. When the buffer becomes
189 -- full we can block, drop the new elements, drop the oldest element and
190 -- insert the new at the end or keep dropping elements uniformly to match
191 -- the rate of the consumer.
192 , maxBuffer
193 , sampleOld
194 , sampleNew
195 , sampleRate
197 -- ** Rate Limiting
198 -- | Evaluate the stream at uniform intervals to maintain a specified
199 -- evaluation rate.
200 , Rate (..)
201 , rate
202 , avgRate
203 , minRate
204 , maxRate
205 , constRate
207 -- * Diagnostics
208 , inspectMode
210 -- * Deprecated
211 , scanx
212 )
213where
215#include "inline.hs"
217import Control.Concurrent (threadDelay)
218import Control.Monad (void)
219import Control.Monad.Catch (MonadCatch)
220import Control.Monad.IO.Class (MonadIO(..))
221import Control.Monad.Trans.Class (MonadTrans(..))
222import Data.Either (isLeft, isRight, fromLeft, fromRight)
223import Data.Kind (Type)
224import Data.Maybe (isJust, fromJust)
225import Streamly.Internal.Data.Fold.Type (Fold (..))
226import Streamly.Internal.Data.Pipe.Type (Pipe (..))
227import Streamly.Internal.Data.Stream.IsStream.Combinators
228 ( inspectMode, maxBuffer, maxThreads, rate, avgRate, minRate
229 , maxRate, constRate)
230import Streamly.Internal.Data.Stream.IsStream.Common
231 ( absTimesWith
232 , drop
233 , findIndices
234 , map
235 , postscanlM'
236 , relTimesWith
237 , reverse
238 , reverse'
239 , scanlMAfter'
240 , postscanlMAfter'
241 , smapM
242 , take
243 , takeWhile
244 , interjectSuffix
245 , intersperseM
246 , mkAsync
247 , mkParallel
248 , zipWith
249 )
250import Streamly.Internal.Control.Concurrent (MonadAsync)
251import Streamly.Internal.Data.Stream.IsStream.Type
252 (IsStream(..), fromStreamS, toStreamS, fromStreamD, toStreamD, toConsK)
253import Streamly.Internal.Data.Stream.Serial (SerialT)
254import Streamly.Internal.Data.SVar (Rate(..))
255import Streamly.Internal.Data.Time.Units (TimeUnit64, AbsTime, RelTime64)
257import qualified Streamly.Internal.Data.Fold as FL
258import qualified Streamly.Internal.Data.Stream.Parallel as Par
259import qualified Streamly.Internal.Data.Stream.Serial as Serial
260import qualified Streamly.Internal.Data.Stream.StreamD as D
261import qualified Streamly.Internal.Data.Stream.StreamK.Type as K
262#ifdef USE_STREAMK_ONLY
263import qualified Streamly.Internal.Data.Stream.StreamK as S
264#else
265import qualified Streamly.Internal.Data.Stream.StreamD as S
266#endif
267import qualified Prelude
269import Prelude hiding
270 ( filter, drop, dropWhile, take, takeWhile, foldr, map, mapM, sequence
271 , reverse, foldr1 , scanl, scanl1, zipWith)
273--
274-- $setup
275-- >>> :m
276-- >>> import Control.Concurrent (threadDelay)
277-- >>> import Data.Function ((&))
278-- >>> import Streamly.Prelude ((|$))
279-- >>> import Prelude hiding ( filter, drop, dropWhile, take, takeWhile, foldr, map, mapM, sequence, reverse, foldr1 , scanl, scanl1)
280-- >>> import qualified Streamly.Prelude as Stream
281-- >>> import Streamly.Internal.Data.Stream.IsStream as Stream
282-- >>> import qualified Streamly.Data.Fold as Fold
283-- >>> import qualified Streamly.Internal.Data.Fold as Fold
284-- >>> import System.IO (stdout, hSetBuffering, BufferMode(LineBuffering))
285--
286-- >>> hSetBuffering stdout LineBuffering
288------------------------------------------------------------------------------
289-- Piping
290------------------------------------------------------------------------------
292-- | Use a 'Pipe' to transform a stream.
293--
294-- /Pre-release/
295--
296{-# INLINE transform #-}
297transform :: (IsStream t, Monad m) => Pipe m a b -> t m a -> t m b
298transform pipe xs = fromStreamD $ D.transform pipe (toStreamD xs)
300------------------------------------------------------------------------------
301-- Transformation Folds
302------------------------------------------------------------------------------
304-- | Right fold to a streaming monad.
305--
306-- > foldrS Stream.cons Stream.nil === id
307--
308-- 'foldrS' can be used to perform stateless stream to stream transformations
309-- like map and filter in general. It can be coupled with a scan to perform
310-- stateful transformations. However, note that the custom map and filter
311-- routines can be much more efficient than this due to better stream fusion.
312--
313-- >>> Stream.toList $ Stream.foldrS Stream.cons Stream.nil $ Stream.fromList [1..5]
314-- [1,2,3,4,5]
315--
316-- Find if any element in the stream is 'True':
317--
318-- >>> Stream.toList $ Stream.foldrS (\x xs -> if odd x then return True else xs) (return False) $ (Stream.fromList (2:4:5:undefined) :: Stream.SerialT IO Int)
319-- [True]
320--
321-- Map (+2) on odd elements and filter out the even elements:
322--
323-- >>> Stream.toList $ Stream.foldrS (\x xs -> if odd x then (x + 2) `Stream.cons` xs else xs) Stream.nil $ (Stream.fromList [1..5] :: Stream.SerialT IO Int)
324-- [3,5,7]
325--
326-- 'foldrM' can also be represented in terms of 'foldrS', however, the former
327-- is much more efficient:
328--
329-- > foldrM f z s = runIdentityT $ foldrS (\x xs -> lift $ f x (runIdentityT xs)) (lift z) s
330--
331-- /Pre-release/
332{-# INLINE foldrS #-}
333foldrS :: IsStream t => (a -> t m b -> t m b) -> t m b -> t m a -> t m b
334foldrS f z xs =
335 fromStream
336 $ K.foldrS
337 (\y ys -> toStream $ f y (fromStream ys))
338 (toStream z)
339 (toStream xs)
341{-# INLINE foldrSShared #-}
342foldrSShared :: IsStream t => (a -> t m b -> t m b) -> t m b -> t m a -> t m b
343foldrSShared f z xs =
344 fromStream
345 $ K.foldrSShared
346 (\y ys -> toStream $ f y (fromStream ys))
347 (toStream z)
348 (toStream xs)
350-- | Right fold to a transformer monad. This is the most general right fold
351-- function. 'foldrS' is a special case of 'foldrT', however 'foldrS'
352-- implementation can be more efficient:
353--
354-- > foldrS = foldrT
355-- > foldrM f z s = runIdentityT $ foldrT (\x xs -> lift $ f x (runIdentityT xs)) (lift z) s
356--
357-- 'foldrT' can be used to translate streamly streams to other transformer
358-- monads e.g. to a different streaming type.
359--
360-- /Pre-release/
361{-# INLINE foldrT #-}
362foldrT :: (IsStream t, Monad m, Monad (s m), MonadTrans s)
363 => (a -> s m b -> s m b) -> s m b -> t m a -> s m b
364foldrT f z s = S.foldrT f z (toStreamS s)
366------------------------------------------------------------------------------
367-- Transformation by Mapping
368------------------------------------------------------------------------------
370-- |
371-- @
372-- mapM f = sequence . map f
373-- @
374--
375-- Apply a monadic function to each element of the stream and replace it with
376-- the output of the resulting action.
377--
378-- @
379-- >>> drain $ Stream.mapM putStr $ Stream.fromList ["a", "b", "c"]
380-- abc
381--
382-- >>> :{
383-- drain $ Stream.replicateM 10 (return 1)
384-- & (fromSerial . Stream.mapM (\x -> threadDelay 1000000 >> print x))
385-- :}
386-- 1
387-- ...
388-- 1
389--
390-- > drain $ Stream.replicateM 10 (return 1)
391-- & (fromAsync . Stream.mapM (\x -> threadDelay 1000000 >> print x))
392-- @
393--
394-- /Concurrent (do not use with 'fromParallel' on infinite streams)/
395--
396-- @since 0.1.0
397{-# INLINE_EARLY mapM #-}
398mapM :: forall t m a b. (IsStream t, MonadAsync m) =>
399 (a -> m b) -> t m a -> t m b
400mapM f = fromStream . K.mapMWith (toConsK (consM @t)) f . toStream
402{-# RULES "mapM serial" mapM = mapMSerial #-}
403{-# INLINE mapMSerial #-}
404mapMSerial :: Monad m => (a -> m b) -> SerialT m a -> SerialT m b
405mapMSerial = Serial.mapM
407-- |
408-- @
409-- sequence = mapM id
410-- @
411--
412-- Replace the elements of a stream of monadic actions with the outputs of
413-- those actions.
414--
415-- @
416-- >>> drain $ Stream.sequence $ Stream.fromList [putStr "a", putStr "b", putStrLn "c"]
417-- abc
418--
419-- >>> :{
420-- drain $ Stream.replicateM 3 (return $ threadDelay 1000000 >> print 1)
421-- & (fromSerial . Stream.sequence)
422-- :}
423-- 1
424-- 1
425-- 1
426--
427-- >>> :{
428-- drain $ Stream.replicateM 3 (return $ threadDelay 1000000 >> print 1)
429-- & (fromAsync . Stream.sequence)
430-- :}
431-- 1
432-- 1
433-- 1
434--
435-- @
436--
437-- /Concurrent (do not use with 'fromParallel' on infinite streams)/
438--
439-- @since 0.1.0
440{-# INLINE sequence #-}
441sequence :: (IsStream t, MonadAsync m) => t m (m a) -> t m a
442sequence = mapM id
444------------------------------------------------------------------------------
445-- Mapping side effects
446------------------------------------------------------------------------------
448-- | Tap the data flowing through a stream into a 'Fold'. For example, you may
449-- add a tap to log the contents flowing through the stream. The fold is used
450-- only for effects, its result is discarded.
451--
452-- @
453-- Fold m a b
454-- |
455-- -----stream m a ---------------stream m a-----
456--
457-- @
458--
459-- >>> Stream.drain $ Stream.tap (Fold.drainBy print) (Stream.enumerateFromTo 1 2)
460-- 1
461-- 2
462--
463-- Compare with 'trace'.
464--
465-- @since 0.7.0
466{-# INLINE tap #-}
467tap :: (IsStream t, Monad m) => FL.Fold m a b -> t m a -> t m a
468tap f xs = fromStreamD $ D.tap f (toStreamD xs)
470-- XXX Remove this. It can be expressed in terms of Fold.sampleFromThen.
471--
472-- | @tapOffsetEvery offset n@ taps every @n@th element in the stream
473-- starting at @offset@. @offset@ can be between @0@ and @n - 1@. Offset 0
474-- means start at the first element in the stream. If the offset is outside
475-- this range then @offset `mod` n@ is used as offset.
476--
477-- >>> Stream.drain $ Stream.tapOffsetEvery 0 2 (Fold.rmapM print Fold.toList) $ Stream.enumerateFromTo 0 10
478-- [0,2,4,6,8,10]
480--
481-- /Pre-release/
482--
483{-# INLINE tapOffsetEvery #-}
484tapOffsetEvery :: (IsStream t, Monad m)
485 => Int -> Int -> FL.Fold m a b -> t m a -> t m a
486tapOffsetEvery offset n f xs =
487 fromStreamD $ D.tapOffsetEvery offset n f (toStreamD xs)
489-- | Redirect a copy of the stream to a supplied fold and run it concurrently
490-- in an independent thread. The fold may buffer some elements. The buffer size
491-- is determined by the prevailing 'maxBuffer' setting.
492--
493-- @
494-- Stream m a -> m b
495-- |
496-- -----stream m a ---------------stream m a-----
497--
498-- @
499--
500-- @
501-- >>> Stream.drain $ Stream.tapAsync (Fold.drainBy print) (Stream.enumerateFromTo 1 2)
502-- 1
503-- 2
504--
505-- @
506--
507-- Exceptions from the concurrently running fold are propagated to the current
508-- computation. Note that, because of buffering in the fold, exceptions may be
509-- delayed and may not correspond to the current element being processed in the
510-- parent stream, but we guarantee that before the parent stream stops the tap
511-- finishes and all exceptions from it are drained.
512--
513-- >>> tapAsync f = Stream.tapAsyncK (Stream.fold f . Stream.adapt)
514--
515-- Compare with 'tap'.
516--
517-- /Pre-release/
518{-# INLINE tapAsync #-}
519tapAsync :: (IsStream t, MonadAsync m) => FL.Fold m a b -> t m a -> t m a
520tapAsync f xs = fromStreamD $ Par.tapAsyncF f (toStreamD xs)
522-- XXX We should keep only tapAsyncK as tapAsync can be implemented in terms
523-- of tapAsyncK and it has better performance. Rename this to tapAsync.
525-- | Like 'tapAsyncF' but uses a stream fold function instead of a 'Fold' type.
526--
527-- /Pre-release/
528{-# INLINE tapAsyncK #-}
529tapAsyncK :: (IsStream t, MonadAsync m) => (t m a -> m b) -> t m a -> t m a
530tapAsyncK f m = fromStream $ Par.tapAsyncK (f . fromStream) (toStream m)
532-- XXX rename this to tapManyAsync_?
533--
534-- | Concurrently distribute a stream to a collection of fold functions,
535-- discarding the outputs of the folds.
536--
537-- @
538-- > Stream.drain $ Stream.distributeAsync_ [Stream.mapM_ print, Stream.mapM_ print] (Stream.enumerateFromTo 1 2)
539-- 1
540-- 2
541-- 1
542-- 2
543--
544-- @
545--
546-- @
547-- distributeAsync_ = flip (foldr tapAsync)
548-- @
549--
550-- /Pre-release/
551--
552{-# INLINE distributeAsync_ #-}
553distributeAsync_ :: (Foldable f, IsStream t, MonadAsync m)
554 => f (t m a -> m b) -> t m a -> t m a
555distributeAsync_ = flip (Prelude.foldr tapAsyncK)
557-- | @pollCounts predicate transform fold stream@ counts those elements in the
558-- stream that pass the @predicate@. The resulting count stream is sent to
559-- another thread which transforms it using @transform@ and then folds it using
560-- @fold@. The thread is automatically cleaned up if the stream stops or
561-- aborts due to exception.
562--
563-- For example, to print the count of elements processed every second:
564--
565-- @
566-- > Stream.drain $ Stream.pollCounts (const True) (Stream.rollingMap (-) . Stream.delayPost 1) (FLold.drainBy print)
567-- $ Stream.enumerateFrom 0
568-- @
569--
570-- Note: This may not work correctly on 32-bit machines.
571--
572-- /Pre-release/
573--
574{-# INLINE pollCounts #-}
575pollCounts ::
576 (IsStream t, MonadAsync m)
577 => (a -> Bool)
578 -> (t m Int -> t m Int)
579 -> Fold m Int b
580 -> t m a
581 -> t m a
582pollCounts predicate transf f xs =
583 fromStreamD
584 $ D.pollCounts predicate (toStreamD . transf . fromStreamD) f
585 $ toStreamD xs
587-- | Calls the supplied function with the number of elements consumed
588-- every @n@ seconds. The given function is run in a separate thread
589-- until the end of the stream. In case there is an exception in the
590-- stream the thread is killed during the next major GC.
591--
592-- Note: The action is not guaranteed to run if the main thread exits.
593--
594-- @
595-- > delay n = threadDelay (round $ n * 1000000) >> return n
596-- > Stream.toList $ Stream.tapRate 2 (\n -> print $ show n ++ " elements processed") (delay 1 Stream.|: delay 0.5 Stream.|: delay 0.5 Stream.|: Stream.nil)
597-- "2 elements processed"
598-- [1.0,0.5,0.5]
599-- "1 elements processed"
600-- @
601--
602-- Note: This may not work correctly on 32-bit machines.
603--
604-- /Pre-release/
605{-# INLINE tapRate #-}
606tapRate ::
607 (IsStream t, MonadAsync m, MonadCatch m)
608 => Double
609 -> (Int -> m b)
610 -> t m a
611 -> t m a
612tapRate n f xs = fromStreamD $ D.tapRate n f $ toStreamD xs
614-- | Apply a monadic function to each element flowing through the stream and
615-- discard the results.
616--
617-- @
618-- >>> Stream.drain $ Stream.trace print (Stream.enumerateFromTo 1 2)
619-- 1
620-- 2
621--
622-- @
623--
624-- Compare with 'tap'.
625--
626-- @since 0.7.0
627{-# INLINE trace #-}
628trace :: (IsStream t, MonadAsync m) => (a -> m b) -> t m a -> t m a
629trace f = mapM (\x -> void (f x) >> return x)
631-- | Perform a side effect before yielding each element of the stream and
632-- discard the results.
633--
634-- @
635-- >>> Stream.drain $ Stream.trace_ (print "got here") (Stream.enumerateFromTo 1 2)
636-- "got here"
637-- "got here"
638--
639-- @
640--
641-- Same as 'interspersePrefix_' but always serial.
642--
643-- See also: 'trace'
644--
645-- /Pre-release/
646{-# INLINE trace_ #-}
647trace_ :: (IsStream t, Monad m) => m b -> t m a -> t m a
648trace_ eff = fromStreamD . D.mapM (\x -> eff >> return x) . toStreamD
650------------------------------------------------------------------------------
651-- Scanning with a Fold
652------------------------------------------------------------------------------
654-- | Scan a stream using the given monadic fold.
655--
656-- >>> Stream.toList $ Stream.takeWhile (< 10) $ Stream.scan Fold.sum (Stream.fromList [1..10])
657-- [0,1,3,6]
658--
659-- @since 0.7.0
660{-# INLINE scan #-}
661scan :: (IsStream t, Monad m) => Fold m a b -> t m a -> t m b
662-- scan = P.scanOnce
663scan fld m = fromStreamD $ D.scanOnce fld $ toStreamD m
665-- | Postscan a stream using the given monadic fold.
666--
667-- The following example extracts the input stream up to a point where the
668-- running average of elements is no more than 10:
669--
670-- >>> import Data.Maybe (fromJust)
671-- >>> let avg = Fold.teeWith (/) Fold.sum (fmap fromIntegral Fold.length)
672-- >>> :{
673-- Stream.toList
674-- $ Stream.map (fromJust . fst)
675-- $ Stream.takeWhile (\(_,x) -> x <= 10)
676-- $ Stream.postscan (Fold.tee Fold.last avg) (Stream.enumerateFromTo 1.0 100.0)
677-- :}
678-- [1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0,11.0,12.0,13.0,14.0,15.0,16.0,17.0,18.0,19.0]
679--
680-- @since 0.7.0
681{-# INLINE postscan #-}
682postscan :: (IsStream t, Monad m) => Fold m a b -> t m a -> t m b
683postscan fld = fromStreamD . D.postscanOnce fld . toStreamD
685------------------------------------------------------------------------------
686-- Scanning - Transformation by Folding
687------------------------------------------------------------------------------
689-- XXX It may be useful to have a version of scan where we can keep the
690-- accumulator independent of the value emitted. So that we do not necessarily
691-- have to keep a value in the accumulator which we are not using. We can pass
692-- an extraction function that will take the accumulator and the current value
693-- of the element and emit the next value in the stream. That will also make it
694-- possible to modify the accumulator after using it. In fact, the step function
695-- can return new accumulator and the value to be emitted. The signature would
696-- be more like mapAccumL. Or we can change the signature of scanx to
697-- accommodate this.
698--
699-- | Strict left scan with an extraction function. Like 'scanl'', but applies a
700-- user supplied extraction function (the third argument) at each step. This is
701-- designed to work with the @foldl@ library. The suffix @x@ is a mnemonic for
702-- extraction.
703--
704-- /Since 0.2.0/
705--
706-- /Since: 0.7.0 (Monad m constraint)/
707{-# DEPRECATED scanx "Please use scanl followed by map instead." #-}
708{-# INLINE scanx #-}
709scanx :: (IsStream t, Monad m) => (x -> a -> x) -> x -> (x -> b) -> t m a -> t m b
710scanx step begin done = fromStreamS . S.scanlx' step begin done . toStreamS
712-- XXX this needs to be concurrent
713-- XXX because of the use of D.cons for appending, scanlM' has quadratic
714-- complexity when iterated over a stream. We should use StreamK style scanlM'
715-- for linear performance on iteration.
716--
717-- | Like 'scanl'' but with a monadic step function and a monadic seed.
718--
719-- /Since: 0.4.0/
720--
721-- /Since: 0.8.0 (signature change)/
722{-# INLINE scanlM' #-}
723scanlM' :: (IsStream t, Monad m) => (b -> a -> m b) -> m b -> t m a -> t m b
724scanlM' step begin m = fromStreamD $ D.scanlM' step begin $ toStreamD m
726-- XXX because of the use of D.cons for appending, scanl' has quadratic
727-- complexity when iterated over a stream. We should use StreamK style scanlM'
728-- for linear performance on iteration.
730-- | Strict left scan. Like 'map', 'scanl'' too is a one to one transformation,
731-- however it adds an extra element.
732--
733-- @
734-- >>> Stream.toList $ Stream.scanl' (+) 0 $ fromList [1,2,3,4]
735-- [0,1,3,6,10]
736--
737-- @
738--
739-- @
740-- >>> Stream.toList $ Stream.scanl' (flip (:)) [] $ Stream.fromList [1,2,3,4]
741-- [[],[1],[2,1],[3,2,1],[4,3,2,1]]
742--
743-- @
744--
745-- The output of 'scanl'' is the initial value of the accumulator followed by
746-- all the intermediate steps and the final result of 'foldl''.
747--
748-- By streaming the accumulated state after each fold step, we can share the
749-- state across multiple stages of stream composition. Each stage can modify or
750-- extend the state, do some processing with it and emit it for the next stage,
751-- thus modularizing the stream processing. This can be useful in
752-- stateful or event-driven programming.
753--
754-- Consider the following monolithic example, computing the sum and the product
755-- of the elements in a stream in one go using a @foldl'@:
756--
757-- @
758-- >>> Stream.foldl' (\(s, p) x -> (s + x, p * x)) (0,1) $ Stream.fromList [1,2,3,4]
759-- (10,24)
760--
761-- @
762--
763-- Using @scanl'@ we can make it modular by computing the sum in the first
764-- stage and passing it down to the next stage for computing the product:
765--
766-- @
767-- >>> :{
768-- Stream.foldl' (\(_, p) (s, x) -> (s, p * x)) (0,1)
769-- $ Stream.scanl' (\(s, _) x -> (s + x, x)) (0,1)
770-- $ Stream.fromList [1,2,3,4]
771-- :}
772-- (10,24)
773--
774-- @
775--
776-- IMPORTANT: 'scanl'' evaluates the accumulator to WHNF. To avoid building
777-- lazy expressions inside the accumulator, it is recommended that a strict
778-- data structure is used for accumulator.
779--
780-- >>> scanl' step z = scan (Fold.foldl' step z)
781-- >>> scanl' f z xs = scanlM' (\a b -> return (f a b)) (return z) xs
782-- >>> scanl' f z xs = z `Stream.cons` postscanl' f z xs
783--
784-- See also: 'usingStateT'
785--
786-- @since 0.2.0
787{-# INLINE scanl' #-}
788scanl' :: (IsStream t, Monad m) => (b -> a -> b) -> b -> t m a -> t m b
789scanl' step z m = fromStreamS $ S.scanl' step z $ toStreamS m
791-- | Like 'scanl'' but does not stream the initial value of the accumulator.
792--
793-- >>> postscanl' step z = postscan (Fold.foldl' step z)
794-- >>> postscanl' f z = postscanlM' (\a b -> return (f a b)) (return z)
795-- >>> postscanl' f z xs = Stream.drop 1 $ Stream.scanl' f z xs
796--
797-- @since 0.7.0
798{-# INLINE postscanl' #-}
799postscanl' :: (IsStream t, Monad m) => (b -> a -> b) -> b -> t m a -> t m b
800postscanl' step z m = fromStreamD $ D.postscanl' step z $ toStreamD m
802-- XXX prescanl does not sound very useful, enable only if there is a
803-- compelling use case.
804--
805-- | Like scanl' but does not stream the final value of the accumulator.
806--
807-- /Pre-release/
808{-# INLINE prescanl' #-}
809prescanl' :: (IsStream t, Monad m) => (b -> a -> b) -> b -> t m a -> t m b
810prescanl' step z m = fromStreamD $ D.prescanl' step z $ toStreamD m
812-- XXX this needs to be concurrent
813-- | Like prescanl' but with a monadic step function and a monadic seed.
814--
815-- /Pre-release/
816{-# INLINE prescanlM' #-}
817prescanlM' :: (IsStream t, Monad m) => (b -> a -> m b) -> m b -> t m a -> t m b
818prescanlM' step z m = fromStreamD $ D.prescanlM' step z $ toStreamD m
820-- XXX this needs to be concurrent
821-- | Like 'scanl1'' but with a monadic step function.
822--
823-- @since 0.6.0
824{-# INLINE scanl1M' #-}
825scanl1M' :: (IsStream t, Monad m) => (a -> a -> m a) -> t m a -> t m a
826scanl1M' step m = fromStreamD $ D.scanl1M' step $ toStreamD m
828-- | Like 'scanl'' but for a non-empty stream. The first element of the stream
829-- is used as the initial value of the accumulator. Does nothing if the stream
830-- is empty.
831--
832-- @
833-- >>> Stream.toList $ Stream.scanl1' (+) $ fromList [1,2,3,4]
834-- [1,3,6,10]
835--
836-- @
837--
838-- @since 0.6.0
839{-# INLINE scanl1' #-}
840scanl1' :: (IsStream t, Monad m) => (a -> a -> a) -> t m a -> t m a
841scanl1' step m = fromStreamD $ D.scanl1' step $ toStreamD m
843------------------------------------------------------------------------------
844-- Filtering
845------------------------------------------------------------------------------
847-- | Modify a @t m a -> t m a@ stream transformation that accepts a predicate
848-- @(a -> b)@ to accept @((s, a) -> b)@ instead, provided a transformation @t m
849-- a -> t m (s, a)@. Convenient to filter with index or time.
850--
851-- @
852-- filterWithIndex = with indexed filter
853-- filterWithAbsTime = with timestamped filter
854-- filterWithRelTime = with timeIndexed filter
855-- @
856--
857-- /Pre-release/
858{-# INLINE with #-}
859with :: forall (t :: (Type -> Type) -> Type -> Type) m a b s. Functor (t m) =>
860 (t m a -> t m (s, a))
861 -> (((s, a) -> b) -> t m (s, a) -> t m (s, a))
862 -> (((s, a) -> b) -> t m a -> t m a)
863with f comb g = fmap snd . comb g . f
865-- | Include only those elements that pass a predicate.
866--
867-- @since 0.1.0
868{-# INLINE filter #-}
869filter :: (IsStream t, Monad m) => (a -> Bool) -> t m a -> t m a
870filter p m = fromStreamS $ S.filter p $ toStreamS m
872-- | Same as 'filter' but with a monadic predicate.
873--
874-- @since 0.4.0
875{-# INLINE filterM #-}
876filterM :: (IsStream t, Monad m) => (a -> m Bool) -> t m a -> t m a
877filterM p m = fromStreamD $ D.filterM p $ toStreamD m
879-- | Drop repeated elements that are adjacent to each other using the supplied
880-- comparison function.
881--
882-- @uniq = uniqBy (==)
883--
884-- To strip duplicate path separators:
885--
886-- @
887-- f x y = x == '/' && x == y
888-- Stream.toList $ Stream.uniqBy f $ Stream.fromList "//a//b"
889-- "/a/b"
890-- @
891--
892-- Space: @O(1)@
893--
894-- See also: 'nubBy'.
895--
896-- /Pre-release/
897--
898{-# INLINE uniqBy #-}
899uniqBy :: (IsStream t, Monad m, Functor (t m)) =>
900 (a -> a -> Bool) -> t m a -> t m a
901uniqBy eq = catMaybes . rollingMap f
903 where
905 f pre curr =
906 case pre of
907 Nothing -> Just curr
908 Just x -> if x `eq` curr then Nothing else Just curr
910-- | Drop repeated elements that are adjacent to each other.
911--
912-- @since 0.6.0
913{-# INLINE uniq #-}
914uniq :: (Eq a, IsStream t, Monad m) => t m a -> t m a
915uniq = fromStreamD . D.uniq . toStreamD
917-- | Strip all leading and trailing occurrences of an element passing a
918-- predicate and make all other consecutive occurrences uniq.
919--
920-- @
921-- prune p = dropWhileAround p $ uniqBy (x y -> p x && p y)
922-- @
923--
924-- @
925-- > Stream.prune isSpace (Stream.fromList " hello world! ")
926-- "hello world!"
927--
928-- @
929--
930-- Space: @O(1)@
931--
932-- /Unimplemented/
933{-# INLINE prune #-}
934prune ::
935 -- (IsStream t, Monad m, Eq a) =>
936 (a -> Bool) -> t m a -> t m a
937prune = error "Not implemented yet!"
939-- Possible implementation:
940-- @repeated =
941-- Stream.catMaybes . Stream.parseMany (Parser.groupBy (==) Fold.repeated)@
942--
943-- 'Fold.repeated' should return 'Just' when repeated, and 'Nothing' for a
944-- single element.
945--
946-- | Emit only repeated elements, once.
947--
948-- /Unimplemented/
949repeated :: -- (IsStream t, Monad m, Eq a) =>
950 t m a -> t m a
951repeated = undefined
953-- We can have more efficient implementations for nubOrd and nubInt by using
954-- Set and IntSet to find/remove duplication. For Hashable we can use a
955-- hashmap. Use rewrite rules to specialize to more efficient impls.
956--
957-- | Drop repeated elements anywhere in the stream.
958--
959-- /Caution: not scalable for infinite streams/
960--
961-- /See also: nubWindowBy/
962--
963-- /Unimplemented/
964--
965{-# INLINE nubBy #-}
966nubBy :: -- (IsStream t, Monad m) =>
967 (a -> a -> Bool) -> t m a -> t m a
968nubBy = undefined -- fromStreamD . D.nubBy . toStreamD
970-- | Drop repeated elements within the specified tumbling window in the stream.
971--
972-- @nubBy = nubWindowBy maxBound@
973--
974-- /Unimplemented/
975--
976{-# INLINE nubWindowBy #-}
977nubWindowBy :: -- (IsStream t, Monad m) =>
978 Int -> (a -> a -> Bool) -> t m a -> t m a
979nubWindowBy = undefined -- fromStreamD . D.nubWithinBy . toStreamD
981-- | Deletes the first occurrence of the element in the stream that satisfies
982-- the given equality predicate.
983--
984-- @
985-- >>> Stream.toList $ Stream.deleteBy (==) 3 $ Stream.fromList [1,3,3,5]
986-- [1,3,5]
987--
988-- @
989--
990-- @since 0.6.0
991{-# INLINE deleteBy #-}
992deleteBy :: (IsStream t, Monad m) => (a -> a -> Bool) -> a -> t m a -> t m a
993deleteBy cmp x m = fromStreamS $ S.deleteBy cmp x (toStreamS m)
995------------------------------------------------------------------------------
996-- Lossy Buffering
997------------------------------------------------------------------------------
999-- XXX We could use 'maxBuffer Block/Drop/Rotate/Sample' instead. However we
1000-- may want to have the evaluation rate independent of the sampling rate. To
1001-- support that we can decouple evaluation and sampling in independent stages.
1002-- The sampling stage would strictly evaluate and sample, the evaluation stage
1003-- would control the evaluation rate.
1005-- | Evaluate the input stream continuously and keep only the oldest @n@
1006-- elements in the buffer, discard the new ones when the buffer is full. When
1007-- the output stream is evaluated it consumes the values from the buffer in a
1008-- FIFO manner.
1010-- /Unimplemented/
1012{-# INLINE sampleOld #-}
1013sampleOld :: -- (IsStream t, Monad m) =>
1014 Int -> t m a -> t m a
1015sampleOld = undefined
1017-- | Evaluate the input stream continuously and keep only the latest @n@
1018-- elements in a ring buffer, keep discarding the older ones to make space for
1019-- the new ones. When the output stream is evaluated it consumes the values
1020-- from the buffer in a FIFO manner.
1022-- /Unimplemented/
1024{-# INLINE sampleNew #-}
1025sampleNew :: -- (IsStream t, Monad m) =>
1026 Int -> t m a -> t m a
1027sampleNew = undefined
1029-- | Like 'sampleNew' but samples at uniform intervals to match the consumer
1030-- rate. Note that 'sampleNew' leads to non-uniform sampling depending on the
1031-- consumer pattern.
1033-- /Unimplemented/
1035{-# INLINE sampleRate #-}
1036sampleRate :: -- (IsStream t, Monad m) =>
1037 Double -> t m a -> t m a
1038sampleRate = undefined
1040------------------------------------------------------------------------------
1041-- Trimming
1042------------------------------------------------------------------------------
1044-- | Same as 'takeWhile' but with a monadic predicate.
1046-- @since 0.4.0
1047{-# INLINE takeWhileM #-}
1048takeWhileM :: (IsStream t, Monad m) => (a -> m Bool) -> t m a -> t m a
1049takeWhileM p m = fromStreamD $ D.takeWhileM p $ toStreamD m
1051-- See the lastN fold for impl hints. Use a Data.Array based ring buffer.
1053-- takeLast n = Stream.concatM . fmap Array.toStream . fold Fold.lastN
1055-- | Take @n@ elements at the end of the stream.
1057-- O(n) space, where n is the number elements taken.
1059-- /Unimplemented/
1060{-# INLINE takeLast #-}
1061takeLast :: -- (IsStream t, Monad m) =>
1062 Int -> t m a -> t m a
1063takeLast = undefined -- fromStreamD $ D.takeLast n $ toStreamD m
1065-- | Take time interval @i@ seconds at the end of the stream.
1067-- O(n) space, where n is the number elements taken.
1069-- /Unimplemented/
1070{-# INLINE takeLastInterval #-}
1071takeLastInterval :: -- (IsStream t, Monad m) =>
1072 Double -> t m a -> t m a
1073takeLastInterval = undefined -- fromStreamD $ D.takeLast n $ toStreamD m
1075-- | Take all consecutive elements at the end of the stream for which the
1076-- predicate is true.
1078-- O(n) space, where n is the number elements taken.
1080-- /Unimplemented/
1081{-# INLINE takeWhileLast #-}
1082takeWhileLast :: -- (IsStream t, Monad m) =>
1083 (a -> Bool) -> t m a -> t m a
1084takeWhileLast = undefined -- fromStreamD $ D.takeWhileLast n $ toStreamD m
1086-- | Like 'takeWhile' and 'takeWhileLast' combined.
1088-- O(n) space, where n is the number elements taken from the end.
1090-- /Unimplemented/
1091{-# INLINE takeWhileAround #-}
1092takeWhileAround :: -- (IsStream t, Monad m) =>
1093 (a -> Bool) -> t m a -> t m a
1094takeWhileAround = undefined -- fromStreamD $ D.takeWhileAround n $ toStreamD m
1096-- | @takeInterval duration@ yields stream elements upto specified time
1097-- @duration@. The duration starts when the stream is evaluated for the first
1098-- time, before the first element is yielded. The time duration is checked
1099-- before generating each element, if the duration has expired the stream
1100-- stops.
1102-- The total time taken in executing the stream is guaranteed to be /at least/
1103-- @duration@, however, because the duration is checked before generating an
1104-- element, the upper bound is indeterminate and depends on the time taken in
1105-- generating and processing the last element.
1107-- No element is yielded if the duration is zero. At least one element is
1108-- yielded if the duration is non-zero.
1110-- /Pre-release/
1112{-# INLINE takeInterval #-}
1113takeInterval ::(MonadIO m, IsStream t, TimeUnit64 d) => d -> t m a -> t m a
1114takeInterval d = fromStreamD . D.takeByTime d . toStreamD
1116-- | Drop elements in the stream as long as the predicate succeeds and then
1117-- take the rest of the stream.
1119-- @since 0.1.0
1120{-# INLINE dropWhile #-}
1121dropWhile :: (IsStream t, Monad m) => (a -> Bool) -> t m a -> t m a
1122dropWhile p m = fromStreamS $ S.dropWhile p $ toStreamS m
1124-- | Same as 'dropWhile' but with a monadic predicate.
1126-- @since 0.4.0
1127{-# INLINE dropWhileM #-}
1128dropWhileM :: (IsStream t, Monad m) => (a -> m Bool) -> t m a -> t m a
1129dropWhileM p m = fromStreamD $ D.dropWhileM p $ toStreamD m
1131-- | @dropInterval duration@ drops stream elements until specified @duration@ has
1132-- passed. The duration begins when the stream is evaluated for the first
1133-- time. The time duration is checked /after/ generating a stream element, the
1134-- element is yielded if the duration has expired otherwise it is dropped.
1136-- The time elapsed before starting to generate the first element is /at most/
1137-- @duration@, however, because the duration expiry is checked after the
1138-- element is generated, the lower bound is indeterminate and depends on the
1139-- time taken in generating an element.
1141-- All elements are yielded if the duration is zero.
1143-- /Pre-release/
1145{-# INLINE dropInterval #-}
1146dropInterval ::(MonadIO m, IsStream t, TimeUnit64 d) => d -> t m a -> t m a
1147dropInterval d = fromStreamD . D.dropByTime d . toStreamD
1149-- | Drop @n@ elements at the end of the stream.
1151-- O(n) space, where n is the number elements dropped.
1153-- /Unimplemented/
1154{-# INLINE dropLast #-}
1155dropLast :: -- (IsStream t, Monad m) =>
1156 Int -> t m a -> t m a
1157dropLast = undefined -- fromStreamD $ D.dropLast n $ toStreamD m
1159-- | Drop time interval @i@ seconds at the end of the stream.
1161-- O(n) space, where n is the number elements dropped.
1163-- /Unimplemented/
1164{-# INLINE dropLastInterval #-}
1165dropLastInterval :: -- (IsStream t, Monad m) =>
1166 Int -> t m a -> t m a
1167dropLastInterval = undefined
1169-- | Drop all consecutive elements at the end of the stream for which the
1170-- predicate is true.
1172-- O(n) space, where n is the number elements dropped.
1174-- /Unimplemented/
1175{-# INLINE dropWhileLast #-}
1176dropWhileLast :: -- (IsStream t, Monad m) =>
1177 (a -> Bool) -> t m a -> t m a
1178dropWhileLast = undefined -- fromStreamD $ D.dropWhileLast n $ toStreamD m
1180-- | Like 'dropWhile' and 'dropWhileLast' combined.
1182-- O(n) space, where n is the number elements dropped from the end.
1184-- /Unimplemented/
1185{-# INLINE dropWhileAround #-}
1186dropWhileAround :: -- (IsStream t, Monad m) =>
1187 (a -> Bool) -> t m a -> t m a
1188dropWhileAround = undefined -- fromStreamD $ D.dropWhileAround n $ toStreamD m
1190------------------------------------------------------------------------------
1191-- Inserting Elements
1192------------------------------------------------------------------------------
1194-- | @insertBy cmp elem stream@ inserts @elem@ before the first element in
1195-- @stream@ that is less than @elem@ when compared using @cmp@.
1197-- @
1198-- insertBy cmp x = 'mergeBy' cmp ('fromPure' x)
1199-- @
1201-- @
1202-- >>> Stream.toList $ Stream.insertBy compare 2 $ Stream.fromList [1,3,5]
1203-- [1,2,3,5]
1205-- @
1207-- @since 0.6.0
1208{-# INLINE insertBy #-}
1209insertBy ::
1210 (IsStream t, Monad m) => (a -> a -> Ordering) -> a -> t m a -> t m a
1211insertBy cmp x m = fromStreamS $ S.insertBy cmp x (toStreamS m)
1213-- | Insert a pure value between successive elements of a stream.
1215-- >>> Stream.toList $ Stream.intersperse ',' $ Stream.fromList "hello"
1216-- "h,e,l,l,o"
1218-- @since 0.7.0
1219{-# INLINE intersperse #-}
1220intersperse :: (IsStream t, MonadAsync m) => a -> t m a -> t m a
1221intersperse a = fromStreamS . S.intersperse a . toStreamS
1223-- | Insert a side effect before consuming an element of a stream except the
1224-- first one.
1226-- >>> Stream.drain $ Stream.trace putChar $ Stream.intersperseM_ (putChar '.') $ Stream.fromList "hello"
1227-- h.e.l.l.o
1229-- /Pre-release/
1230{-# INLINE intersperseM_ #-}
1231intersperseM_ :: (IsStream t, Monad m) => m b -> t m a -> t m a
1232intersperseM_ m = fromStreamD . D.intersperseM_ m . toStreamD
1234-- | Intersperse a monadic action into the input stream after every @n@
1235-- elements.
1237-- @
1238-- > Stream.toList $ Stream.intersperseBySpan 2 (return ',') $ Stream.fromList "hello"
1239-- "he,ll,o"
1241-- @
1243-- /Unimplemented/
1244{-# INLINE intersperseBySpan #-}
1245intersperseBySpan :: -- IsStream t =>
1246 Int -> m a -> t m a -> t m a
1247intersperseBySpan _n _f _xs = undefined
1249-- | Insert an effect and its output after consuming an element of a stream.
1251-- >>> Stream.toList $ Stream.trace putChar $ intersperseSuffix (putChar '.' >> return ',') $ Stream.fromList "hello"
1252-- h.,e.,l.,l.,o.,"h,e,l,l,o,"
1254-- /Pre-release/
1255{-# INLINE intersperseSuffix #-}
1256intersperseSuffix :: (IsStream t, Monad m) => m a -> t m a -> t m a
1257intersperseSuffix m = fromStreamD . D.intersperseSuffix m . toStreamD
1259-- | Insert a side effect after consuming an element of a stream.
1261-- @
1262-- >>> Stream.mapM_ putChar $ Stream.intersperseSuffix_ (threadDelay 1000000) $ Stream.fromList "hello"
1263-- hello
1265-- @
1267-- /Pre-release/
1269{-# INLINE intersperseSuffix_ #-}
1270intersperseSuffix_ :: (IsStream t, Monad m) => m b -> t m a -> t m a
1271intersperseSuffix_ m = fromStreamD . D.intersperseSuffix_ m . toStreamD
1273-- XXX Use an offset argument, like tapOffsetEvery
1275-- | Like 'intersperseSuffix' but intersperses an effectful action into the
1276-- input stream after every @n@ elements and after the last element.
1278-- >>> Stream.toList $ Stream.intersperseSuffixBySpan 2 (return ',') $ Stream.fromList "hello"
1279-- "he,ll,o,"
1281-- /Pre-release/
1283{-# INLINE intersperseSuffixBySpan #-}
1284intersperseSuffixBySpan :: (IsStream t, Monad m)
1285 => Int -> m a -> t m a -> t m a
1286intersperseSuffixBySpan n eff =
1287 fromStreamD . D.intersperseSuffixBySpan n eff . toStreamD
1289-- | Insert a side effect before consuming an element of a stream.
1291-- >>> Stream.toList $ Stream.trace putChar $ Stream.interspersePrefix_ (putChar '.' >> return ',') $ Stream.fromList "hello"
1292-- .h.e.l.l.o"hello"
1294-- Same as 'trace_' but may be concurrent.
1296-- /Concurrent/
1298-- /Pre-release/
1300{-# INLINE interspersePrefix_ #-}
1301interspersePrefix_ :: (IsStream t, MonadAsync m) => m b -> t m a -> t m a
1302interspersePrefix_ m = mapM (\x -> void m >> return x)
1304------------------------------------------------------------------------------
1305-- Inserting Time
1306------------------------------------------------------------------------------
1308-- Note: delay must be serial.
1310-- | Introduce a delay of specified seconds before consuming an element of the
1311-- stream except the first one.
1313-- >>> Stream.mapM_ print $ Stream.timestamped $ Stream.delay 1 $ Stream.enumerateFromTo 1 3
1314-- (AbsTime (TimeSpec {sec = ..., nsec = ...}),1)
1315-- (AbsTime (TimeSpec {sec = ..., nsec = ...}),2)
1316-- (AbsTime (TimeSpec {sec = ..., nsec = ...}),3)
1318-- @since 0.8.0
1320{-# INLINE delay #-}
1321delay :: (IsStream t, MonadIO m) => Double -> t m a -> t m a
1322delay n = intersperseM_ $ liftIO $ threadDelay $ round $ n * 1000000
1324-- Note: delay must be serial.
1326-- | Introduce a delay of specified seconds after consuming an element of a
1327-- stream.
1329-- >>> Stream.mapM_ print $ Stream.timestamped $ Stream.delayPost 1 $ Stream.enumerateFromTo 1 3
1330-- (AbsTime (TimeSpec {sec = ..., nsec = ...}),1)
1331-- (AbsTime (TimeSpec {sec = ..., nsec = ...}),2)
1332-- (AbsTime (TimeSpec {sec = ..., nsec = ...}),3)
1334-- /Pre-release/
1336{-# INLINE delayPost #-}
1337delayPost :: (IsStream t, MonadIO m) => Double -> t m a -> t m a
1338delayPost n = intersperseSuffix_ $ liftIO $ threadDelay $ round $ n * 1000000
1340-- Note: delay must be serial, that's why 'trace_' is used.
1342-- | Introduce a delay of specified seconds before consuming an element of a
1343-- stream.
1345-- >>> Stream.mapM_ print $ Stream.timestamped $ Stream.delayPre 1 $ Stream.enumerateFromTo 1 3
1346-- (AbsTime (TimeSpec {sec = ..., nsec = ...}),1)
1347-- (AbsTime (TimeSpec {sec = ..., nsec = ...}),2)
1348-- (AbsTime (TimeSpec {sec = ..., nsec = ...}),3)
1350-- /Pre-release/
1352{-# INLINE delayPre #-}
1353delayPre :: (IsStream t, MonadIO m) => Double -> t m a -> t m a
1354delayPre n = trace_ $ liftIO $ threadDelay $ round $ n * 1000000
1356------------------------------------------------------------------------------
1357-- Reorder in sequence
1358------------------------------------------------------------------------------
1360-- | Buffer until the next element in sequence arrives. The function argument
1361-- determines the difference in sequence numbers. This could be useful in
1362-- implementing sequenced streams, for example, TCP reassembly.
1364-- /Unimplemented/
1366{-# INLINE reassembleBy #-}
1367reassembleBy
1368 :: -- (IsStream t, Monad m) =>
1369 Fold m a b
1370 -> (a -> a -> Int)
1371 -> t m a
1372 -> t m b
1373reassembleBy = undefined
1375------------------------------------------------------------------------------
1376-- Position Indexing
1377------------------------------------------------------------------------------
1379-- |
1380-- > indexed = Stream.postscanl' (\(i, _) x -> (i + 1, x)) (-1,undefined)
1381-- > indexed = Stream.zipWith (,) (Stream.enumerateFrom 0)
1383-- Pair each element in a stream with its index, starting from index 0.
1385-- >>> Stream.toList $ Stream.indexed $ Stream.fromList "hello"
1386-- [(0,'h'),(1,'e'),(2,'l'),(3,'l'),(4,'o')]
1388-- @since 0.6.0
1389{-# INLINE indexed #-}
1390indexed :: (IsStream t, Monad m) => t m a -> t m (Int, a)
1391indexed = fromStreamD . D.indexed . toStreamD
1393-- |
1394-- > indexedR n = Stream.postscanl' (\(i, _) x -> (i - 1, x)) (n + 1,undefined)
1395-- > indexedR n = Stream.zipWith (,) (Stream.enumerateFromThen n (n - 1))
1397-- Pair each element in a stream with its index, starting from the
1398-- given index @n@ and counting down.
1400-- >>> Stream.toList $ Stream.indexedR 10 $ Stream.fromList "hello"
1401-- [(10,'h'),(9,'e'),(8,'l'),(7,'l'),(6,'o')]
1403-- @since 0.6.0
1404{-# INLINE indexedR #-}
1405indexedR :: (IsStream t, Monad m) => Int -> t m a -> t m (Int, a)
1406indexedR n = fromStreamD . D.indexedR n . toStreamD
1408-------------------------------------------------------------------------------
1409-- Time Indexing
1410-------------------------------------------------------------------------------
1412-- Note: The timestamp stream must be the second stream in the zip so that the
1413-- timestamp is generated after generating the stream element and not before.
1414-- If we do not do that then the following example will generate the same
1415-- timestamp for first two elements:
1417-- Stream.mapM_ print $ Stream.timestamped $ Stream.delay $ Stream.enumerateFromTo 1 3
1419-- | Pair each element in a stream with an absolute timestamp, using a clock of
1420-- specified granularity. The timestamp is generated just before the element
1421-- is consumed.
1423-- >>> Stream.mapM_ print $ Stream.timestampWith 0.01 $ Stream.delay 1 $ Stream.enumerateFromTo 1 3
1424-- (AbsTime (TimeSpec {sec = ..., nsec = ...}),1)
1425-- (AbsTime (TimeSpec {sec = ..., nsec = ...}),2)
1426-- (AbsTime (TimeSpec {sec = ..., nsec = ...}),3)
1428-- /Pre-release/
1430{-# INLINE timestampWith #-}
1431timestampWith :: (IsStream t, MonadAsync m, Functor (t m))
1432 => Double -> t m a -> t m (AbsTime, a)
1433timestampWith g stream = zipWith (flip (,)) stream (absTimesWith g)
1435-- TBD: check performance vs a custom implementation without using zipWith.
1437-- /Pre-release/
1439{-# INLINE timestamped #-}
1440timestamped :: (IsStream t, MonadAsync m, Functor (t m))
1441 => t m a -> t m (AbsTime, a)
1442timestamped = timestampWith 0.01
1444-- | Pair each element in a stream with relative times starting from 0, using a
1445-- clock with the specified granularity. The time is measured just before the
1446-- element is consumed.
1448-- >>> Stream.mapM_ print $ Stream.timeIndexWith 0.01 $ Stream.delay 1 $ Stream.enumerateFromTo 1 3
1449-- (RelTime64 (NanoSecond64 ...),1)
1450-- (RelTime64 (NanoSecond64 ...),2)
1451-- (RelTime64 (NanoSecond64 ...),3)
1453-- /Pre-release/
1455{-# INLINE timeIndexWith #-}
1456timeIndexWith :: (IsStream t, MonadAsync m, Functor (t m))
1457 => Double -> t m a -> t m (RelTime64, a)
1458timeIndexWith g stream = zipWith (flip (,)) stream (relTimesWith g)
1460-- | Pair each element in a stream with relative times starting from 0, using a
1461-- 10 ms granularity clock. The time is measured just before the element is
1462-- consumed.
1464-- >>> Stream.mapM_ print $ Stream.timeIndexed $ Stream.delay 1 $ Stream.enumerateFromTo 1 3
1465-- (RelTime64 (NanoSecond64 ...),1)
1466-- (RelTime64 (NanoSecond64 ...),2)
1467-- (RelTime64 (NanoSecond64 ...),3)
1469-- /Pre-release/
1471{-# INLINE timeIndexed #-}
1472timeIndexed :: (IsStream t, MonadAsync m, Functor (t m))
1473 => t m a -> t m (RelTime64, a)
1474timeIndexed = timeIndexWith 0.01
1476------------------------------------------------------------------------------
1477-- Searching
1478------------------------------------------------------------------------------
1480-- | Find all the indices where the value of the element in the stream is equal
1481-- to the given value.
1483-- > elemIndices a = findIndices (== a)
1485-- @since 0.5.0
1486{-# INLINE elemIndices #-}
1487elemIndices :: (IsStream t, Eq a, Monad m) => a -> t m a -> t m Int
1488elemIndices a = findIndices (== a)
1490------------------------------------------------------------------------------
1491-- Rolling map
1492------------------------------------------------------------------------------
1494-- XXX this is not a one-to-one map so calling it map may not be right.
1495-- We can perhaps call it zipWithTail or rollWith.
1497-- | Apply a function on every two successive elements of a stream. The first
1498-- argument of the map function is the previous element and the second argument
1499-- is the current element. When the current element is the first element, the
1500-- previous element is 'Nothing'.
1502-- /Pre-release/
1504{-# INLINE rollingMap #-}
1505rollingMap :: (IsStream t, Monad m) => (Maybe a -> a -> b) -> t m a -> t m b
1506rollingMap f m = fromStreamD $ D.rollingMap f $ toStreamD m
1508-- | Like 'rollingMap' but with an effectful map function.
1510-- /Pre-release/
1512{-# INLINE rollingMapM #-}
1513rollingMapM :: (IsStream t, Monad m) => (Maybe a -> a -> m b) -> t m a -> t m b
1514rollingMapM f m = fromStreamD $ D.rollingMapM f $ toStreamD m
1516-- | Like 'rollingMap' but requires at least two elements in the stream,
1517-- returns an empty stream otherwise.
1519-- This is the stream equivalent of the list idiom @zipWith f xs (tail xs)@.
1521-- /Pre-release/
1523{-# INLINE rollingMap2 #-}
1524rollingMap2 :: (IsStream t, Monad m) => (a -> a -> b) -> t m a -> t m b
1525rollingMap2 f m = fromStreamD $ D.rollingMap2 f $ toStreamD m
1527------------------------------------------------------------------------------
1528-- Maybe Streams
1529------------------------------------------------------------------------------
1531-- | Map a 'Maybe' returning function to a stream, filter out the 'Nothing'
1532-- elements, and return a stream of values extracted from 'Just'.
1534-- Equivalent to:
1536-- @
1537-- mapMaybe f = Stream.map 'fromJust' . Stream.filter 'isJust' . Stream.map f
1538-- @
1540-- @since 0.3.0
1541{-# INLINE mapMaybe #-}
1542mapMaybe :: (IsStream t, Monad m) => (a -> Maybe b) -> t m a -> t m b
1543mapMaybe f m = fromStreamS $ S.mapMaybe f $ toStreamS m
1545-- | Like 'mapMaybe' but maps a monadic function.
1547-- Equivalent to:
1549-- @
1550-- mapMaybeM f = Stream.map 'fromJust' . Stream.filter 'isJust' . Stream.mapM f
1551-- @
1553-- /Concurrent (do not use with 'fromParallel' on infinite streams)/
1555-- @since 0.3.0
1556{-# INLINE_EARLY mapMaybeM #-}
1557mapMaybeM :: (IsStream t, MonadAsync m, Functor (t m))
1558 => (a -> m (Maybe b)) -> t m a -> t m b
1559mapMaybeM f = fmap fromJust . filter isJust . mapM f
1561{-# RULES "mapMaybeM serial" mapMaybeM = mapMaybeMSerial #-}
1562{-# INLINE mapMaybeMSerial #-}
1563mapMaybeMSerial :: Monad m => (a -> m (Maybe b)) -> SerialT m a -> SerialT m b
1564mapMaybeMSerial f m = fromStreamD $ D.mapMaybeM f $ toStreamD m
1566-- | In a stream of 'Maybe's, discard 'Nothing's and unwrap 'Just's.
1568-- /Pre-release/
1570{-# INLINE catMaybes #-}
1571catMaybes :: (IsStream t, Monad m, Functor (t m)) => t m (Maybe a) -> t m a
1572catMaybes = fmap fromJust . filter isJust
1574------------------------------------------------------------------------------
1575-- Either streams
1576------------------------------------------------------------------------------
1578-- | Discard 'Right's and unwrap 'Left's in an 'Either' stream.
1580-- /Pre-release/
1582{-# INLINE lefts #-}
1583lefts :: (IsStream t, Monad m, Functor (t m)) => t m (Either a b) -> t m a
1584lefts = fmap (fromLeft undefined) . filter isLeft
1586-- | Discard 'Left's and unwrap 'Right's in an 'Either' stream.
1588-- /Pre-release/
1590{-# INLINE rights #-}
1591rights :: (IsStream t, Monad m, Functor (t m)) => t m (Either a b) -> t m b
1592rights = fmap (fromRight undefined) . filter isRight
1594-- | Remove the either wrapper and flatten both lefts and as well as rights in
1595-- the output stream.
1597-- /Pre-release/
1599{-# INLINE both #-}
1600both :: Functor (t m) => t m (Either a a) -> t m a
1601both = fmap (either id id)
1603------------------------------------------------------------------------------
1604-- Concurrent Application
1605------------------------------------------------------------------------------
1607-- | Parallel transform application operator; applies a stream transformation
1608-- function @t m a -> t m b@ to a stream @t m a@ concurrently; the input stream
1609-- is evaluated asynchronously in an independent thread yielding elements to a
1610-- buffer and the transformation function runs in another thread consuming the
1611-- input from the buffer. '|$' is just like regular function application
1612-- operator '$' except that it is concurrent.
1614-- If you read the signature as @(t m a -> t m b) -> (t m a -> t m b)@ you can
1615-- look at it as a transformation that converts a transform function to a
1616-- buffered concurrent transform function.
1618-- The following code prints a value every second even though each stage adds a
1619-- 1 second delay.
1622-- >>> :{
1623-- Stream.drain $
1624-- Stream.mapM (\x -> threadDelay 1000000 >> print x)
1625-- |$ Stream.replicateM 3 (threadDelay 1000000 >> return 1)
1626-- :}
1627-- 1
1628-- 1
1629-- 1
1631-- /Concurrent/
1633-- /Since: 0.3.0 ("Streamly")/
1635-- @since 0.8.0
1636{-# INLINE (|$) #-}
1637(|$) :: (IsStream t, MonadAsync m) => (t m a -> t m b) -> (t m a -> t m b)
1638-- (|$) f = f . mkAsync
1639(|$) f = f . mkParallel
1641infixr 0 |$
1643-- | Same as '|$'.
1645-- /Internal/
1647{-# INLINE applyAsync #-}
1648applyAsync :: (IsStream t, MonadAsync m)
1649 => (t m a -> t m b) -> (t m a -> t m b)
1650applyAsync = (|$)
1652-- | Same as '|$' but with arguments reversed.
1654-- (|&) = flip (|$)
1656-- /Concurrent/
1658-- /Since: 0.3.0 ("Streamly")/
1660-- @since 0.8.0
1661{-# INLINE (|&) #-}
1662(|&) :: (IsStream t, MonadAsync m) => t m a -> (t m a -> t m b) -> t m b
1663x |& f = f |$ x
1665infixl 1 |&