@@ -22,12 +22,6 @@ module Streamly.Prelude.Internal
23 -- * Construction
23 -- * Construction
24 -- ** Primitives
24 -- ** Primitives
25− -- | Primitives to construct a stream from pure values or monadic actions.
26− -- All other stream construction and generation combinators described later
27− -- can be expressed in terms of these primitives. However, the special
28− -- versions provided in this module can be much more efficient in most
29− -- cases. Users can create custom combinators using these primitives.
@@ -36,7 +30,6 @@ module Streamly.Prelude.Internal
38 -- ** From Values
32 -- ** From Values
39− -- | Generate a monadic stream from a seed value or values.
42 , K.repeat
35 , K.repeat
@@ -44,27 +37,12 @@ module Streamly.Prelude.Internal
44 , replicate
37 , replicate
45 , replicateM
38 , replicateM
47− -- Note: Using enumeration functions e.g. 'Prelude.enumFromThen' turns out
48− -- to be slightly faster than the idioms like @[from, then..]@.
50 -- ** Enumeration
40 -- ** Enumeration
51− -- | We can use the 'Enum' type class to enumerate a type producing a list
52− -- and then convert it to a stream:
55− -- 'fromList' $ 'Prelude.enumFromThen' from then
58− -- However, this is not particularly efficient.
59− -- The 'Enumerable' type class provides corresponding functions that
60− -- generate a stream instead of a list, efficiently.
62 , Enumerable (..)
41 , Enumerable (..)
63 , enumerate
42 , enumerate
64 , enumerateTo
43 , enumerateTo
66 -- ** From Generators
45 -- ** From Generators
67− -- | Generate a monadic stream from a seed value and a generator function.
69 , unfoldrM
47 , unfoldrM
@@ -73,8 +51,6 @@ module Streamly.Prelude.Internal
73 , fromIndicesM
51 , fromIndicesM
75 -- ** From Containers
53 -- ** From Containers
76− -- | Convert an input structure, container or source into a stream. All of
77− -- these can be expressed in terms of primitives.
78 , P.fromList
54 , P.fromList
79 , fromListM
55 , fromListM
80 , K.fromFoldable
56 , K.fromFoldable
@@ -83,68 +59,11 @@ module Streamly.Prelude.Internal
83 -- * Elimination
59 -- * Elimination
85 -- ** Deconstruction
61 -- ** Deconstruction
86− -- | It is easy to express all the folds in terms of the 'uncons' primitive,
87− -- however the specific implementations provided later are generally more
94 -- ** Folding
66 -- ** Folding
95−-- | In imperative terms a fold can be considered as a loop over the stream
96−-- that reduces the stream to a single value.
97−-- Left and right folds use a fold function @f@ and an identity element @z@
98−-- (@zero@) to recursively deconstruct a structure and then combine and reduce
99−-- the values or transform and reconstruct a new container.
101−-- In general, a right fold is suitable for transforming and reconstructing a
102−-- right associated structure (e.g. cons lists and streamly streams) and a left
103−-- fold is suitable for reducing a right associated structure. The behavior of
104−-- right and left folds are described in detail in the individual fold's
105−-- documentation. To illustrate the two folds for cons lists:
107−-- > foldr :: (a -> b -> b) -> b -> [a] -> b
108−-- > foldr f z [] = z
109−-- > foldr f z (x:xs) = x `f` foldr f z xs
111−-- > foldl :: (b -> a -> b) -> b -> [a] -> b
112−-- > foldl f z [] = z
113−-- > foldl f z (x:xs) = foldl f (z `f` x) xs
115−-- @foldr@ is conceptually equivalent to:
117−-- > foldr f z [] = z
118−-- > foldr f z [x] = f x z
119−-- > foldr f z xs = foldr f (foldr f z (tail xs)) [head xs]
121−-- @foldl@ is conceptually equivalent to:
123−-- > foldl f z [] = z
124−-- > foldl f z [x] = f z x
125−-- > foldl f z xs = foldl f (foldl f z (init xs)) [last xs]
127−-- Left and right folds are duals of each other.
130−-- foldr f z xs = foldl (flip f) z (reverse xs)
131−-- foldl f z xs = foldr (flip f) z (reverse xs)
137−-- foldr f z xs = foldl g id xs z where g k x = k . f x
138−-- foldl f z xs = foldr g id xs z where g x k = k . flip f x
142−-- As a general rule, foldr cannot have state and foldl cannot have control.
144−-- NOTE: Folds are inherently serial as each step needs to use the result of
145−-- the previous step. However, it is possible to fold parts of the stream in
146−-- parallel and then combine the results using a monoid.
148 -- ** Right Folds
67 -- ** Right Folds
@@ -157,15 +76,11 @@ module Streamly.Prelude.Internal
157 , foldlM'
76 , foldlM'
159 -- ** Composable Left Folds
78 -- ** Composable Left Folds
162 , runFold
79 , runFold
164 -- ** Full Folds
81 -- ** Full Folds
165− -- | Folds that are guaranteed to evaluate the whole stream.
167 -- -- ** To Summary (Full Folds)
83 -- -- ** To Summary (Full Folds)
168− -- -- | Folds that summarize the stream to a single value.
@@ -174,8 +89,6 @@ module Streamly.Prelude.Internal
174 --, mconcat
89 --, mconcat
176 -- -- ** To Summary (Maybe) (Full Folds)
91 -- -- ** To Summary (Maybe) (Full Folds)
177− -- -- | Folds that summarize a non-empty stream to a 'Just' value and return
178− -- 'Nothing' for an empty stream.
179 , maximumBy
92 , maximumBy
180 , maximum
93 , maximum
181 , minimumBy
94 , minimumBy
@@ -186,18 +99,11 @@ module Streamly.Prelude.Internal
186 , toStreamRev
99 , toStreamRev
188 -- ** Lazy Folds
101 -- ** Lazy Folds
190− -- | Folds that generate a lazy structure. Note that the generated
191− -- structure may not be lazy if the underlying monad is strict.
193 -- -- ** To Containers (Full Folds)
103 -- -- ** To Containers (Full Folds)
194− -- -- | Convert or divert a stream into an output structure, container or
198 -- ** Partial Folds
106 -- ** Partial Folds
199− -- | Folds that may terminate before evaluating the whole stream. These
200− -- folds strictly evaluate the stream until the result is determined.
202 -- -- ** To Elements (Partial Folds)
108 -- -- ** To Elements (Partial Folds)
@@ -213,7 +119,6 @@ module Streamly.Prelude.Internal
213 , elemIndex
119 , elemIndex
215 -- -- ** To Boolean (Partial Folds)
121 -- -- ** To Boolean (Partial Folds)
216− -- -- | Folds that summarize the stream to a boolean value.
219 , notElem
124 , notElem
@@ -223,78 +128,15 @@ module Streamly.Prelude.Internal
225 -- * Transformation
130 -- * Transformation
227 , transform
131 , transform
229 -- ** Mapping
133 -- ** Mapping
230− -- | In imperative terms a map operation can be considered as a loop over
231− -- the stream that transforms the stream into another stream by performing
232− -- an operation on each element of the stream.
234− -- 'map' is the least powerful transformation operation with strictest
235− -- guarantees. A map, (1) is a stateless loop which means that no state is
236− -- allowed to be carried from one iteration to another, therefore,
237− -- operations on different elements are guaranteed to not affect each
238− -- other, (2) is a strictly one-to-one transformation of stream elements
239− -- which means it guarantees that no elements can be added or removed from
240− -- the stream, it can merely transform them.
241 , Serial.map
134 , Serial.map
242 , sequence
135 , sequence
246 -- ** Scanning
139 -- ** Scanning
248− -- | A scan is more powerful than map. While a 'map' is a stateless loop, a
249− -- @scan@ is a stateful loop which means that a state can be shared across
250− -- all the loop iterations, therefore, future iterations can be impacted by
251− -- the state changes made by the past iterations. A scan yields the state
252− -- of the loop after each iteration. Like a map, a @postscan@ or @prescan@
253− -- does not add or remove elements in the stream, it just transforms them.
254− -- However, a @scan@ adds one extra element to the stream.
256− -- A left associative scan, also known as a prefix sum, can be thought of
257− -- as a stream transformation consisting of left folds of all prefixes of a
258− -- stream. Another way of thinking about it is that it streams all the
259− -- intermediate values of the accumulator while applying a left fold on the
260− -- input stream. A right associative scan, on the other hand, can be
261− -- thought of as a stream consisting of right folds of all the suffixes of
264− -- The following equations hold for lists:
266− -- > scanl f z xs == map (foldl f z) $ inits xs
267− -- > scanr f z xs == map (foldr f z) $ tails xs
270− -- > scanl (+) 0 [1,2,3,4]
274− -- 0 + 1 + 2 + 3 = 6
275− -- 0 + 1 + 2 + 3 + 4 = 10
277− -- > scanr (+) 0 [1,2,3,4]
278− -- 1 + 2 + 3 + 4 + 0 = 10
279− -- 2 + 3 + 4 + 0 = 9
285− -- Left and right scans are duals:
287− -- > scanr f z xs == reverse $ scanl (flip f) z (reverse xs)
288− -- > scanl f z xs == reverse $ scanr (flip f) z (reverse xs)
290− -- A scan is a stateful map i.e. a combination of map and fold:
292− -- > map f xs = tail $ scanl (\_ x -> f x) z xs
293− -- > map f xs = reverse $ head $ scanr (\_ x -> f x) z xs
295− -- > foldl f z xs = last $ scanl f z xs
296− -- > foldr f z xs = head $ scanr f z xs
298 -- ** Left scans
140 -- ** Left scans
300 , scanlM'
142 , scanlM'
@@ -326,9 +168,6 @@ module Streamly.Prelude.Internal
326 -- , timestampedR -- timer
168 -- , timestampedR -- timer
328 -- ** Filtering
170 -- ** Filtering
329− -- | Remove some elements from the stream based on a predicate. In
330− -- imperative terms a filter over a stream corresponds to a loop with a
331− -- @continue@ clause for the cases when the predicate fails.
334 , filterM
173 , filterM
@@ -352,21 +191,15 @@ module Streamly.Prelude.Internal
352 -- , pruneBy -- dropAround + uniqBy - like words
191 -- , pruneBy -- dropAround + uniqBy - like words
354 -- ** Mapping Filters
193 -- ** Mapping Filters
355− -- | Mapping along with filtering
357 , mapMaybe
194 , mapMaybe
358 , mapMaybeM
195 , mapMaybeM
360 -- ** Scanning Filters
197 -- ** Scanning Filters
361− -- | Stateful transformation along with filtering
363 , findIndices
198 , findIndices
364 , elemIndices
199 , elemIndices
365 -- , seqIndices -- search a sequence in the stream
200 -- , seqIndices -- search a sequence in the stream
367 -- ** Insertion
202 -- ** Insertion
368− -- | Insertion adds more elements to the stream.
370 , insertBy
203 , insertBy
371 , intersperseM
204 , intersperseM
372 , intersperse
205 , intersperse
@@ -379,37 +212,10 @@ module Streamly.Prelude.Internal
379 , reverse'
212 , reverse'
381 -- * Multi-Stream Operations
214 -- * Multi-Stream Operations
382− -- | New streams can be constructed by appending, merging or zipping
383− -- existing streams.
385 -- ** Appending
216 -- ** Appending
386− -- | Streams form a 'Semigroup' and a 'Monoid' under the append
391− -- -------Stream m a------|-------Stream m a------|=>----Stream m a---
396− -- >> S.toList $ S.fromList [1,2] \<> S.fromList [3,4]
398− -- >> S.toList $ fold $ [S.fromList [1,2], S.fromList [3,4]]
402 -- ** Merging
218 -- ** Merging
403− -- | Streams form a commutative semigroup under the merge
408− -- -------Stream m a------|
409− -- |=>----Stream m a---
410− -- -------Stream m a------|
414 -- , merge
220 -- , merge
415 , mergeBy
221 , mergeBy
@@ -418,26 +224,15 @@ module Streamly.Prelude.Internal
418 , mergeAsyncByM
224 , mergeAsyncByM
420 -- ** Zipping
226 -- ** Zipping
424− -- -------Stream m a------|
425− -- |=>----Stream m c---
426− -- -------Stream m b------|
429 , zipWith
227 , zipWith
430 , zipWithM
228 , zipWithM
431 , Z.zipAsyncWith
229 , Z.zipAsyncWith
432 , Z.zipAsyncWithM
230 , Z.zipAsyncWithM
434 -- ** Nested Streams
232 -- ** Nested Streams
435− -- | Stream operations represent loops in imperative programming, streams
436− -- of streams represent nested loops.
438 , concatMapM
233 , concatMapM
439 , concatMap
234 , concatMap
440− , K.concatMapBy
235+ , concatMapWith
441 -- , interposeBy
236 -- , interposeBy
442 -- , intercalate
237 -- , intercalate
@@ -460,30 +255,19 @@ module Streamly.Prelude.Internal
460 -- , breakOnSeq
255 -- , breakOnSeq
462 -- ** Splitting
257 -- ** Splitting
463− -- | Streams can be split into segments in space or in time. We use the
464− -- term @chunk@ to refer to a spatial length of the stream (spatial window)
465− -- and the term @session@ to refer to a length in time (time window).
467− -- In imperative terms, grouped folding can be considered as a nested loop
468− -- where we loop over the stream to group elements and then loop over
469− -- individual groups to fold them to a single value that is yielded in the
472 -- , groupScan
258 -- , groupScan
474 -- -- *** Chunks
260 -- -- *** Chunks
475 , chunksOf
261 , chunksOf
476− , sessionsOf
262+ , intervalsOf
478 -- -- *** Using Element Separators
264 -- -- *** Using Element Separators
479− -- On == Dropping the separator
480 , splitOn
265 , splitOn
481 , splitOnSuffix
266 , splitOnSuffix
482 -- , splitOnPrefix
267 -- , splitOnPrefix
484− -- By == Keeping the separator
485 -- , splitBy
269 -- , splitBy
486− , splitBySuffix
270+ , splitWithSuffix
487 -- , splitByPrefix
271 -- , splitByPrefix
488 , wordsBy -- stripAndCompactBy
272 , wordsBy -- stripAndCompactBy
@@ -494,7 +278,7 @@ module Streamly.Prelude.Internal
495 -- Keeping the delimiters
279 -- Keeping the delimiters
496 , splitBySeq
280 , splitBySeq
497− , splitBySuffixSeq
281+ , splitWithSuffixSeq
498 -- , splitByPrefixSeq
282 -- , splitByPrefixSeq
499 -- , wordsBySeq
283 -- , wordsBySeq
@@ -513,31 +297,18 @@ module Streamly.Prelude.Internal
515 -- * Windowed Classification
299 -- * Windowed Classification
516− -- | Split the stream into windows or chunks in space or time. Each window
517− -- can be associated with a key, all events associated with a particular
518− -- key in the window can be folded to a single result. The stream is split
519− -- into windows of specified size, the window can be terminated early if
520− -- the closing flag is specified in the input stream.
522− -- The term "chunk" is used for a space window and the term "session" is
523− -- used for a time window.
525 -- ** Tumbling Windows
301 -- ** Tumbling Windows
526− -- | A new window starts after the previous window is finished.
527 -- , classifyChunksOf
302 -- , classifyChunksOf
528 , classifySessionsBy
303 , classifySessionsBy
529 , classifySessionsOf
304 , classifySessionsOf
531 -- ** Keep Alive Windows
306 -- ** Keep Alive Windows
532− -- | The window size is extended if an event arrives within the specified
533− -- window size. This can represent sessions with idle or inactive timeout.
534 -- , classifyKeepAliveChunks
307 -- , classifyKeepAliveChunks
535 , classifyKeepAliveSessions
308 , classifyKeepAliveSessions
538 -- ** Sliding Windows
311 -- ** Sliding Windows
539− -- | A new window starts after the specified slide from the previous
540− -- window. Therefore windows can overlap.
541 , classifySlidingChunks
312 , classifySlidingChunks
542 , classifySlidingSessions
313 , classifySlidingSessions
@@ -546,10 +317,6 @@ module Streamly.Prelude.Internal
546 -- , slidingSessionBuffer
317 -- , slidingSessionBuffer
548 -- ** Containers of Streams
319 -- ** Containers of Streams
549− -- | These are variants of standard 'Foldable' fold functions that use a
550− -- polymorphic stream sum operation (e.g. 'async' or 'wSerial') to fold a
551− -- finite container of streams.
553 , foldWith
320 , foldWith
554 , foldMapWith
321 , foldMapWith
555 , forEachWith
322 , forEachWith
@@ -613,6 +380,7 @@ import qualified System.IO as IO
613import Streamly.Enumeration (Enumerable(..), enumerate, enumerateTo)
380import Streamly.Enumeration (Enumerable(..), enumerate, enumerateTo)
614import Streamly.Fold.Types (Fold (..))
381import Streamly.Fold.Types (Fold (..))
615import Streamly.Memory.Array (Array)
382import Streamly.Memory.Array (Array)
383+-- import Streamly.Memory.Ring (Ring)
616import Streamly.SVar (MonadAsync, defState)
384import Streamly.SVar (MonadAsync, defState)
617import Streamly.Streams.Async (mkAsync')
385import Streamly.Streams.Async (mkAsync')
618import Streamly.Streams.Combinators (maxYields)
386import Streamly.Streams.Combinators (maxYields)
@@ -1003,101 +771,21 @@ fromHandle h = go
1003-- Elimination by Folding
771-- Elimination by Folding
1004------------------------------------------------------------------------------
772------------------------------------------------------------------------------
1006−-- | Right associative/pull fold.
774+-- | Right associative/lazy pull fold. @foldrM build final stream@ constructs
775+-- an output structure using the step function @build@. @build@ is invoked with
776+-- the next input element and the remaining (lazy) tail of the output
777+-- structure. It builds a lazy output expression using the two. When the "tail
778+-- structure" in the output expression is evaluated it calls @build@ again thus
779+-- lazily consuming the input @stream@ until either the output expression built
780+-- by @build@ is free of the "tail" or the input is exhausted in which case
781+-- @final@ is used as the terminating case for the output structure. For more
782+-- details see the description in the previous section.
1008-- Example, determine if any element is 'odd' in a stream:
784-- Example, determine if any element is 'odd' in a stream:
1010-- >>> S.foldrM (\x xs -> if odd x then return True else xs) (return False) $ S.fromList (2:4:5:undefined)
786-- >>> S.foldrM (\x xs -> if odd x then return True else xs) (return False) $ S.fromList (2:4:5:undefined)
1011-- > True
787-- > True
1013−-- Let's take a closer look at the @foldr@ definition for lists, as given
1017−-- foldr f z (x:xs) = x \`f` foldr f z xs
1020−-- @foldr@ invokes the fold step function @f@ as @f x (foldr f z xs)@. At each
1021−-- invocation of @f@ @foldr@ gives us the next element in the input container
1022−-- @x@ and a recursive expression @foldr f z xs@ representing the yet unbuilt
1023−-- (lazy thunk) part of the output. Therefore, when @f x xs@ is lazy in @xs@
1024−-- it can consume the input one element at a time in FIFO order to build a lazy
1025−-- output expression. For example,
1027−-- > f x remaining = show x : remaining
1029−-- @take 2 $ foldr f [] (1:2:undefined)@ would consume the input lazily on
1030−-- demand, consuming only first two elements and resulting in ["1", "2"]. @f@
1031−-- can terminate recursion by not evaluating the @remaining@ part:
1033−-- > f 2 remaining = show 2 : []
1034−-- > f x remaining = show x : remaining
1036−-- @f@ would terminate recursion whenever it sees element @2@ in the input.
1037−-- Therefore, @foldr f [] (1:2:undefined)@ would work as before. If @f a b@ is
1038−-- strict in @b@ it would end up consuming the whole input right away and
1039−-- expanding the recursive expression @b@ (i.e. @foldr f z xs@) fully before
1040−-- it yields an output expression, resulting in the following /right
1041−-- associated expression/:
1044−-- foldr f z xs == x1 \`f` (x2 \`f` ...(xn \`f` z))
1049−-- > f x remaining = x + remaining
1051−-- With this definition, @foldr f 0 [1..1000]@, would recurse completely until
1052−-- it reaches the recursion terminating case @... `f` (1000 `f` 0)@, and then
1053−-- start reducing the whole expression from right to left, therefore, consuming
1054−-- the input elements in LIFO order. Thus, such an evaluation would require
1055−-- memory proportional to the size of input. Try out @foldr (+) 0 (map (\\x ->
1056−-- trace (show x) x) [1..10])@.
1058−-- Notice, the order of the arguments to the step function @f a b@. It follows
1059−-- the order of @a@ and @b@ in the right associative recursive expression
1060−-- generated by expanding @a \`f` b@.
1062−-- A right fold is a pull fold, the step function is the puller, it can pull
1063−-- more data from the input container by using its second argument in the
1064−-- output expression or terminate pulling by not using it. As a corollary:
1066−-- 1. a step function which is lazy in its second argument (usually functions
1067−-- or constructors that build a lazy structure e.g. @(:)@) can pull lazily on
1069−-- 2. a step function strict in its second argument (usually reducers e.g.
1070−-- (+)) would end up pulling all of its input and buffer it in memory before
1071−-- potentially reducing it.
1073−-- A right fold is suitable for lazy reconstructions e.g. transformation,
1074−-- mapping, filtering of /right associated input structures/ (e.g. cons lists).
1075−-- Whereas a left fold is suitable for reductions (e.g. summing a stream of
1076−-- numbers) of right associated structures. Note that these roles will reverse
1077−-- for left associated structures (e.g. snoc lists). Most of our observations
1078−-- here assume right associated structures, lists being the canonical example.
1080−-- 1. A lazy FIFO style pull using a right fold allows pulling a potentially
1081−-- /infinite/ input stream lazily, perform transformations on it, and
1082−-- reconstruct a new structure without having to buffer the whole structure. In
1083−-- contrast, a left fold would buffer the entire structure before the
1084−-- reconstructed structure can be consumed.
1085−-- 2. Even if buffering the entire input structure is ok, we need to keep in
1086−-- mind that a right fold reconstructs structures in a FIFO style, whereas a
1087−-- left fold reconstructs in a LIFO style, thereby reversing the order of
1089−-- 3. A right fold has termination control and therefore can terminate early
1090−-- without going throught the entire input, a left fold cannot terminate
1091−-- without consuming all of its input. For example, a right fold
1092−-- implementation of 'or' can terminate as soon as it finds the first 'True'
1093−-- element, whereas a left fold would necessarily go through the entire input
1094−-- irrespective of that.
1095−-- 4. Reduction (e.g. using (+) on a stream of numbers) using a right fold
1096−-- occurs in a LIFO style, which means that the entire input gets buffered
1097−-- before reduction starts. Whereas with a strict left fold reductions occur
1098−-- incrementally in FIFO style. Therefore, a strict left fold is more suitable
1101-- /Since: 0.7.0 (signature changed)/
789-- /Since: 0.7.0 (signature changed)/
1103-- /Since: 0.2.0 (signature changed)/
791-- /Since: 0.2.0 (signature changed)/
@@ -1155,7 +843,8 @@ foldrT :: (IsStream t, Monad m, Monad (s m), MonadTrans s)
1155 => (a -> s m b -> s m b) -> s m b -> t m a -> s m b
843 => (a -> s m b -> s m b) -> s m b -> t m a -> s m b
1156foldrT f z s = S.foldrT f z (toStreamS s)
844foldrT f z s = S.foldrT f z (toStreamS s)
1158−-- | Right fold for lazy monads or pure streams.
846+-- | Right fold, lazy for lazy monads and pure streams, and strict for strict
1160-- Please avoid using this routine in strict monads like IO unless you need a
849-- Please avoid using this routine in strict monads like IO unless you need a
1161-- strict right fold. This is provided only for use in lazy monads (e.g.
850-- strict right fold. This is provided only for use in lazy monads (e.g.
@@ -1192,96 +881,13 @@ foldr1 f m = S.foldr1 f (toStreamS m)
1192foldx :: Monad m => (x -> a -> x) -> x -> (x -> b) -> SerialT m a -> m b
881foldx :: Monad m => (x -> a -> x) -> x -> (x -> b) -> SerialT m a -> m b
1193foldx = P.foldlx'
882foldx = P.foldlx'
1195−-- | Strict left associative/push fold. Note that the observations below about
884+-- | Left associative/strict push fold. @foldl' reduce initial stream@ invokes
1196−-- the behavior of a left fold assume that we are working on a right associated
885+-- @reduce@ with the accumulator and the next input in the input stream, using
1197−-- structure like cons lists and streamly streams. If we are working on a left
886+-- @initial@ as the initial value of the current value of the accumulator. When
1198−-- associated structure (e.g. snoc lists) the roles of right and left folds
887+-- the input is exhausted the current value of the accumulator is returned.
1199−-- would reverse.
888+-- Make sure to use a strict data structure for accumulator to not build
1200−--
889+-- unnecessary lazy expressions unless that's what you want. See the previous
1201−-- Let's take a closer look at the @foldl@ definition for lists given above:
890+-- section for more details.
1204−-- foldl f z (x:xs) = foldl f (z \`f` x) xs
1207−-- @foldl@ calls itself recursively, in each call it invokes @f@ as @f z x@
1208−-- providing it with the result accumulated till now @z@ (the state) and the
1209−-- next element from the input container. First call to @f@ is supplied with
1210−-- the initial value of the accumulator @z@ and each subsequent call uses the
1211−-- output of the previous call to @f z x@.
1213−-- >> foldl' (+) 0 [1,2,3]
1216−-- The recursive call at the head of the output expression is bound to be
1217−-- evaluated until recursion terminates, therefore, a left fold always
1218−-- /consumes the whole input container/. The following would result in an
1219−-- error, even though the fold is not using the values at all:
1221−-- >> foldl' (\_ _ -> 0) 0 (1:undefined)
1222−-- > *** Exception: Prelude.undefined
1224−-- As @foldl@ recurses, it builds the left associated expression shown below.
1225−-- Notice, the order of the arguments to the step function @f b a@. It follows
1226−-- the left associative recursive expression generated by expanding @b \`f` a@.
1229−-- foldl f z xs == (((z \`f` x1) \`f` x2) ...) \`f` xn
1233−-- The strict left fold @foldl'@ forces the reduction of its argument @z \`f`
1234−-- x@ before using it, therefore it never builds the whole expression in
1235−-- memory. Thus, @z \`f` x1@ would get reduced to @z1@ and then @z1 \`f` x2@
1236−-- would get reduced to @z2@ and so on, incrementally reducing the expression
1237−-- from left to right as it recurses, consuming the input in FIFO order. Try
1238−-- out @foldl' (+) 0 (map (\\x -> trace (show x) x) [1..10])@ to see how it
1239−-- works. For example:
1242−-- > S.foldl' (+) 0 $ S.fromList [1,2,3,4]
1253−-- However, @foldl'@ evaluates the accumulator only to WHNF. It may further
1254−-- help if the step function uses a strict data structure as accumulator to
1255−-- improve performance and to keep the expression fully reduced at all times
1258−-- A left fold can also build a new structure instead of reducing one if a
1259−-- constructor is used as a fold step. However, it may not be very useful
1260−-- because it will consume the whole input and construct the new structure in
1261−-- memory before we can consume it. Thus the whole structure gets buffered in
1262−-- memory. When the list constructor is used it would build a new list in
1263−-- reverse (LIFO) order:
1266−-- > S.foldl' (flip (:)) [] $ S.fromList [1,2,3,4]
1270−-- A left fold is a push fold. The producer pushes its contents to the step
1271−-- function of the fold. The step function therefore has no control to stop the
1272−-- input, it can only discard it if it does not need it. We can also consider a
1273−-- left fold as a state machine where the state is store in the accumulator,
1274−-- the state can be modified based on new inputs that are pushed to the fold.
1276−-- In general, a strict left fold is a reducing fold, whereas a right fold is a
1277−-- constructing fold. A strict left fold reduces in a FIFO order whereas it
1278−-- constructs in a LIFO order, and vice-versa for the right fold. See the
1279−-- documentation of 'foldrM' for a discussion on where a left or right fold is
1282−-- To perform a left fold lazily without having to consume all the input one
1283−-- can use @scanl@ to stream the intermediate results of the fold and consume
1284−-- the resulting stream lazily.
1286-- @since 0.2.0
892-- @since 0.2.0
1287{-# INLINE foldl' #-}
893{-# INLINE foldl' #-}
@@ -1321,51 +927,6 @@ foldlM' step begin m = S.foldlM' step begin $ toStreamS m
1321-- Running a Fold
927-- Running a Fold
1322------------------------------------------------------------------------------
928------------------------------------------------------------------------------
1326−-- "Streamly.Fold" module defines composable left folds which can be combined
1327−-- together in many interesting ways. Those folds can be run using 'runFold'.
1328−-- The following two ways of folding are equivalent in functionality and
1331−-- >>> S.runFold FL.sum (S.enumerateFromTo 1 100)
1333−-- >>> S.sum (S.enumerateFromTo 1 100)
1336−-- However, left folds cannot terminate early even if it does not need to
1337−-- consume more input to determine the result. Therefore, the performance is
1338−-- equivalent only for full folds like 'sum' and 'length'. For partial folds
1339−-- like 'head' or 'any' the the folds defined in this module may be much more
1340−-- efficient because they are implemented as right folds that terminate as soon
1341−-- as we get the result. Note that when a full fold is composed with a partial
1342−-- fold in parallel the performance is not impacted as we anyway have to
1343−-- consume the whole stream due to the full fold.
1345−-- >>> S.head (1 `S.cons` undefined)
1347−-- >>> S.runFold FL.head (1 `S.cons` undefined)
1348−-- *** Exception: Prelude.undefined
1350−-- However, we can wrap the fold in a scan to convert it into a lazy stream of
1351−-- fold steps. We can then terminate the stream whenever we want. For example,
1353−-- >>> S.toList $ S.take 1 $ S.runScan FL.head (1 `S.cons` undefined)
1356−-- The following example extracts the input stream up to a point where the
1357−-- running average of elements is no more than 10:
1361−-- $ S.map (fromJust . fst)
1362−-- $ S.takeWhile (\\(_,x) -> x <= 10)
1363−-- $ S.runPostscan ((,) \<$> FL.last \<*> avg) (S.enumerateFromTo 1.0 100.0)
1366−-- [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]
1369-- | Fold a stream using the supplied left fold.
930-- | Fold a stream using the supplied left fold.
1371-- >>> S.runFold FL.sum (S.enumerateFromTo 1 100)
932-- >>> S.runFold FL.sum (S.enumerateFromTo 1 100)
@@ -1673,7 +1234,7 @@ elemIndex a = findIndex (== a)
1673------------------------------------------------------------------------------
1234------------------------------------------------------------------------------
1675-- | Returns 'True' if the first stream is the same as or a prefix of the
1236-- | Returns 'True' if the first stream is the same as or a prefix of the
1676−-- second.
1237+-- second. A stream is a prefix of itself.
1679-- > S.isPrefixOf (S.fromList "hello") (S.fromList "hello" :: SerialT IO Char)
1240-- > S.isPrefixOf (S.fromList "hello") (S.fromList "hello" :: SerialT IO Char)
@@ -1687,7 +1248,7 @@ isPrefixOf m1 m2 = D.isPrefixOf (toStreamD m1) (toStreamD m2)
1688-- | Returns 'True' if all the elements of the first stream occur, in order, in
1249-- | Returns 'True' if all the elements of the first stream occur, in order, in
1689-- the second stream. The elements do not have to occur consecutively. A stream
1250-- the second stream. The elements do not have to occur consecutively. A stream
1690−-- is treated as a subsequence of itself.
1251+-- is a subsequence of itself.
1693-- > S.isSubsequenceOf (S.fromList "hlo") (S.fromList "hello" :: SerialT IO Char)
1254-- > S.isSubsequenceOf (S.fromList "hlo") (S.fromList "hello" :: SerialT IO Char)
@@ -1877,7 +1438,7 @@ scanlM' step begin m = fromStreamD $ D.scanlM' step begin $ toStreamD m
1877-- thus modularizing the stream processing. This can be useful in
1438-- thus modularizing the stream processing. This can be useful in
1878-- stateful or event-driven programming.
1439-- stateful or event-driven programming.
1880−-- Consider the following monolothic example, computing the sum and the product
1441+-- Consider the following monolithic example, computing the sum and the product
1881-- of the elements in a stream in one go using a @foldl'@:
1442-- of the elements in a stream in one go using a @foldl'@:
@@ -2132,6 +1693,12 @@ sequence m = fromStreamS $ S.sequence (toStreamS m)
2132-- | Map a 'Maybe' returning function to a stream, filter out the 'Nothing'
1693-- | Map a 'Maybe' returning function to a stream, filter out the 'Nothing'
2133-- elements, and return a stream of values extracted from 'Just'.
1694-- elements, and return a stream of values extracted from 'Just'.
1699+-- mapMaybe f = S.map 'fromJust' . S.filter 'isJust' . S.map f
2135-- @since 0.3.0
1702-- @since 0.3.0
2136{-# INLINE mapMaybe #-}
1703{-# INLINE mapMaybe #-}
2137mapMaybe :: (IsStream t, Monad m) => (a -> Maybe b) -> t m a -> t m b
1704mapMaybe :: (IsStream t, Monad m) => (a -> Maybe b) -> t m a -> t m b
@@ -2139,6 +1706,12 @@ mapMaybe f m = fromStreamS $ S.mapMaybe f $ toStreamS m
2140-- | Like 'mapMaybe' but maps a monadic function.
1707-- | Like 'mapMaybe' but maps a monadic function.
1712+-- mapMaybeM f = S.map 'fromJust' . S.filter 'isJust' . S.mapM f
2142-- /Concurrent (do not use with 'parallely' on infinite streams)/
1715-- /Concurrent (do not use with 'parallely' on infinite streams)/
2144-- @since 0.3.0
1717-- @since 0.3.0
@@ -2162,10 +1735,9 @@ mapMaybeMSerial f m = fromStreamD $ D.mapMaybeM f $ toStreamD m
2162-- /Note:/ 'reverse'' is much faster than this, use that when performance
1735-- /Note:/ 'reverse'' is much faster than this, use that when performance
2163-- matters.
1736-- matters.
2166-- > reverse = S.foldlT (flip S.cons) S.nil
1738-- > reverse = S.foldlT (flip S.cons) S.nil
2168−-- Returns the elements of the stream in reverse order. The stream must be
1740+-- | Returns the elements of the stream in reverse order. The stream must be
2169-- finite. Note that this necessarily buffers the entire stream in memory.
1741-- finite. Note that this necessarily buffers the entire stream in memory.
2171-- /Since 0.7.0 (Monad m constraint)/
1743-- /Since 0.7.0 (Monad m constraint)/
@@ -2426,7 +1998,7 @@ mergeByM f m1 m2 = fromStreamS $ S.mergeByM f (toStreamS m1) (toStreamS m2)
2428-- | Like 'mergeByM' but stops merging as soon as any of the two streams stops.
2000-- | Like 'mergeByM' but stops merging as soon as any of the two streams stops.
2429−{-# INLINABLE mergeUptoShortest #-}
2001+{-# INLINABLE mergeEndByAny #-}
2430mergeEndByAny
2002mergeEndByAny
2431 :: (IsStream t, Monad m)
2003 :: (IsStream t, Monad m)
2432 => (a -> a -> m Ordering) -> t m a -> t m a -> t m a
2004 => (a -> a -> m Ordering) -> t m a -> t m a -> t m a
@@ -2484,35 +2056,43 @@ mergeAsyncByM f m1 m2 = K.mkStream $ \st stp sng yld -> do
2484-- Nesting
2056-- Nesting
2485------------------------------------------------------------------------------
2057------------------------------------------------------------------------------
2487−-- | Map each element of the stream to produce a stream and then flatten the
2059+-- | @concatMapWith merge map stream@ is a two dimensional looping combinator.
2488−-- results into a single stream.
2060+-- The first argument specifies a merge or concat function that is used to
2489−--
2061+-- merge the streams generated by applying the second argument i.e. the @map@
2490−-- > concatMap f = concatMapM (return . f)
2062+-- function to each element of the input stream. The concat function could be
2491−--
2063+-- 'serial', 'parallel', 'async', 'ahead' or any other zip or merge function
2492−-- In imperative terms, a 'concatMap' corresponds to nested loops. We loop over
2064+-- and the second argument could be any stream generation function using a
2493−-- the input stream and then for each element of the input stream another
2065+-- seed.
2494−-- stream is generated and then we loop over that inner stream as well to yield
2495−-- each element of that stream to generate a single output stream.
2497−-- 'concatMap' can perform filtering by mapping an element to a 'nil'
2500−-- > filter p m = S.concatMap (\x -> if p x then S.yield x else S.nil) m
2067+-- /Compare 'foldMapWith'/
2502−-- Its a map, therefore it can degenerate to a simple map operation as well:
2069+-- @since 0.7.0
2503−--
2070+{-# INLINE concatMapWith #-}
2504−-- > map f m = S.concatMap (\x -> S.yield (f x)) m
2071+concatMapWith
2073+ => (forall c. t m c -> t m c -> t m c)
2077+concatMapWith = K.concatMapBy
2079+-- | Map a stream producing function on each element of the stream and then
2080+-- flatten the results into a single stream.
2506−-- 'concatMap' is not inherently stateful, however, it can be combined with a
2082+-- @
2507−-- scan to perform stateful operations.
2083+-- concatMap = 'concatMapWith' 'Serial.serial'
2084+-- concatMap f = 'concatMapM' (return . f)
2509-- @since 0.6.0
2087-- @since 0.6.0
2510{-# INLINE concatMap #-}
2088{-# INLINE concatMap #-}
2511concatMap ::(IsStream t, Monad m) => (a -> t m b) -> t m a -> t m b
2089concatMap ::(IsStream t, Monad m) => (a -> t m b) -> t m a -> t m b
2512concatMap f m = fromStreamD $ D.concatMap (toStreamD . f) (toStreamD m)
2090concatMap f m = fromStreamD $ D.concatMap (toStreamD . f) (toStreamD m)
2514−-- | Map each element to a stream to produce a stream using a monadic function
2092+-- | Map a stream producing monadic function on each element of the stream
2515−-- and then flatten the results into a single stream.
2093+-- and then flatten the results into a single stream. Since the stream
2094+-- generation function is monadic, unlike 'concatMap', it can produce an
2095+-- effect at the beginning of each iteration of the inner loop.
2517-- @since 0.6.0
2097-- @since 0.6.0
2518{-# INLINE concatMapM #-}
2098{-# INLINE concatMapM #-}
@@ -2523,9 +2103,16 @@ concatMapM f m = fromStreamD $ D.concatMapM (fmap toStreamD . f) (toStreamD m)
2523-- | A generalization of insertBy to inserting sequences.
2103-- | A generalization of insertBy to inserting sequences.
2524interposeBy :: (IsStream t, Monad m)
2104interposeBy :: (IsStream t, Monad m)
2525 => (a -> a -> Ordering) -> t m a -> t m a -> t m a
2105 => (a -> a -> Ordering) -> t m a -> t m a -> t m a
2106+interposeBy = undefined
2108+-- XXX shall we intercalate an Array instead? A stream is exhaustible and
2109+-- should be used only once unless it is a pure stream. or we can have
2110+-- intercalateN to intercalate n elements from the input stream at a time and
2111+-- generate the stream by cycling the array.
2527-- | A generalization of intersperseM to intersperse sequences.
2113-- | A generalization of intersperseM to intersperse sequences.
2528intercalate :: (IsStream t, MonadAsync m) => t m a -> t m a -> t m a
2114intercalate :: (IsStream t, MonadAsync m) => t m a -> t m a -> t m a
2115+intercalate = undefined
2531------------------------------------------------------------------------------
2118------------------------------------------------------------------------------
@@ -2565,10 +2152,11 @@ intercalate :: (IsStream t, MonadAsync m) => t m a -> t m a -> t m a
2565-- >>> splitAt_ 4 [1,2,3]
2152-- >>> splitAt_ 4 [1,2,3]
2566-- > ([1,2,3],[])
2153-- > ([1,2,3],[])
2568-- This can be considered as a two-fold version of 'ltake' where we take both
2157-- This can be considered as a two-fold version of 'ltake' where we take both
2569-- the segments instead of discarding the leftover.
2158-- the segments instead of discarding the leftover.
2572{-# INLINE splitAt #-}
2160{-# INLINE splitAt #-}
2574 :: Monad m
2162 :: Monad m
@@ -2649,19 +2237,19 @@ chunksOf n f m = D.fromStreamD $ D.groupsOf n f (D.toStreamD m)
2650-- XXX we can implement this by repeatedly applying the 'lrunFor' fold.
2238-- XXX we can implement this by repeatedly applying the 'lrunFor' fold.
2651-- XXX add this example after fixing the serial stream rate control
2239-- XXX add this example after fixing the serial stream rate control
2652−-- >>> S.toList $ S.take 5 $ sessionsOf 1 FL.sum $ constRate 2 $ S.enumerateFrom 1
2240+-- >>> S.toList $ S.take 5 $ intervalsOf 1 FL.sum $ constRate 2 $ S.enumerateFrom 1
2653-- > [3,7,11,15,19]
2241-- > [3,7,11,15,19]
2655-- | Group the input stream into windows of @n@ second each and then fold each
2243-- | Group the input stream into windows of @n@ second each and then fold each
2656-- group using the provided fold function.
2244-- group using the provided fold function.
2658-- @since 0.7.0
2246-- @since 0.7.0
2659−{-# INLINE sessionsOf #-}
2247+{-# INLINE intervalsOf #-}
2660−sessionsOf
2248+intervalsOf
2661 :: (IsStream t, MonadAsync m)
2249 :: (IsStream t, MonadAsync m)
2662 => Double -> Fold m a b -> t m a -> t m b
2250 => Double -> Fold m a b -> t m a -> t m b
2663−sessionsOf n f xs =
2251+intervalsOf n f xs =
2664− splitBySuffix isNothing (FL.lcatMaybes f)
2252+ splitWithSuffix isNothing (FL.lcatMaybes f)
2665 (intersperseByTime n (return Nothing) (Serial.map Just xs))
2253 (intersperseByTime n (return Nothing) (Serial.map Just xs))
2667------------------------------------------------------------------------------
2255------------------------------------------------------------------------------
@@ -2887,11 +2475,12 @@ breakOn pat f m = undefined
2887-- separators. We can have a single split operation taking the splitter config
2475-- separators. We can have a single split operation taking the splitter config
2888-- as argument.
2476-- as argument.
2478+-- | Split on an infixed separator element, dropping the separator. Splits the
2890−-- | Split a stream on separator elements determined by a predicate, dropping
2479+-- stream on separator elements determined by the supplied predicate, separator
2891−-- the separator. Separator is considered as infixed between two segments, if
2480+-- is considered as infixed between two segments, if one side of the separator
2892−-- one side of the separator is missing then it is parsed as an empty stream.
2481+-- is missing then it is parsed as an empty stream. The supplied 'Fold' is
2482+-- applied on the split segments. With '-' representing non-separator elements
2893−-- With '-' representing elements and '.' as separator, 'splitOn' splits as
2483+-- and '.' as separator, 'splitOn' splits as follows:
2897-- "--.--" => "--" "--"
2486-- "--.--" => "--" "--"
@@ -2988,10 +2577,10 @@ splitOnSuffix
2988splitOnSuffix predicate f m =
2577splitOnSuffix predicate f m =
2989 D.fromStreamD $ D.splitSuffixBy predicate f (D.toStreamD m)
2578 D.fromStreamD $ D.splitSuffixBy predicate f (D.toStreamD m)
2991−-- | Like 'splitBy' but ignores repeated separators or separators in leading
2580+-- | Like 'splitOn' after stripping leading, trailing, and repeated separators.
2992−-- or trailing position. Therefore, @"..a..b.."@ would be parsed as
2581+-- Therefore, @".a..b."@ with '.' as the separator would be parsed as
2993−-- @["a","b"]@. In other words, it treats the input like words separated by
2582+-- @["a","b"]@. In other words, its like parsing words from whitespace
2994−-- whitespace elements determined by the predicate.
2583+-- separated text.
2996-- > wordsBy' p xs = S.toList $ S.wordsBy p (FL.toList) (S.fromList xs)
2585-- > wordsBy' p xs = S.toList $ S.wordsBy p (FL.toList) (S.fromList xs)
@@ -3007,6 +2596,9 @@ splitOnSuffix predicate f m =
3007-- > words = wordsBy isSpace
2596-- > words = wordsBy isSpace
3009-- @since 0.7.0
2598-- @since 0.7.0
2600+-- It is equivalent to splitting in any of the infix/prefix/suffix styles
2601+-- followed by removal of empty segments.
3010{-# INLINE wordsBy #-}
2602{-# INLINE wordsBy #-}
3012 :: (IsStream t, Monad m)
2604 :: (IsStream t, Monad m)
@@ -3017,30 +2609,30 @@ wordsBy predicate f m =
3017-- | Like 'splitOnSuffix' but keeps the suffix attached to the resulting
2609-- | Like 'splitOnSuffix' but keeps the suffix attached to the resulting
3018-- splits.
2610-- splits.
3020−-- > splitBySuffix' p xs = S.toList $ S.splitBySuffix p (FL.toList) (S.fromList xs)
2612+-- > splitWithSuffix' p xs = S.toList $ S.splitWithSuffix p (FL.toList) (S.fromList xs)
3022−-- >>> splitBySuffix' (== '.') ""
2614+-- >>> splitWithSuffix' (== '.') ""
3025−-- >>> splitBySuffix' (== '.') "."
2617+-- >>> splitWithSuffix' (== '.') "."
3028−-- >>> splitBySuffix' (== '.') "a"
2620+-- >>> splitWithSuffix' (== '.') "a"
3031−-- >>> splitBySuffix' (== '.') ".a"
2623+-- >>> splitWithSuffix' (== '.') ".a"
3032-- > [".","a"]
2624-- > [".","a"]
3034−-- >>> splitBySuffix' (== '.') "a."
2626+-- >>> splitWithSuffix' (== '.') "a."
3035-- > ["a."]
2627-- > ["a."]
3037−-- >>> splitBySuffix' (== '.') "a.b"
2629+-- >>> splitWithSuffix' (== '.') "a.b"
3038-- > ["a.","b"]
2630-- > ["a.","b"]
3040−-- >>> splitBySuffix' (== '.') "a.b."
2632+-- >>> splitWithSuffix' (== '.') "a.b."
3041-- > ["a.","b."]
2633-- > ["a.","b."]
3043−-- >>> splitBySuffix' (== '.') "a..b.."
2635+-- >>> splitWithSuffix' (== '.') "a..b.."
3044-- > ["a.",".","b.","."]
2636-- > ["a.",".","b.","."]
3046-- @since 0.7.0
2638-- @since 0.7.0
@@ -3048,11 +2640,11 @@ wordsBy predicate f m =
3048-- This can be considered as an n-fold version of 'breakPost' where we apply
2640-- This can be considered as an n-fold version of 'breakPost' where we apply
3049-- 'breakPost' successively on the input stream.
2641-- 'breakPost' successively on the input stream.
3051−{-# INLINE splitBySuffix #-}
2643+{-# INLINE splitWithSuffix #-}
3052−splitBySuffix
2644+splitWithSuffix
3053 :: (IsStream t, Monad m)
2645 :: (IsStream t, Monad m)
3054 => (a -> Bool) -> Fold m a b -> t m a -> t m b
2646 => (a -> Bool) -> Fold m a b -> t m a -> t m b
3055−splitBySuffix predicate f m =
2647+splitWithSuffix predicate f m =
3056 D.fromStreamD $ D.splitSuffixBy' predicate f (D.toStreamD m)
2648 D.fromStreamD $ D.splitSuffixBy' predicate f (D.toStreamD m)
3058------------------------------------------------------------------------------
2650------------------------------------------------------------------------------
@@ -3271,11 +2863,11 @@ splitBySeq patt f m = intersperseM (runFold f (A.read patt)) $ splitOnSeq patt f
3271-- > ["a.",".","b.","."]
2863-- > ["a.",".","b.","."]
3273-- @since 0.7.0
2865-- @since 0.7.0
3274−{-# INLINE splitBySuffixSeq #-}
2866+{-# INLINE splitWithSuffixSeq #-}
3275−splitBySuffixSeq
2867+splitWithSuffixSeq
3276 :: (IsStream t, MonadIO m, Storable a, Enum a, Eq a)
2868 :: (IsStream t, MonadIO m, Storable a, Enum a, Eq a)
3277 => Array a -> Fold m a b -> t m a -> t m b
2869 => Array a -> Fold m a b -> t m a -> t m b
3278−splitBySuffixSeq patt f m =
2870+splitWithSuffixSeq patt f m =
3279 D.fromStreamD $ D.splitSuffixOn True patt f (D.toStreamD m)
2871 D.fromStreamD $ D.splitSuffixOn True patt f (D.toStreamD m)