on master help sign in
Make some doc updates in Streamly.Data.Stream.*
commit9cce0ebeedc9d5f7576b621223d7c01745965bef authorHarendra Kumar <harendra@composewell.com> dateFri 19 Aug 2022, 13:12 (4 years ago) parent0dc91ab
10 files changed+231−183
core/src/Streamly/Data/Stream.hs+115−100 core/src/Streamly/Internal/Data/Stream/Bottom.hs−4 core/src/Streamly/Internal/Data/Stream/Eliminate.hs+10−6 core/src/Streamly/Internal/Data/Stream/Expand.hs+20−18 core/src/Streamly/Internal/Data/Stream/Generate.hs+4 core/src/Streamly/Internal/Data/Stream/Reduce.hs+8−5 core/src/Streamly/Internal/Data/Stream/Top.hs+5−6 core/src/Streamly/Internal/Data/Stream/Transform.hs+38−32 core/src/Streamly/Internal/Data/Stream/Type.hs+25−11 core/src/Streamly/Internal/Data/Stream/WSerial.hs+6−1
core/src/Streamly/Data/Stream.hs+115−100
@@ -18,20 +18,9 @@
1818--
1919-- We will add some more imports in the examples as needed.
2020--
21−-- For effectful streams we will use the following IO action that blocks for
22−-- @n@ seconds:
21+-- For effectful streams we will use the following IO action:
2322--
24−-- >>> import Control.Concurrent (threadDelay)
25−-- >>> :{
26−-- delay n = do
27−-- threadDelay (n * 1000000) -- sleep for n seconds
28−-- putStrLn (show n ++ " sec") -- print "n sec"
29−-- return n -- IO Int
30−-- :}
31−--
32−-- >>> delay 1
33−-- 1 sec
34−-- 1
23+-- >>> effect n = print n >> return n
3524--
3625-- = Overview
3726--
@@ -53,10 +42,10 @@
5342--
5443-- 'consM' constructs a stream from effectful actions:
5544--
56−-- >>> stream = delay 1 `consM` delay 2 `consM` nil
45+-- >>> stream = effect 1 `consM` effect 2 `consM` nil
5746-- >>> Stream.fold Fold.toList stream
58−-- 1 sec
59−-- 2 sec
47+-- 1
48+-- 2
6049-- [1,2]
6150--
6251-- == Console Echo Program
@@ -69,13 +58,13 @@
6958--
7059-- >>> import Data.Function ((&))
7160--
72−-- @
73−-- > :{
74−-- Stream.repeatM getLine -- Stream IO String
75−-- & Stream.mapM putStrLn -- Stream IO ()
76−-- & Stream.fold Fold.drain -- IO ()
61+-- >>> :{
62+-- echo =
63+-- Stream.repeat getLine -- Stream IO (IO String)
64+-- & Stream.sequence -- Stream IO String
65+-- & Stream.mapM putStrLn -- Stream IO ()
66+-- & Stream.fold Fold.drain -- IO ()
7767-- :}
78−-- @
7968--
8069-- This is a console echo program. It is an example of a declarative loop
8170-- written using streaming combinators. Compare it with an imperative @while@
@@ -84,85 +73,48 @@
8473-- Hopefully, this gives you an idea how we can program declaratively by
8574-- representing loops using streams. In this module, you can find all
8675-- "Data.List" like functions and many more powerful combinators to perform
87−-- common programming tasks. Also see "Streamly.Internal.Data.Stream.IsStream"
76+-- common programming tasks. Also see "Streamly.Internal.Data.Stream"
8877-- module for many more @Pre-release@ combinators. See the
8978-- <https://github.com/composewell/streamly-examples> repository for many more
9079-- real world examples of stream programming.
91−-- == Combining two streams
92−--
93−-- Two streams can be combined to form a single stream in various interesting
94−-- ways. 'serial' (append), 'wSerial' (interleave), 'ahead' (concurrent,
95−-- ordered append), 'async' (lazy concurrent, unordered append) , 'wAsync'
96−-- (lazy concurrent, unordered interleave), 'parallel' (strict concurrent
97−-- merge), 'zipWith', 'zipAsyncWith' (concurrent zip), 'mergeBy',
98−-- 'mergeAsyncBy' (concurrent merge) are some ways of combining two streams.
99−--
100−-- For example, the `parallel` combinator schedules both the streams
101−-- concurrently.
102−--
103−-- >>> stream1 = Stream.mapM id $ Stream.fromList [delay 3, delay 4]
104−-- >>> stream2 = Stream.mapM id $ Stream.fromList [delay 1, delay 2]
105−-- >>> Stream.fold Fold.toList $ stream1 `parallel` stream2
106−-- ...
107−--
108−-- We can chain the operations to combine more than two streams:
10980--
110−-- >>> stream3 = Stream.mapM id $ Stream.fromList [delay 1, delay 2]
111−-- >>> Stream.fold Fold.toList $ stream1 `parallel` stream2 `parallel` stream3
112−-- ...
81+-- == Combining two streams
11382--
114−-- Concurrent generation ('consM') and concurrent merging of streams is the
115−-- fundamental basis of all concurrency in streamly.
83+-- Two streams can be combined to form a single stream in several ways.
84+-- 'append', 'interleave', 'zipWith', 'mergeBy', are some ways of combining two
85+-- streams.
11686--
11787-- == Combining many streams
11888--
11989-- The 'concatMapWith' combinator can be used to generalize the two stream
120−-- combining combinators to @n@ streams. For example, we can use
121−-- @concatMapWith parallel@ to read concurrently from all incoming network
122−-- connections and combine the input streams into a single output stream:
123−--
124−-- @
125−-- import qualified Streamly.Network.Inet.TCP as TCP
126−-- import qualified Streamly.Network.Socket as Socket
127−--
128−-- Stream.unfold TCP.acceptOnPort 8090
129−-- & Stream.concatMapWith Stream.parallel (Stream.unfold Socket.read)
130−-- @
90+-- combining combinators to @n@ streams.
13191--
13292-- See the @streamly-examples@ repository for a full working example.
13393--
13494-- == Semigroup Instance
13595--
136−-- Earlier we distinguished stream types based on the execution behavior of
137−-- actions within a stream. Stream types are also distinguished based on how
138−-- actions from different streams are scheduled for execution when two streams
139−-- are combined together.
140−--
141−
142−-- For 'Stream', '<>' has an appending behavior i.e. it executes the actions
143−-- from the second stream after executing actions from the first stream:
96+-- The 'Semigroup' operation '<>' has an appending behavior i.e. it executes
97+-- the actions from the second stream after executing actions from the first
98+-- stream:
14499--
145−-- >>> stream1 = Stream.mapM id $ Stream.fromList [delay 1, delay 2]
146−-- >>> stream2 = Stream.mapM id $ Stream.fromList [delay 3, delay 4]
100+-- >>> stream1 = Stream.sequence $ Stream.fromList [effect 1, effect 2]
101+-- >>> stream2 = Stream.sequence $ Stream.fromList [effect 3, effect 4]
147102-- >>> Stream.fold Fold.toList $ stream1 <> stream2
148−-- 1 sec
149−-- 2 sec
150−-- 3 sec
151−-- 4 sec
103+-- 1
104+-- 2
105+-- 3
106+-- 4
152107-- [1,2,3,4]
153108--
154−-- By default, folds like 'drain' force the stream type to be 'Stream', so
155−-- 'replicateM' in the following code runs serially, and takes 10 seconds:
156−--
157−-- >>> Stream.fold Fold.drain $ Stream.replicateM 10 $ delay 1
158−-- ...
159−--
160109module Streamly.Data.Stream
161110 (
162111 Stream
163112 -- * Construction
164113 -- | Functions ending in the general shape @b -> Stream m a@.
165114 --
115+ -- See also: "Streamly.Internal.Data.Stream.Generate" for
116+ -- @Pre-release@ functions.
117+
166118 -- ** Primitives
167119 -- | Primitives to construct a stream from pure values or monadic actions.
168120 -- All other stream construction and generation combinators described later
@@ -172,10 +124,12 @@ module Streamly.Data.Stream
172124 , nil
173125 , cons
174126 , consM
127+ -- , cons2 -- fused version
128+ -- , consM2 -- fused version
175129
176130 -- ** Unfolding
177131 -- | Generalized way of generating a stream efficiently.
178− , unfold
132+ , unfold -- XXX rename to fromUnfold?
179133 , unfoldr
180134 , unfoldrM
181135
@@ -200,6 +154,7 @@ module Streamly.Data.Stream
200154 -- However, this is not particularly efficient.
201155 -- The 'Enumerable' type class provides corresponding functions that
202156 -- generate a stream instead of a list, efficiently.
157+
203158 , Enumerable (..)
204159 , enumerate
205160 , enumerateTo
@@ -217,16 +172,17 @@ module Streamly.Data.Stream
217172 -- * Elimination
218173 -- | Functions ending in the general shape @Stream m a -> m b@
219174 --
220− -- ** Running a 'Fold'
221− -- $runningfolds
222− , fold
175+ -- See also: "Streamly.Internal.Data.Stream.Eliminate" for
176+ -- @Pre-release@ functions.
223177
224178 -- ** Deconstruction
225179 -- | Functions ending in the general shape @Stream m a -> m (b, Stream m a)@
226180 , uncons
181+ -- , foldBreak
182+ -- , parseBreak
227183
228− -- ** General Folds
229−-- | In imperative terms a fold can be considered as a loop over the stream
184+ -- -- ** General Folds
185+-- EXPLANATION: In imperative terms a fold can be considered as a loop over the stream
230186-- that reduces the stream to a single value.
231187-- Left and right folds both use a fold function @f@ and an identity element
232188-- @z@ (@zero@) to deconstruct a recursive data structure and reconstruct a
@@ -289,13 +245,16 @@ module Streamly.Data.Stream
289245-- @
290246--
291247
292−-- As a general rule, foldr cannot have state and foldl cannot have control.
293−
294248-- NOTE: Folds are inherently serial as each step needs to use the result of
295249-- the previous step. However, it is possible to fold parts of the stream in
296250-- parallel and then combine the results using a monoid.
297251
298− -- *** Right Folds
252+ -- ** Left folds
253+ -- $runningfolds
254+ , fold -- XXX rename to run? We can have a Stream.run and Fold.run.
255+ -- XXX fold1 can be achieved using Monoids or Refolds.
256+
257+ -- ** Right Folds
299258 -- $rightfolds
300259 , foldrM
301260 , foldr
@@ -310,11 +269,16 @@ module Streamly.Data.Stream
310269 , stripPrefix
311270
312271 -- * Transformation
272+ -- | See also: "Streamly.Internal.Data.Stream.Transform" for
273+ -- @Pre-release@ functions.
274+
313275 -- ** Mapping
314276 -- | In imperative terms a map operation can be considered as a loop over
315277 -- the stream that transforms the stream into another stream by performing
316− -- an operation on each element of the stream.
317− --
278+ -- an operation on each element of the stream. Use 'fmap' for mapping a
279+ -- pure function on a stream.
280+
281+ -- EXPLANATION:
318282 -- 'map' is the least powerful transformation operation with strictest
319283 -- guarantees. A map, (1) is a stateless loop which means that no state is
320284 -- allowed to be carried from one iteration to another, therefore,
@@ -326,18 +290,20 @@ module Streamly.Data.Stream
326290 , mapM
327291
328292 -- ** Mapping Side Effects
329− , trace
293+ -- , trace -- XXX Use "tracing" map instead?
330294 , tap
331295 , delay
332296
333− -- ** Scanning By 'Fold'
297+ -- ** Scanning (Stateful Transformation)
334298 , scan
335299 , postscan
300+ -- XXX postscan1 can be implemented using Monoids or Refolds.
336301
337302 -- ** Filtering
338303 -- | Remove some elements from the stream based on a predicate. In
339304 -- imperative terms a filter over a stream corresponds to a loop with a
340305 -- @continue@ clause for the cases when the predicate fails.
306+
341307 , deleteBy
342308 , filter
343309 , filterM
@@ -354,6 +320,7 @@ module Streamly.Data.Stream
354320
355321 -- ** Inserting Elements
356322 -- | Inserting elements is a special case of interleaving/merging streams.
323+
357324 , insertBy
358325 , intersperseM
359326 , intersperse
@@ -371,7 +338,7 @@ module Streamly.Data.Stream
371338 -- | Finding the presence or location of an element, a sequence of elements
372339 -- or another stream within a stream.
373340
374− -- ** Searching Elements
341+ -- -- ** Searching Elements
375342 , findIndices
376343 , elemIndices
377344
@@ -379,22 +346,51 @@ module Streamly.Data.Stream
379346 , mapMaybe
380347 , mapMaybeM
381348
382− -- ** PairWise combinators
383− -- | These functions have O(n^2) append performance when used linearly e.g.
384− -- using 'concatMapWith'. However, they can be combined pair wise using
349+ -- * Combining Streams
350+ -- | New streams can be constructed by appending, merging or zipping
351+ -- existing streams.
352+ --
353+ -- See also: "Streamly.Internal.Data.Stream.Expand" for
354+ -- @Pre-release@ functions.
355+
356+ -- ** Appending
357+ , append
358+ , append2
359+
360+ -- ** Interleaving
361+ -- , interleave
362+ -- , interleave2
363+ , wSerial -- XXX rename to interleaveWeighted
364+
365+ -- ** Merging
366+ -- | Merging of @n@ streams can be performed by combining the streams pair
367+ -- wise using
385368 -- 'Streamly.Internal.Data.Stream.IsStream.Expand.concatPairsWith' to give
386− -- O(n * log n) complexity.
369+ -- O(n * log n) time complexity.
370+ -- If used with 'concatMapWith' it will have O(n^2) performance.
371+
387372 , mergeBy
388373 , mergeByM
374+ -- , mergeBy2
375+ -- , mergeByM2
376+
377+ -- ** Zipping
378+ -- | Zipping of @n@ streams can be performed by combining the streams pair
379+ -- wise using
380+ -- 'Streamly.Internal.Data.Stream.IsStream.Expand.concatPairsWith' with
381+ -- O(n * log n) time complexity.
382+ -- If used with 'concatMapWith' it will have O(n^2) performance.
389383 , zipWith
390384 , zipWithM
385+ -- , zipWith2
386+ -- , zipWithM2
391387
392− -- ** Nested Unfolds
388+ -- * Nested Unfolds
393389 , unfoldMany
394390 , intercalate
395391 , intercalateSuffix
396392
397− -- ** Nested Streams
393+ -- * Nested Streams
398394 -- | Stream operations like map and filter represent loop processing in
399395 -- imperative programming terms. Similarly, the imperative concept of
400396 -- nested loops are represented by streams of streams. The 'concatMap'
@@ -417,11 +413,15 @@ module Streamly.Data.Stream
417413 --
418414 -- > filter p m = S.concatMap (\x -> if p x then S.fromPure x else S.nil) m
419415 --
416+
420417 , concatMapWith
421418 , concatMap
422419 , concatMapM
423420
424421 -- * Nested Folds
422+ -- |
423+ -- See also: "Streamly.Internal.Data.Stream.Reduce" for
424+ -- @Pre-release@ functions.
425425 , foldMany
426426
427427 -- * Exceptions
@@ -429,21 +429,36 @@ module Streamly.Data.Stream
429429 -- possible, they should be called in an outer loop to mitigate the cost.
430430 -- For example, instead of calling them on a stream of chars call them on a
431431 -- stream of arrays before flattening it to a stream of chars.
432+ --
433+ -- See also: "Streamly.Internal.Data.Stream.Exception" for
434+ -- @Pre-release@ functions.
435+
436+ , onException
437+ , handle
438+
439+ -- * Resource Management
432440 , before
433441 , after
434− , bracket
435− , onException
436442 , finally
437− , handle
443+ , bracket
438444
439445 -- * Lifting Inner Monad
446+ -- | See also: "Streamly.Internal.Data.Stream.Lift" for
447+ -- @Pre-release@ functions.
448+
440449 , liftInner
441450 , runReaderT
442451 , runStateT
452+
453+ -- -- * Stream Types
454+ -- $serial
455+ -- , Interleave
456+ -- , Zip
443457 )
444458where
445459
446460import Streamly.Internal.Data.Stream
461+import Streamly.Internal.Data.Stream.WSerial (wSerial)
447462import Prelude
448463 hiding (filter, drop, dropWhile, take, takeWhile, zipWith, foldr,
449464 foldl, map, mapM, mapM_, sequence, all, any, sum, product, elem,
core/src/Streamly/Internal/Data/Stream/Bottom.hs−4
@@ -200,10 +200,6 @@ foldContinue f s = D.foldContinue f $ toStreamD s
200200-- >>> Stream.fold Fold.sum Stream.nil
201201-- 0
202202--
203−-- However, 'foldMany' on an empty stream results in an empty stream.
204−-- Therefore, @Stream.fold f@ is not the same as @Stream.head . Stream.foldMany
205−-- f@.
206−--
207203-- >>> fold f = Stream.parse (Parser.fromFold f)
208204--
209205-- @since 0.9.0
core/src/Streamly/Internal/Data/Stream/Eliminate.hs+10−6
@@ -126,6 +126,8 @@ import Prelude hiding (foldr, reverse)
126126-- (Just h, t) -> Just (h, t)
127127-- :}
128128--
129+-- /Not fused/
130+--
129131{-# INLINE uncons #-}
130132uncons :: Monad m => Stream m a -> m (Maybe (a, Stream m a))
131133uncons m = fmap (fmap (fmap fromStreamK)) $ K.uncons (toStreamK m)
@@ -146,7 +148,7 @@ uncons m = fmap (fmap (fmap fromStreamK)) $ K.uncons (toStreamK m)
146148--
147149-- Example, determine if any element is 'odd' in a stream:
148150--
149−-- >>> s = Stream.unfold Unfold.fromList (2:4:5:undefined)
151+-- >>> s = Stream.fromList (2:4:5:undefined)
150152-- >>> step x xs = if odd x then return True else xs
151153-- >>> Stream.foldrM step (return False) s
152154-- True
@@ -165,6 +167,8 @@ foldrM step acc m = D.foldrM step acc $ toStreamD m
165167-- would be strict in its accumulator and therefore would necessarily consume
166168-- all its input.
167169--
170+-- >>> foldr f z = Stream.foldrM (\a b -> f a <$> b) (return z)
171+--
168172{-# INLINE foldr #-}
169173foldr :: Monad m => (a -> b -> b) -> b -> Stream m a -> m b
170174foldr f z = foldrM (\a b -> f a <$> b) (return z)
@@ -188,7 +192,7 @@ foldlS f z =
188192--
189193-- For example, to reverse a stream:
190194--
191−-- >>> input = Stream.unfold Unfold.fromList [1..5] :: Stream IO Int
195+-- >>> input = Stream.fromList [1..5] :: Stream IO Int
192196-- >>> rev = Stream.fold Fold.toList $ Stream.foldlT (flip Stream.cons) Stream.nil input
193197--
194198{-# INLINE foldlT #-}
@@ -257,7 +261,7 @@ parseBreak p strm = fmap f $ K.parseBreak (PRD.fromParserK p) (toStreamK strm)
257261-- | Returns 'True' if the first stream is the same as or a prefix of the
258262-- second. A stream is a prefix of itself.
259263--
260−-- >>> Stream.isPrefixOf (Stream.unfold Unfold.fromList "hello") (Stream.unfold Unfold.fromList "hello" :: Stream IO Char)
264+-- >>> Stream.isPrefixOf (Stream.fromList "hello") (Stream.fromList "hello" :: Stream IO Char)
261265-- True
262266--
263267{-# INLINE isPrefixOf #-}
@@ -267,7 +271,7 @@ isPrefixOf m1 m2 = D.isPrefixOf (toStreamD m1) (toStreamD m2)
267271-- | Returns 'True' if the first stream is an infix of the second. A stream is
268272-- considered an infix of itself.
269273--
270−-- >>> s = Stream.unfold Unfold.fromList "hello" :: Stream IO Char
274+-- >>> s = Stream.fromList "hello" :: Stream IO Char
271275-- >>> Stream.isInfixOf s s
272276-- True
273277--
@@ -305,7 +309,7 @@ isInfixOf infx stream = do
305309-- | Returns 'True' if the first stream is a suffix of the second. A stream is
306310-- considered a suffix of itself.
307311--
308−-- >>> Stream.isSuffixOf (Stream.unfold Unfold.fromList "hello") (Stream.unfold Unfold.fromList "hello" :: Stream IO Char)
312+-- >>> Stream.isSuffixOf (Stream.fromList "hello") (Stream.fromList "hello" :: Stream IO Char)
309313-- True
310314--
311315-- Space: @O(n)@, buffers entire input stream and the suffix.
@@ -322,7 +326,7 @@ isSuffixOf suffix stream = reverse suffix `isPrefixOf` reverse stream
322326-- the second stream. The elements do not have to occur consecutively. A stream
323327-- is a subsequence of itself.
324328--
325−-- >>> Stream.isSubsequenceOf (Stream.unfold Unfold.fromList "hlo") (Stream.unfold Unfold.fromList "hello" :: Stream IO Char)
329+-- >>> Stream.isSubsequenceOf (Stream.fromList "hlo") (Stream.fromList "hello" :: Stream IO Char)
326330-- True
327331--
328332{-# INLINE isSubsequenceOf #-}
core/src/Streamly/Internal/Data/Stream/Expand.hs+20−18
@@ -148,15 +148,13 @@ import Prelude hiding (concat, concatMap, zipWith)
148148
149149infixr 6 `append2`
150150
151−-- | Append the outputs of two streams, yielding all the elements from the
152−-- first stream and then yielding all the elements from the second stream.
151+-- | This is fused version of 'append'. It could be up to 100x faster than
152+-- 'append' when combining two fusible streams. However, it slows down
153+-- quadratically with the number of streams being appended. Therefore, it is
154+-- suitable for ad-hoc append of a few streams, and should not be used with
155+-- 'concatMapWith' or 'concatPairsWith'.
153156--
154−-- IMPORTANT NOTE: This could be 100x faster than @serial/<>@ for appending a
155−-- few (say 100) streams because it can fuse via stream fusion. However, it
156−-- does not scale for a large number of streams (say 1000s) and becomes
157−-- qudartically slow. Therefore use this for custom appending of a few streams
158−-- but use 'concatMap' or 'concatMapWith serial' for appending @n@ streams or
159−-- infinite containers of streams.
157+-- /Fused/
160158--
161159-- /Pre-release/
162160{-# INLINE append2 #-}
@@ -168,12 +166,16 @@ infixr 6 `append`
168166-- | Appends two streams sequentially, yielding all elements from the first
169167-- stream, and then all elements from the second stream.
170168--
171−-- >>> s1 = Stream.unfold Unfold.fromList [1,2]
172−-- >>> s2 = Stream.unfold Unfold.fromList [3,4]
169+-- >>> s1 = Stream.fromList [1,2]
170+-- >>> s2 = Stream.fromList [3,4]
173171-- >>> Stream.fold Fold.toList $ s1 `Stream.append` s2
174172-- [1,2,3,4]
175173--
176−-- This operation can be used to fold an infinite lazy container of streams.
174+-- This has O(n) append performance where @n@ is the number of streams. It can
175+-- be used to efficiently fold an infinite lazy container of streams
176+-- 'concatMapWith' et. al.
177+--
178+-- /Not fused/
177179--
178180-- /Pre-release/
179181--
@@ -193,8 +195,8 @@ append = (<>)
193195-- If the streams are sorted in ascending order, the resulting stream would
194196-- also remain sorted in ascending order.
195197--
196−-- >>> s1 = Stream.unfold Unfold.fromList [1,3,5]
197−-- >>> s2 = Stream.unfold Unfold.fromList [2,4,6,8]
198+-- >>> s1 = Stream.fromList [1,3,5]
199+-- >>> s2 = Stream.fromList [2,4,6,8]
198200-- >>> Stream.fold Fold.toList $ Stream.mergeBy compare s1 s2
199201-- [1,2,3,4,5,6,8]
200202--
@@ -218,8 +220,8 @@ mergeBy f m1 m2 = fromStreamK $ K.mergeBy f (toStreamK m1) (toStreamK m2)
218220--
219221-- >>> :{
220222-- do
221−-- let s1 = Stream.unfold Unfold.fromList [1,1,1,1,1,1]
222−-- s2 = Stream.unfold Unfold.fromList [2,2,2]
223+-- let s1 = Stream.fromList [1,1,1,1,1,1]
224+-- s2 = Stream.fromList [2,2,2]
223225-- let proportionately m n = do
224226-- ref <- newIORef $ cycle $ Prelude.concat [Prelude.replicate m LT, Prelude.replicate n GT]
225227-- return $ \_ _ -> do
@@ -347,7 +349,7 @@ gintercalate unf1 str1 unf2 str2 =
347349-- >>> intersperse = Stream.intercalate Unfold.identity
348350-- >>> unwords = Stream.intercalate Unfold.fromList " "
349351--
350−-- >>> input = Stream.unfold Unfold.fromList ["abc", "def", "ghi"]
352+-- >>> input = Stream.fromList ["abc", "def", "ghi"]
351353-- >>> Stream.fold Fold.toList $ Stream.intercalate Unfold.fromList " " input
352354-- "abc def ghi"
353355--
@@ -377,7 +379,7 @@ gintercalateSuffix unf1 str1 unf2 str2 =
377379-- >>> intersperseSuffix = Stream.intercalateSuffix Unfold.identity
378380-- >>> unlines = Stream.intercalateSuffix Unfold.fromList "\n"
379381--
380−-- >>> input = Stream.unfold Unfold.fromList ["abc", "def", "ghi"]
382+-- >>> input = Stream.fromList ["abc", "def", "ghi"]
381383-- >>> Stream.fold Fold.toList $ Stream.intercalateSuffix Unfold.fromList "\n" input
382384-- "abc\ndef\nghi\n"
383385--
@@ -430,7 +432,7 @@ concatSmapMWith combine f initial =
430432--
431433-- For example, you can sort a stream using merge sort like this:
432434--
433−-- >>> s = Stream.unfold Unfold.fromList [5,1,7,9,2]
435+-- >>> s = Stream.fromList [5,1,7,9,2]
434436-- >>> generate = Stream.fromPure
435437-- >>> combine = Stream.mergeBy compare
436438-- >>> Stream.fold Fold.toList $ Stream.concatPairsWith combine generate s
core/src/Streamly/Internal/Data/Stream/Generate.hs+4
@@ -367,6 +367,8 @@ iterateM step = fromStreamD . D.iterateM step
367367-- Note that the function @f@ must be lazy in its argument, that's why we use
368368-- 'unsafeInterleaveIO' on @action@ because IO monad is strict.
369369--
370+-- /Not fused/
371+--
370372-- /Pre-release/
371373{-# INLINE mfix #-}
372374mfix :: Monad m => (m a -> Stream m a) -> Stream m a
@@ -381,6 +383,8 @@ mfix f = fromStreamK $ K.mfix (toStreamK . f)
381383--
382384-- Construct a stream from a 'Foldable' containing pure values:
383385--
386+-- /Not fused/
387+--
384388{-# INLINE fromFoldable #-}
385389fromFoldable :: Foldable f => f a -> Stream m a
386390fromFoldable = fromStreamK . K.fromFoldable
core/src/Streamly/Internal/Data/Stream/Reduce.hs+8−5
@@ -131,17 +131,20 @@ dropSuffix = error "Not implemented yet!"
131131-- To sum every two contiguous elements in a stream:
132132--
133133-- >>> f = Fold.take 2 Fold.sum
134−-- >>> Stream.fold Fold.toList $ Stream.foldMany f $ Stream.unfold Unfold.fromList [1..10]
134+-- >>> Stream.fold Fold.toList $ Stream.foldMany f $ Stream.fromList [1..10]
135135-- [3,7,11,15,19]
136136--
137137-- On an empty stream the output is empty:
138138--
139−-- >>> Stream.fold Fold.toList $ Stream.foldMany f $ Stream.unfold Unfold.fromList []
139+-- >>> Stream.fold Fold.toList $ Stream.foldMany f $ Stream.fromList []
140140-- []
141141--
142142-- Note @Stream.foldMany (Fold.take 0)@ would result in an infinite loop in a
143143-- non-empty stream.
144144--
145+-- Note 'foldMany' on an empty stream results in an empty stream. Therefore,
146+-- @Stream.fold f@ is not the same as @Stream.head . Stream.foldMany f@.
147+--
145148{-# INLINE foldMany #-}
146149foldMany
147150 :: Monad m
@@ -177,7 +180,7 @@ foldSequence _f _m = undefined
177180--
178181-- >>> import Data.Monoid (Sum(..))
179182-- >>> f x = return (Fold.take 2 (Fold.sconcat x))
180−-- >>> s = fmap Sum $ Stream.unfold Unfold.fromList [1..10]
183+-- >>> s = fmap Sum $ Stream.fromList [1..10]
181184-- >>> Stream.fold Fold.toList $ fmap getSum $ Stream.foldIterateM f (pure 0) s
182185-- [3,10,21,36,55,55]
183186--
@@ -210,7 +213,7 @@ refoldIterateM c i m = fromStreamD $ D.refoldIterateM c i (toStreamD m)
210213-- This is the streaming equivalent of the 'Streamly.Internal.Data.Parser.many'
211214-- parse combinator.
212215--
213−-- >>> s = Stream.unfold Unfold.fromList [1..10]
216+-- >>> s = Stream.fromList [1..10]
214217-- >>> parser = Parser.takeBetween 0 2 Fold.sum
215218-- >>> Stream.fold Fold.toList $ Stream.parseMany parser s
216219-- [3,7,11,15,19]
@@ -281,7 +284,7 @@ parseManyTill = undefined
281284-- the result is used to generate the next parser and so on.
282285--
283286-- >>> import Data.Monoid (Sum(..))
284−-- >>> s = Stream.unfold Unfold.fromList [1..10]
287+-- >>> s = Stream.fromList [1..10]
285288-- >>> Stream.fold Fold.toList $ fmap getSum $ Stream.parseIterate (\b -> Parser.takeBetween 0 2 (Fold.sconcat b)) 0 $ fmap Sum s
286289-- [3,10,21,36,55,55]
287290--
core/src/Streamly/Internal/Data/Stream/Top.hs+5−6
@@ -68,7 +68,6 @@ import qualified Streamly.Internal.Data.Stream.Expand as Stream
6868import qualified Streamly.Internal.Data.Stream.Reduce as Stream
6969import qualified Streamly.Internal.Data.Stream.Transform as Stream
7070import qualified Streamly.Internal.Data.Stream.StreamD as StreamD
71−import qualified Streamly.Internal.Data.Unfold as Unfold
7271
7372import Prelude hiding (filter, zipWith, concatMap, concat)
7473
@@ -371,7 +370,7 @@ joinOuter eq s1 s =
371370 foundArr <-
372371 Stream.fold
373372 (MA.writeN len)
374− (Stream.unfold Unfold.fromList (Prelude.replicate len False))
373+ (Stream.fromList (Prelude.replicate len False))
375374 return $ go inputArr foundArr <> leftOver inputArr foundArr
376375
377376 where
@@ -436,7 +435,7 @@ joinOuterMap s1 s2 =
436435 -- XXX Not sure if toList/fromList would fuse optimally. We may have to
437436 -- create a fused Map.toStream function.
438437 let res1 = fmap (joinAB km2)
439− $ Stream.unfold Unfold.fromList $ Map.toList km1
438+ $ Stream.fromList $ Map.toList km1
440439 where
441440 joinAB km (k, a) =
442441 case k `Map.lookup` km of
@@ -448,7 +447,7 @@ joinOuterMap s1 s2 =
448447 -- in the second Map, we can flag it in the first pass and not do any
449448 -- lookup in the second pass if it is flagged.
450449 let res2 = Stream.mapMaybe (joinAB km1)
451− $ Stream.unfold Unfold.fromList $ Map.toList km2
450+ $ Stream.fromList $ Map.toList km2
452451 where
453452 joinAB km (k, b) =
454453 case k `Map.lookup` km of
@@ -569,7 +568,7 @@ differenceBy eq s1 s2 =
569568 -- deleted or not.
570569 xs <- Stream.fold Fold.toList s1
571570 let f = Fold.foldl' (flip (List.deleteBy eq)) xs
572− fmap (Stream.unfold Unfold.fromList) $ Stream.fold f s2
571+ fmap Stream.fromList $ Stream.fold f s2
573572
574573-- | Like 'differenceBy' but works only on sorted streams.
575574--
@@ -616,7 +615,7 @@ unionBy eq s1 s2 =
616615 s3 = Stream.concatM
617616 $ do
618617 xs1 <- liftIO $ readIORef ref
619− return $ Stream.unfold Unfold.fromList xs1
618+ return $ Stream.fromList xs1
620619 return $ Stream.mapM f s1 <> s3
621620
622621-- | Like 'unionBy' but works only on sorted streams.
core/src/Streamly/Internal/Data/Stream/Transform.hs+38−32
@@ -150,6 +150,7 @@ import Prelude hiding
150150-- $setup
151151-- >>> :m
152152-- >>> import Control.Concurrent (threadDelay)
153+-- >>> import Control.Monad.IO.Class (MonadIO (liftIO))
153154-- >>> import Control.Monad.Trans (lift)
154155-- >>> import Control.Monad.Trans.Identity (runIdentityT)
155156-- >>> import Data.Function ((&))
@@ -192,21 +193,21 @@ transform pipe xs = fromStreamD $ D.transform pipe (toStreamD xs)
192193-- stateful transformations. However, note that the custom map and filter
193194-- routines can be much more efficient than this due to better stream fusion.
194195--
195−-- >>> input = Stream.unfold Unfold.fromList [1..5]
196+-- >>> input = Stream.fromList [1..5]
196197-- >>> Stream.fold Fold.toList $ Stream.foldrS Stream.cons Stream.nil input
197198-- [1,2,3,4,5]
198199--
199200-- Find if any element in the stream is 'True':
200201--
201202-- >>> step x xs = if odd x then return True else xs
202−-- >>> input = Stream.unfold Unfold.fromList (2:4:5:undefined) :: Stream IO Int
203+-- >>> input = Stream.fromList (2:4:5:undefined) :: Stream IO Int
203204-- >>> Stream.fold Fold.toList $ Stream.foldrS step (return False) input
204205-- [True]
205206--
206207-- Map (+2) on odd elements and filter out the even elements:
207208--
208209-- >>> step x xs = if odd x then (x + 2) `Stream.cons` xs else xs
209−-- >>> input = Stream.unfold Unfold.fromList [1..5] :: Stream IO Int
210+-- >>> input = Stream.fromList [1..5] :: Stream IO Int
210211-- >>> Stream.fold Fold.toList $ Stream.foldrS step Stream.nil input
211212-- [3,5,7]
212213--
@@ -252,7 +253,7 @@ foldrT f z s = D.foldrT f z (toStreamD s)
252253-- Apply a monadic function to each element of the stream and replace it with
253254-- the output of the resulting action.
254255--
255−-- >>> s = Stream.unfold Unfold.fromList ["a", "b", "c"]
256+-- >>> s = Stream.fromList ["a", "b", "c"]
256257-- >>> Stream.fold Fold.drain $ Stream.mapM putStr s
257258-- abc
258259--
@@ -263,12 +264,12 @@ mapM :: Monad m => (a -> m b) -> Stream m a -> Stream m b
263264mapM f m = fromStreamK $ D.toStreamK $ D.mapM f $ toStreamD m
264265
265266-- |
266−-- sequence = Stream.mapM id
267+-- >>> sequence = Stream.mapM id
267268--
268269-- Replace the elements of a stream of monadic actions with the outputs of
269270-- those actions.
270271--
271−-- >>> s = Stream.unfold Unfold.fromList [putStr "a", putStr "b", putStrLn "c"]
272+-- >>> s = Stream.fromList [putStr "a", putStr "b", putStrLn "c"]
272273-- >>> Stream.fold Fold.drain $ Stream.sequence s
273274-- abc
274275--
@@ -291,7 +292,7 @@ sequence = mapM id
291292--
292293-- @
293294--
294−-- >>> s = Stream.unfold Unfold.enumerateFromTo (1, 2)
295+-- >>> s = Stream.enumerateFromTo 1 2
295296-- >>> Stream.fold Fold.drain $ Stream.tap (Fold.drainBy print) s
296297-- 1
297298-- 2
@@ -305,7 +306,7 @@ tap f xs = fromStreamD $ D.tap f (toStreamD xs)
305306-- | Apply a monadic function to each element flowing through the stream and
306307-- discard the results.
307308--
308−-- >>> s = Stream.unfold Unfold.enumerateFromTo (1, 2)
309+-- >>> s = Stream.enumerateFromTo 1 2
309310-- >>> Stream.fold Fold.drain $ Stream.trace print s
310311-- 1
311312-- 2
@@ -319,7 +320,7 @@ trace f = mapM (\x -> void (f x) >> return x)
319320-- | Perform a side effect before yielding each element of the stream and
320321-- discard the results.
321322--
322−-- >>> s = Stream.unfold Unfold.enumerateFromTo (1, 2)
323+-- >>> s = Stream.enumerateFromTo 1 2
323324-- >>> Stream.fold Fold.drain $ Stream.trace_ (print "got here") s
324325-- "got here"
325326-- "got here"
@@ -348,16 +349,20 @@ trace_ eff = fromStreamD . D.mapM (\x -> eff >> return x) . toStreamD
348349
349350-- | Strict left scan. Scan a stream using the given monadic fold.
350351--
351−-- >>> s = Stream.unfold Unfold.fromList [1..10]
352+-- >>> s = Stream.fromList [1..10]
352353-- >>> Stream.fold Fold.toList $ Stream.takeWhile (< 10) $ Stream.scan Fold.sum s
353354-- [0,1,3,6]
354355--
356+-- See also: 'usingStateT'
357+--
358+
359+-- EXPLANATION:
355360-- >>> scanl' step z = Stream.scan (Fold.foldl' step z)
356361--
357362-- Like 'map', 'scanl'' too is a one to one transformation,
358363-- however it adds an extra element.
359364--
360−-- >>> s = Stream.unfold Unfold.fromList [1,2,3,4]
365+-- >>> s = Stream.fromList [1,2,3,4]
361366-- >>> Stream.fold Fold.toList $ scanl' (+) 0 s
362367-- [0,1,3,6,10]
363368--
@@ -386,7 +391,7 @@ trace_ eff = fromStreamD . D.mapM (\x -> eff >> return x) . toStreamD
386391-- >>> :{
387392-- foldl' (\(_, p) (s, x) -> (s, p * x)) (0,1)
388393-- $ scanl' (\(s, _) x -> (s + x, x)) (0,1)
389−-- $ Stream.unfold Unfold.fromList [1,2,3,4]
394+-- $ Stream.fromList [1,2,3,4]
390395-- :}
391396-- (10,24)
392397--
@@ -394,8 +399,6 @@ trace_ eff = fromStreamD . D.mapM (\x -> eff >> return x) . toStreamD
394399-- lazy expressions inside the accumulator, it is recommended that a strict
395400-- data structure is used for accumulator.
396401--
397−-- See also: 'usingStateT'
398−--
399402{-# INLINE scan #-}
400403scan :: Monad m => Fold m a b -> Stream m a -> Stream m b
401404scan fld m = fromStreamD $ D.scanOnce fld $ toStreamD m
@@ -441,7 +444,7 @@ filterM p m = fromStreamD $ D.filterM p $ toStreamD m
441444
442445-- | Use a filtering fold on a stream.
443446--
444−-- >>> input = Stream.unfold Unfold.fromList [1..10]
447+-- >>> input = Stream.fromList [1..10]
445448-- >>> Stream.fold Fold.sum $ Stream.foldFilter (Fold.satisfy (> 5)) input
446449-- 40
447450--
@@ -458,7 +461,7 @@ foldFilter p = fromStreamD . D.foldFilter p . toStreamD
458461--
459462-- To strip duplicate path separators:
460463--
461−-- >>> input = Stream.unfold Unfold.fromList "//a//b"
464+-- >>> input = Stream.fromList "//a//b"
462465-- >>> f x y = x == '/' && y == '/'
463466-- >>> Stream.fold Fold.toList $ Stream.uniqBy f input
464467-- "/a/b"
@@ -539,7 +542,7 @@ nubBy = undefined -- fromStreamD . D.nubBy . toStreamD
539542-- | Deletes the first occurrence of the element in the stream that satisfies
540543-- the given equality predicate.
541544--
542−-- >>> input = Stream.unfold Unfold.fromList [1,3,3,5]
545+-- >>> input = Stream.fromList [1,3,3,5]
543546-- >>> Stream.fold Fold.toList $ Stream.deleteBy (==) 3 input
544547-- [1,3,5]
545548--
@@ -579,7 +582,7 @@ dropWhileM p m = fromStreamD $ D.dropWhileM p $ toStreamD m
579582--
580583-- >>> insertBy cmp x = Stream.mergeBy cmp (Stream.fromPure x)
581584--
582−-- >>> input = Stream.unfold Unfold.fromList [1,3,5]
585+-- >>> input = Stream.fromList [1,3,5]
583586-- >>> Stream.fold Fold.toList $ Stream.insertBy compare 2 input
584587-- [1,2,3,5]
585588--
@@ -589,7 +592,7 @@ insertBy cmp x m = fromStreamD $ D.insertBy cmp x (toStreamD m)
589592
590593-- | Insert a pure value between successive elements of a stream.
591594--
592−-- >>> input = Stream.unfold Unfold.fromList "hello"
595+-- >>> input = Stream.fromList "hello"
593596-- >>> Stream.fold Fold.toList $ Stream.intersperse ',' input
594597-- "h,e,l,l,o"
595598--
@@ -600,7 +603,7 @@ intersperse a = fromStreamD . D.intersperse a . toStreamD
600603-- | Insert a side effect before consuming an element of a stream except the
601604-- first one.
602605--
603−-- >>> input = Stream.unfold Unfold.fromList "hello"
606+-- >>> input = Stream.fromList "hello"
604607-- >>> Stream.fold Fold.drain $ Stream.trace putChar $ Stream.intersperseM_ (putChar '.') input
605608-- h.e.l.l.o
606609--
@@ -612,7 +615,7 @@ intersperseM_ m = fromStreamD . D.intersperseM_ m . toStreamD
612615-- | Intersperse a monadic action into the input stream after every @n@
613616-- elements.
614617--
615−-- >> input = Stream.unfold Unfold.fromList "hello"
618+-- >> input = Stream.fromList "hello"
616619-- >> Stream.fold Fold.toList $ Stream.intersperseBySpan 2 (return ',') input
617620-- "he,ll,o"
618621--
@@ -624,7 +627,7 @@ intersperseBySpan _n _f _xs = undefined
624627
625628-- | Insert an effect and its output after consuming an element of a stream.
626629--
627−-- >>> input = Stream.unfold Unfold.fromList "hello"
630+-- >>> input = Stream.fromList "hello"
628631-- >>> Stream.fold Fold.toList $ Stream.trace putChar $ intersperseSuffix (putChar '.' >> return ',') input
629632-- h.,e.,l.,l.,o.,"h,e,l,l,o,"
630633--
@@ -635,7 +638,7 @@ intersperseSuffix m = fromStreamD . D.intersperseSuffix m . toStreamD
635638
636639-- | Insert a side effect after consuming an element of a stream.
637640--
638−-- >>> input = Stream.unfold Unfold.fromList "hello"
641+-- >>> input = Stream.fromList "hello"
639642-- >>> Stream.fold Fold.toList $ Stream.intersperseSuffix_ (threadDelay 1000000) input
640643-- "hello"
641644--
@@ -650,7 +653,7 @@ intersperseSuffix_ m = fromStreamD . D.intersperseSuffix_ m . toStreamD
650653-- | Like 'intersperseSuffix' but intersperses an effectful action into the
651654-- input stream after every @n@ elements and after the last element.
652655--
653−-- >>> input = Stream.unfold Unfold.fromList "hello"
656+-- >>> input = Stream.fromList "hello"
654657-- >>> Stream.fold Fold.toList $ Stream.intersperseSuffixBySpan 2 (return ',') input
655658-- "he,ll,o,"
656659--
@@ -664,7 +667,7 @@ intersperseSuffixBySpan n eff =
664667
665668-- | Insert a side effect before consuming an element of a stream.
666669--
667−-- >>> input = Stream.unfold Unfold.fromList "hello"
670+-- >>> input = Stream.fromList "hello"
668671-- >>> Stream.fold Fold.toList $ Stream.trace putChar $ Stream.interspersePrefix_ (putChar '.' >> return ',') input
669672-- .h.e.l.l.o"hello"
670673--
@@ -682,12 +685,15 @@ interspersePrefix_ m = mapM (\x -> void m >> return x)
682685
683686-- | Introduce a delay of specified seconds between elements of the stream.
684687--
685−-- >>> input = Stream.unfold Unfold.enumerateFromTo (1, 3)
688+-- >>> input = Stream.enumerateFromTo 1 3
686689-- >>> Stream.fold (Fold.drainBy print) $ Stream.delay 1 input
687690-- 1
688691-- 2
689692-- 3
690693--
694+-- >>> sleep n = liftIO $ threadDelay $ round $ n * 1000000
695+-- >>> delay n = Stream.intersperseM_ $ sleep n
696+--
691697{-# INLINE delay #-}
692698delay :: MonadIO m => Double -> Stream m a -> Stream m a
693699delay n = intersperseM_ $ liftIO $ threadDelay $ round $ n * 1000000
@@ -695,7 +701,7 @@ delay n = intersperseM_ $ liftIO $ threadDelay $ round $ n * 1000000
695701-- | Introduce a delay of specified seconds after consuming an element of a
696702-- stream.
697703--
698−-- >>> input = Stream.unfold Unfold.enumerateFromTo (1, 3)
704+-- >>> input = Stream.enumerateFromTo 1 3
699705-- >>> Stream.fold (Fold.drainBy print) $ Stream.delayPost 1 input
700706-- 1
701707-- 2
@@ -710,7 +716,7 @@ delayPost n = intersperseSuffix_ $ liftIO $ threadDelay $ round $ n * 1000000
710716-- | Introduce a delay of specified seconds before consuming an element of a
711717-- stream.
712718--
713−-- >>> input = Stream.unfold Unfold.enumerateFromTo (1, 3)
719+-- >>> input = Stream.enumerateFromTo 1 3
714720-- >>> Stream.fold (Fold.drainBy print) $ Stream.delayPre 1 input
715721-- 1
716722-- 2
@@ -748,11 +754,11 @@ reassembleBy = undefined
748754-- |
749755-- >>> f = Fold.foldl' (\(i, _) x -> (i + 1, x)) (-1,undefined)
750756-- >>> indexed = Stream.postscan f
751−-- >>> indexed = Stream.zipWith (,) (Stream.unfold Unfold.enumerateFrom 0)
757+-- >>> indexed = Stream.zipWith (,) (Stream.enumerateFrom 0)
752758--
753759-- Pair each element in a stream with its index, starting from index 0.
754760--
755−-- >>> Stream.fold Fold.toList $ Stream.indexed $ Stream.unfold Unfold.fromList "hello"
761+-- >>> Stream.fold Fold.toList $ Stream.indexed $ Stream.fromList "hello"
756762-- [(0,'h'),(1,'e'),(2,'l'),(3,'l'),(4,'o')]
757763--
758764{-# INLINE indexed #-}
@@ -763,13 +769,13 @@ indexed = fromStreamD . D.indexed . toStreamD
763769-- >>> f n = Fold.foldl' (\(i, _) x -> (i - 1, x)) (n + 1,undefined)
764770-- >>> indexedR n = Stream.postscan (f n)
765771--
766−-- >>> s n = Stream.unfold Unfold.enumerateFromThen (n, (n - 1))
772+-- >>> s n = Stream.enumerateFromThen n (n - 1)
767773-- >>> indexedR n = Stream.zipWith (,) (s n)
768774--
769775-- Pair each element in a stream with its index, starting from the
770776-- given index @n@ and counting down.
771777--
772−-- >>> Stream.fold Fold.toList $ Stream.indexedR 10 $ Stream.unfold Unfold.fromList "hello"
778+-- >>> Stream.fold Fold.toList $ Stream.indexedR 10 $ Stream.fromList "hello"
773779-- [(10,'h'),(9,'e'),(8,'l'),(7,'l'),(6,'o')]
774780--
775781{-# INLINE indexedR #-}
core/src/Streamly/Internal/Data/Stream/Type.hs+25−11
@@ -88,7 +88,7 @@ import qualified Streamly.Internal.Data.Stream.StreamK.Type as K
8888--
8989-- >>> :{
9090-- Stream.fold Fold.toList $ do
91−-- x <- Stream.unfold Unfold.fromList [1,2] -- foreach x in stream
91+-- x <- Stream.fromList [1,2] -- foreach x in stream
9292-- return x
9393-- :}
9494-- [1,2]
@@ -97,8 +97,8 @@ import qualified Streamly.Internal.Data.Stream.StreamK.Type as K
9797--
9898-- >>> :{
9999-- Stream.fold Fold.toList $ do
100−-- x <- Stream.unfold Unfold.fromList [1,2] -- foreach x in stream
101−-- y <- Stream.unfold Unfold.fromList [3,4] -- foreach y in stream
100+-- x <- Stream.fromList [1,2] -- foreach x in stream
101+-- y <- Stream.fromList [3,4] -- foreach y in stream
102102-- return (x, y)
103103-- :}
104104-- [(1,3),(1,4),(2,3),(2,4)]
@@ -225,18 +225,24 @@ TRAVERSABLE_INSTANCE(Stream)
225225
226226infixr 5 `cons`
227227
228−-- | Construct a stream by adding a pure value at the head of an existing
229−-- stream. Same as the following but more efficient:
230−--
231−-- For example:
228+-- | A right associative prepend operation to add a pure value at the head of
229+-- an existing stream::
232230--
233231-- >>> s = 1 `Stream.cons` 2 `Stream.cons` 3 `Stream.cons` Stream.nil
234232-- >>> Stream.fold Fold.toList s
235233-- [1,2,3]
236234--
235+-- It can be used efficiently with 'Prelude.foldr':
236+--
237+-- >>> fromFoldable = Prelude.foldr Stream.cons Stream.nil
238+--
239+-- Same as the following but more efficient:
240+--
237241-- >>> cons x xs = return x `Stream.consM` xs
238242--
239−-- /Pre-release/
243+-- /Not fused/
244+--
245+-- @since 0.9.0
240246--
241247{-# INLINE_NORMAL cons #-}
242248cons :: a -> Stream m a -> Stream m a
@@ -244,17 +250,25 @@ cons x = fromStreamK . K.cons x . toStreamK
244250
245251infixr 5 `consM`
246252
247−-- | Constructs a stream by adding a monadic action at the head of an
248−-- existing stream. For example:
253+-- | A right associative prepend operation to add an effectful value at the
254+-- head of an existing stream::
249255--
250256-- >>> s = putStrLn "hello" `consM` putStrLn "world" `consM` Stream.nil
251257-- >>> Stream.fold Fold.drain s
252258-- hello
253259-- world
254260--
261+-- It can be used efficiently with 'Prelude.foldr':
262+--
263+-- >>> fromFoldableM = Prelude.foldr Stream.consM Stream.nil
264+--
265+-- Same as the following but more efficient:
266+--
255267-- >>> consM x xs = Stream.fromEffect x `Stream.append` xs
256268--
257−-- /Pre-release/
269+-- /Not fused/
270+--
271+-- @since 0.9.0
258272--
259273{-# INLINE consM #-}
260274{-# SPECIALIZE consM :: IO a -> Stream IO a -> Stream IO a #-}
core/src/Streamly/Internal/Data/Stream/WSerial.hs+6−1
@@ -151,8 +151,13 @@ wSerialK m1 m2 = mkStream $ \st yld sng stp -> do
151151-- | Interleaves two streams, yielding one element from each stream
152152-- alternately. When one stream stops the rest of the other stream is used in
153153-- the output stream.
154+--
155+-- This gives exponential priority to earlier streams than the ones joining
156+-- later. Because of exponential weighting it can be used with 'concatMapWith'.
157+--
158+-- /Not fused/
154159
155−-- Scheduling Notes:
160+-- NOTE:
156161--
157162-- Note that evaluation of @a \`wSerial` b \`wSerial` c@ does not interleave
158163-- @a@, @b@ and @c@ with equal priority. This expression is equivalent to @a