on 70fbefe help sign in
streamly/src/Streamly.hs
690 lines 27 kB history raw
1-- |
2-- Module : Streamly
3-- Copyright : (c) 2017 Composewell Technologies
4--
5-- License : BSD3
6-- Maintainer : streamly@composewell.com
7-- Stability : experimental
8-- Portability : GHC
9--
10-- Streamly is a general purpose programming framework using cocnurrent data
11-- flow programming paradigm. It can be considered as a generalization of
12-- Haskell lists to monadic streaming with concurrent composition capability.
13-- The serial stream type in streamly @SerialT m a@ is like the list type @[a]@
14-- parameterized by the monad @m@. For example, @SerialT IO a@ is a moral
15-- equivalent of @[a]@ in the IO monad. Streams are constructed very much like
16-- lists, except that they use 'nil' and 'cons' instead of '[]' and ':'.
17--
18-- @
19-- > import "Streamly"
20-- > import "Streamly.Prelude" (cons, consM)
21-- > import qualified "Streamly.Prelude" as S
22-- >
23-- > S.toList $ 1 \`cons` 2 \`cons` 3 \`cons` nil
24-- [1,2,3]
25-- @
26--
27-- Unlike lists, streams can be constructed from monadic effects:
28--
29-- @
30-- > S.'toList' $ 'getLine' \`consM` 'getLine' \`consM` S.'nil'
31-- hello
32-- world
33-- ["hello","world"]
34-- @
35--
36-- Streams are processed just like lists, with list like combinators, except
37-- that they are monadic and work in a streaming fashion. Here is a simple
38-- console echo program example:
39--
40-- @
41-- > S.drain $ S.repeatM getLine & S.mapM putStrLn
42-- @
43--
44-- @SerialT Identity a@ is a moral equivalent of pure lists. Streamly utilizes
45-- fusion for high performance, therefore, we can represent and process strings
46-- as streams of 'Char', encode and decode the streams to/from UTF8 and
47-- serialize them to @Array Word8@ obviating the need for special purpose
48-- libraries like @bytestring@ and @text@.
49--
50-- For more details
51-- please see the "Streamly.Tutorial" module and the examples directory in this
52-- package.
54{-# LANGUAGE NoMonomorphismRestriction #-}
55{-# OPTIONS_GHC -Wno-orphans #-}
57#include "inline.hs"
59module Streamly {-# DEPRECATED "Please use \"Streamly.Prelude\" instead." #-}
60 (
61 -- -- * Concepts Overview
62 -- -- ** Streams
63 -- -- $streams
65 -- -- ** Folds
66 -- -- $folds
68 -- -- ** Arrays
69 -- -- $arrays
71 -- * Module Overview
72 -- $streamtypes
74 -- * Type Synonyms
75 MonadAsync
77 -- * Stream transformers
78 -- | A stream represents a sequence of pure or effectful actions. The
79 -- `cons` and `consM` operations and the corresponding operators '.:' and
80 -- '|:' can be used to join pure values or effectful actions in a sequence.
81 -- The effects in the stream can be executed in many different ways
82 -- depending on the type of stream. In other words, the behavior of 'consM'
83 -- depends on the type of the stream.
84 --
85 -- There are three high level categories of streams, /spatially ordered/
86 -- streams, /speculative/ streams and /time ordered/ streams. Spatially
87 -- ordered streams, 'SerialT' and 'WSerialT', execute the effects in serial
88 -- order i.e. one at a time and present the outputs of those effects to the
89 -- consumer in the same order. Speculative streams, 'AheadT', may execute
90 -- many effects concurrently but present the outputs to the consumer in the
91 -- specified spatial order. Time ordered streams, 'AsyncT', 'WAsyncT' and
92 -- 'ParallelT', may execute many effects concurrently and present the
93 -- outputs of those effects to the consumer in time order i.e. as soon as
94 -- the output is generated.
95 --
96 -- We described above how the effects in a sequence are executed for
97 -- different types of streams. The behvavior of the 'Semigroup' and 'Monad'
98 -- instances follow the behavior of 'consM'. Stream generation operations
99 -- like 'repeatM' also execute the effects differently for different
100 -- streams, providing a concurrent generation capability when used with
101 -- stream types that execute effects concurrently. Similarly, effectful
102 -- transformation operations like 'mapM' also execute the transforming
103 -- effects differently for different types of streams.
105 -- ** Serial Streams
106 -- $serial
107 , SerialT
108 , WSerialT
110 -- ** Speculative Streams
111 -- $ahead
112 , AheadT
114 -- ** Asynchronous Streams
115 -- $async
116 , AsyncT
117 , WAsyncT
118 , ParallelT
120 -- ** Zipping Streams
121 -- $zipping
122 , ZipSerialM
123 , ZipAsyncM
125 -- * Parallel Function Application
126 -- $application
127 , (IP.|$)
128 , (IP.|&)
129 , (IP.|$.)
130 , (IP.|&.)
131 , mkAsync
133 -- * Merging Streams
134 -- $sum
135 , serial
136 , wSerial
137 , ahead
138 , async
139 , wAsync
140 , parallel
142 -- * Concurrency Control
143 -- $concurrency
144 , maxThreads
145 , maxBuffer
147 -- * Rate Limiting
148 , Rate (..)
149 , rate
150 , avgRate
151 , minRate
152 , maxRate
153 , constRate
155 -- * Stream Type Adapters
156 -- $adapters
157 , IsStream ()
159 , serially
160 , wSerially
161 , asyncly
162 , aheadly
163 , wAsyncly
164 , parallely
165 , zipSerially
166 , zipAsyncly
167 , adapt
169 -- * IO Streams
170 , Serial
171 , WSerial
172 , Ahead
173 , Async
174 , WAsync
175 , Parallel
176 , ZipSerial
177 , ZipAsync
179 -- ** Folding Containers of Streams
180 -- | These are variants of standard 'Foldable' fold functions that use a
181 -- polymorphic stream sum operation (e.g. 'async' or 'wSerial') to fold a
182 -- finite container of streams. Note that these are just special cases of
183 -- the more general 'concatMapWith' operation.
184 --
185 , foldWith
186 , foldMapWith
187 , forEachWith
189 -- * Re-exports
190 , Semigroup (..)
191 -- * Deprecated
192 , Streaming
193 , runStream
194 , runStreaming
195 , runStreamT
196 , runInterleavedT
197 , runAsyncT
198 , runParallelT
199 , runZipStream
200 , runZipAsync
201 , StreamT
202 , InterleavedT
203 , ZipStream
204 , interleaving
205 , zipping
206 , zippingAsync
207 , (<=>)
208 , (<|)
209 )
210where
212import Data.Semigroup (Semigroup(..))
213import Streamly.Internal.Control.Concurrent (MonadAsync)
214import Streamly.Internal.Data.SVar (Rate(..))
215import Streamly.Internal.Data.Stream.Ahead
216import Streamly.Internal.Data.Stream.Async
217import Streamly.Internal.Data.Stream.IsStream.Combinators
218import Streamly.Internal.Data.Stream.IsStream.Expand
219import Streamly.Internal.Data.Stream.IsStream.Type
220import Streamly.Internal.Data.Stream.Serial (StreamT, InterleavedT)
221import Streamly.Internal.Data.Stream.Zip
223import qualified Streamly.Prelude as P
224import qualified Streamly.Internal.Data.Stream.IsStream as IP
225import qualified Streamly.Internal.Data.Stream.IsStream.Transform as Transform
227-- XXX provide good succinct examples of pipelining, merging, splitting etc.
228-- below.
229--
230-- $streams
231--
232-- A program is expressed as a network of streams and folds. A stream is a
233-- source or generator of data elements and a fold is a consumer of data elements that
234-- reduces multiple input elements to a single value.
235--
236-- In the following example, a 'Word8' stream is generated by using
237-- 'Streamly.FileSystem.Handle.read' on a file handle, then the
238-- 'Streamly.Prelude.splitBySuffix' transformation splits the stream on
239-- newlines (ascii value 10); it uses the 'Streamly.Data.Fold.drain' fold to reduce
240-- the resulting lines to unit values (@()@), 'Streamly.Prelude.length' fold
241-- then counts the unit elements in the resulting stream which gives us the
242-- number of lines in the file:
243--
244-- > S.length $ S.splitOnSuffix FL.drain 10 $ FH.read fh
245--
246-- The following example folds the lines to arrays of 'Word8' using the
247-- 'Streamly.Data.Array.Foreign.writeF' fold and then wraps the lines in square
248-- brackets before writing them to standard output using
249-- 'Streamly.FileSystem.Handle.write':
250--
251-- > wrapLine ln = S.fromList "[" <> A.read ln <> S.fromList "]\n"
252-- > readLines = S.splitOnSuffix A.writeF 10
253-- > FH.write stdout $ S.concatMap wrapLine $ readLines fh1
254--
255-- One stream can be appended after another:
256--
257-- > FH.write stdout $ S.concatMap wrapLine $ readLines fh1 <> readLines fh2
258--
259-- The following example reads two files concurrently, merges the lines from
260-- the two streams and writes the resulting stream to another file:
261--
262-- > FH.write stdout $ S.concatMap wrapLine $ readLines fh1 `parallel` readLines fh2
263--
264-- There are many ways to generate, merge, zip, transform and fold data
265-- streams. Many transformations can be chained in a stream pipeline. See
266-- "Streamly.Prelude" module for combinators to manipulate streams.
268-- $folds
269--
270-- The way stream types in this module like 'SerialT' represent data sources,
271-- the same way the 'Fold' type from "Streamly.Data.Fold" represents data sinks or
272-- reducers of streams. Reducers can be combined to consume a stream source in
273-- many ways. The simplest is to reduce a stream source using a fold e.g.:
274--
275-- > S.fold FL.length $ S.enumerateTo 100
276--
277-- Folds are consumers of streams and can be used to split a stream into
278-- multiple independent flows. Grouping transforms a stream by applying a fold
279-- on segments of a stream, distributing applies multiple folds in parallel on
280-- the same stream and combines them, partitioning sends different elements of
281-- a stream to different folds, unzipping divides the elements of a stream into
282-- parts and sends them through different folds. Parsers are nothing but a
283-- particular type of folds. Transformations can be applied contravariantly on
284-- the input of a fold.
285--
286-- @
287--
288-- |---transform----Fold m a b--------|
289-- ---stream m a-->transform-->| |---f b c ...
290-- |---transform----Fold m a c--------|
291-- | |
292-- ...
293-- @
294--
296-- $arrays
297--
298-- Streamly arrays (See "Streamly.Data.Array.Foreign") complement streams to provide an
299-- efficient computing paradigm. Streams are suitable for immutable
300-- transformations of /potentially infinite/ data using /sequential access/ and
301-- pipelined transformations whereas arrays are suitable for in-place
302-- transformations of /necessarily finite/ data using /random access/. Streams
303-- are synonymous with /sequential pipelined processing/ whereas arrays are
304-- synonymous with /efficient buffering and random access/.
305--
306-- In general, a data processing pipeline reads data from some IO device, does
307-- some processing on it and finally writes the output to another IO device.
308-- Streams provide the overall framework of sequential processing pipeline in
309-- which arrays are used as buffering elements in the middle. In addition to
310-- buffering in the middle, arrays can also be used at the boundaries of the
311-- pipeline to efficiently interface with external storage systems like memory,
312-- files and network. If streams are the pipes in a water pipeline network
313-- then arrays are like the storage tanks in the middle. On the input side,
314-- think of arrays as buckets to fetch water to feed the pipeline and on the
315-- output side buckets to remove the processed water.
316--
317-- 'ByteString' data type from the 'bytestring' package and the 'Text' data
318-- type from the 'text' package are special cases of arrays. 'ByteString' is
319-- like @Array Word8@ and 'Text' is like @utf16@ encoded @Array Word8@.
320-- Streamly arrays can be transformed as efficiently as @bytestring@ or @text@
321-- by using stream operations on them.
323-- Streams and arrays are equally important in computing. They are computing
324-- duals of each other.
326-- $streamtypes
327-- The basic stream type is 'Serial', it represents a sequence of IO actions,
328-- and is a 'Monad'. The type 'SerialT' is a monad transformer that can
329-- represent a sequence of actions in an arbitrary monad. The type 'Serial' is
330-- in fact a synonym for @SerialT IO@. There are a few more types similar to
331-- 'SerialT', all of them represent a stream and differ only in the
332-- 'Semigroup', 'Applicative' and 'Monad' compositions of the stream. 'Serial'
333-- and 'WSerial' types compose serially whereas 'Async' and 'WAsync'
334-- types compose concurrently. All these types can be freely inter-converted
335-- using type combinators without any cost. You can freely switch to any type
336-- of composition at any point in the program. When no type annotation or
337-- explicit stream type combinators are used, the default stream type is
338-- inferred as 'Serial'.
339--
340-- This module exports stream types, instances and combinators for:
341--
342-- * converting between different stream types
343-- * appending and concurrently merging streams
344-- * Concurrency control
345-- * Concurrent function application
346-- * Stream rate control
347--
348-- This module is designed to be imported unqualified:
349--
350-- @
351-- import Streamly
352-- @
353--
354-- See the "Streamly.Prelude" module for APIs for construction,
355-- generation, elimination and transformation of streams.
357------------------------------------------------------------------------------
358-- Eliminating a stream
359------------------------------------------------------------------------------
361-- | Same as 'runStream'
362--
363-- @since 0.1.0
364{-# DEPRECATED runStreaming "Please use runStream instead." #-}
365runStreaming :: (Monad m, IsStream t) => t m a -> m ()
366runStreaming = P.drain . adapt
368-- | Same as @runStream@.
369--
370-- @since 0.1.0
371{-# DEPRECATED runStreamT "Please use runStream instead." #-}
372runStreamT :: Monad m => SerialT m a -> m ()
373runStreamT = P.drain
375-- | Same as "Streamly.Prelude.runStream".
376--
377{-# DEPRECATED runStream "Please use Streamly.Prelude.drain instead." #-}
378runStream :: Monad m => SerialT m a -> m ()
379runStream = P.drain
381-- | Same as @drain . fromWSerial@.
382--
383-- @since 0.1.0
384{-# DEPRECATED runInterleavedT "Please use 'drain . interleaving' instead." #-}
385runInterleavedT :: Monad m => WSerialT m a -> m ()
386runInterleavedT = P.drain . adapt
388-- | Same as @drain . fromParallel@.
389--
390-- @since 0.1.0
391{-# DEPRECATED runParallelT "Please use 'drain . fromParallel' instead." #-}
392runParallelT :: Monad m => ParallelT m a -> m ()
393runParallelT = P.drain . adapt
395-- | Same as @drain . fromAsync@.
396--
397-- @since 0.1.0
398{-# DEPRECATED runAsyncT "Please use 'drain . fromAsync' instead." #-}
399runAsyncT :: Monad m => AsyncT m a -> m ()
400runAsyncT = P.drain . adapt
402-- | Same as @drain . zipping@.
403--
404-- @since 0.1.0
405{-# DEPRECATED runZipStream "Please use 'drain . fromZipSerial instead." #-}
406runZipStream :: Monad m => ZipSerialM m a -> m ()
407runZipStream = P.drain . adapt
409-- | Same as @drain . zippingAsync@.
410--
411-- @since 0.1.0
412{-# DEPRECATED runZipAsync "Please use 'drain . fromZipAsync instead." #-}
413runZipAsync :: Monad m => ZipAsyncM m a -> m ()
414runZipAsync = P.drain . adapt
416{-
417-- | Same as "Streamly.Prelude.foldWith".
418--
419{-# DEPRECATED foldWith "Please use Streamly.Prelude.foldWith instead." #-}
420{-# INLINABLE foldWith #-}
421foldWith :: (IsStream t, Foldable f)
422 => (t m a -> t m a -> t m a) -> f (t m a) -> t m a
423foldWith = P.foldWith
425-- | Same as "Streamly.Prelude.foldMapWith".
426--
427{-# DEPRECATED foldMapWith "Please use Streamly.Prelude.foldMapWith instead." #-}
428{-# INLINABLE foldMapWith #-}
429foldMapWith :: (IsStream t, Foldable f)
430 => (t m b -> t m b -> t m b) -> (a -> t m b) -> f a -> t m b
431foldMapWith = P.foldMapWith
433-- | Same as "Streamly.Prelude.forEachWith".
434--
435{-# DEPRECATED forEachWith "Please use Streamly.Prelude.forEachWith instead." #-}
436{-# INLINABLE forEachWith #-}
437forEachWith :: (IsStream t, Foldable f)
438 => (t m b -> t m b -> t m b) -> f a -> (a -> t m b) -> t m b
439forEachWith = P.forEachWith
440-}
442-- XXX Deprecate it in 0.8.0
443--
444-- | Make a stream asynchronous, triggers the computation and returns a stream
445-- in the underlying monad representing the output generated by the original
446-- computation. The returned action is exhaustible and must be drained once. If
447-- not drained fully we may have a thread blocked forever and once exhausted it
448-- will always return 'empty'.
449--
450-- @since 0.2.0
451{-# INLINABLE mkAsync #-}
452mkAsync :: (IsStream t, MonadAsync m) => t m a -> m (t m a)
453mkAsync = return . Transform.mkAsync
455------------------------------------------------------------------------------
456-- Documentation
457------------------------------------------------------------------------------
459-- $serial
460--
461-- When a stream consumer demands an element from a serial stream constructed
462-- as @a \`consM` b \`consM` ... nil@, the action @a@ at the head of the stream
463-- sequence is executed and the result is supplied to the consumer. When the
464-- next element is demanded, the action @b@ is executed and its result is
465-- supplied. Thus, the effects are performed and results are consumed strictly
466-- in a serial order. Serial streams can be considered as /spatially ordered/
467-- streams as the order of execution and consumption is the same as the spatial
468-- order in which the actions are composed by the programmer.
469--
470-- Serial streams enforce the side effects as well as the results of the
471-- actions to be in the same order in which the actions are added to the
472-- stream. Therefore, the semigroup operation for serial streams is not
473-- commutative:
474--
475-- @
476-- a <> b is not the same as b <> a
477-- @
478--
479-- There are two serial stream types 'SerialT' and 'WSerialT'. The stream
480-- evaluation of both the variants works in the same way as described above,
481-- they differ only in the 'Semigroup' and 'Monad' implementaitons.
483-- $ahead
484--
485-- When a stream consumer demands an element from a speculative stream
486-- constructed as @a \`consM` b \`consM` ... nil@, the action @a@ at the head
487-- of the stream is executed and the output of the action is supplied to the
488-- consumer. However, in addition to the action at the head multiple actions
489-- following it may also be executed concurrently and the results buffered.
490-- When the next element is demanded it may be served from the buffer and we
491-- may execute the next action in the sequence to keep the buffer adequately
492-- filled. Thus, the actions are executed concurrently but results consumed in
493-- serial order just like serial streams. `consM` can be used to fold an
494-- infinite lazy container of effects, as the number of concurrent executions
495-- is limited.
496--
497-- Similar to 'consM', the monadic stream generation (e.g. replicateM) and
498-- transformation operations (e.g. mapM) on speculative streams can execute
499-- multiple effects concurrently in a speculative manner.
500--
501-- How many effects can be executed concurrently and how many results can be
502-- buffered are controlled by 'maxThreads' and 'maxBuffer' combinators
503-- respectively. The actual number of concurrent threads is adjusted according
504-- to the rate at which the consumer is consuming the stream. It may even
505-- execute actions serially in a single thread if that is enough to match the
506-- consumer's speed.
507--
508-- Speculative streams enforce ordering of the results of actions in the stream
509-- but the side effects are only partially ordered. Therefore, the semigroup
510-- operation for speculative streams is not commutative from the pure outputs
511-- perspective but commutative from side effects perspective.
513-- $async
514--
515-- /Scheduling and execution:/ In an asynchronous stream @a \`consM` b \`consM`
516-- c ...@, the actions @a@, @b@, and @c@ are executed concurrently with the
517-- consumer of the stream. The actions are /scheduled/ for execution in the
518-- same order as they are specified in the stream. Multiple scheduled actions
519-- may be /executed/ concurrently in parallel threads of execution. The
520-- actions may be executed out of order and they may complete at arbitrary
521-- times. Therefore, the /effects/ of the actions may be observed out of
522-- order.
523--
524-- /Buffering:/ The /results/ from multiple threads of execution are queued in
525-- a buffer as soon as they become available. The consumer of the stream is
526-- served from this buffer. Therefore, the consumer may observe the results to
527-- be out of order. In other words, an asynchronous stream is an unordered
528-- stream i.e. order does not matter.
529--
530-- /Concurrency control:/ Threads are suspended if the `maxBuffer` limit is
531-- reached, and resumed when the consumer makes space in the buffer. The
532-- maximum number of concurrent threads depends on `maxThreads`. Number of
533-- threads is increased or decreased based on the speed of the consumer.
534--
535-- /Generation operations:/ Concurrent stream generation operations e.g.
536-- 'Streamly.Prelude.replicateM' when used in async style schedule and execute
537-- the stream generating actions in the manner described above. The generation
538-- actions run concurrently, effects and results of the actions as observed by
539-- the consumer of the stream may be out of order.
540--
541-- /Transformation operations:/ Concurrent stream transformation operations
542-- e.g. 'Streamly.Prelude.mapM', when used in async style, schedule and
543-- execute transformation actions in the manner described above. Transformation
544-- actions run concurrently, effects and results of the actions may be
545-- observed by the consumer out of order.
546--
547-- /Variants:/ There are two asynchronous stream types 'AsyncT' and 'WAsyncT'.
548-- They are identical with respect to single stream evaluation behavior. Their
549-- behaviors differ in how they combine multiple streams using 'Semigroup' or
550-- 'Monad' composition. Since the order of elements does not matter in
551-- asynchronous streams the 'Semigroup' operation is effectively commutative.
553-- $zipping
554--
555-- 'ZipSerialM' and 'ZipAsyncM', provide 'Applicative' instances for zipping the
556-- corresponding elements of two streams together. Note that these types are
557-- not monads.
559-- $application
560--
561-- Stream processing functions can be composed in a chain using function
562-- application with or without the '$' operator, or with reverse function
563-- application operator '&'. Streamly provides concurrent versions of these
564-- operators applying stream processing functions such that each stage of the
565-- stream can run in parallel. The operators start with a @|@; we can read '|$'
566-- as "@parallel dollar@" to remember that @|@ comes before '$'.
567--
568-- Imports for the code snippets below:
569--
570-- @
571-- import Streamly
572-- import qualified Streamly.Prelude as S
573-- import Control.Concurrent
574-- @
576-- $sum
577-- The 'Semigroup' operation '<>' of each stream type combines two streams in a
578-- type specific manner. This section provides polymorphic versions of '<>'
579-- which can be used to combine two streams in a predetermined way irrespective
580-- of the type.
582-- XXX An alternative design choice would be to let a control parameter affect
583-- the nearest SVar only and then it gets cleared. The benefit of the current
584-- choice is that it is simply just like global configuration, just like state
585-- behaves, so should be easy to comprehend. But it has the downside of leaking
586-- to undesired actions, that is we can forget to reset it.
587--
588-- $concurrency
589--
590-- These combinators can be used at any point in a stream composition to set
591-- parameters to control the concurrency of the /argument stream/. A control
592-- parameter set at any point remains effective for any concurrent combinators
593-- used in the argument stream until it is reset by using the combinator again.
594-- These control parameters have no effect on non-concurrent combinators in the
595-- stream, or on non-concurrent streams.
596--
597-- /Pitfall:/ Remember that 'maxBuffer' in the following example applies to
598-- 'mapM' and any other combinators that may follow it, and it does not apply
599-- to the combinators before it:
600--
601-- @
602-- ...
603-- $ maxBuffer 10
604-- $ S.mapM ...
605-- ...
606-- @
607--
608-- If we use '&' instead of '$' the situation will reverse, in the following
609-- example, 'maxBuffer' does not apply to 'mapM', it applies to combinators
610-- that come before it, because those are the arguments to 'maxBuffer':
611--
612-- @
613-- ...
614-- & maxBuffer 10
615-- & S.mapM ...
616-- ...
617-- @
619-- $adapters
620--
621-- You may want to use different stream composition styles at different points
622-- in your program. Stream types can be freely converted or adapted from one
623-- type to another. The 'IsStream' type class facilitates type conversion of
624-- one stream type to another. It is not used directly, instead the type
625-- combinators provided below are used for conversions.
626--
627-- To adapt from one monomorphic type (e.g. 'AsyncT') to another monomorphic
628-- type (e.g. 'SerialT') use the 'adapt' combinator. To give a polymorphic code
629-- a specific interpretation or to adapt a specific type to a polymorphic type
630-- use the type specific combinators e.g. 'fromAsync' or 'fromWSerial'. You
631-- cannot adapt polymorphic code to polymorphic code, as the compiler would not know
632-- which specific type you are converting from or to. If you see a an
633-- @ambiguous type variable@ error then most likely you are using 'adapt'
634-- unnecessarily on polymorphic code.
636-- | Same as 'Streamly.Prelude.concatFoldableWith'
637--
638-- @since 0.1.0
639{-# DEPRECATED foldWith "Please use 'Streamly.Prelude.concatFoldableWith' instead." #-}
640{-# INLINEABLE foldWith #-}
641foldWith :: (IsStream t, Foldable f) => (t m a -> t m a -> t m a) -> f (t m a) -> t m a
642foldWith = P.concatFoldableWith
644-- | Same as 'Streamly.Prelude.concatMapFoldableWith'
645--
646-- @since 0.1.0
647{-# DEPRECATED foldMapWith "Please use 'Streamly.Prelude.concatMapFoldableWith' instead." #-}
648{-# INLINEABLE foldMapWith #-}
649foldMapWith :: (IsStream t, Foldable f) => (t m b -> t m b -> t m b) -> (a -> t m b) -> f a -> t m b
650foldMapWith = P.concatMapFoldableWith
652-- | Same as 'Streamly.Prelude.concatForFoldableWith'
653--
654-- @since 0.1.0
655{-# DEPRECATED forEachWith "Please use 'Streamly.Prelude.concatForFoldableWith' instead." #-}
656{-# INLINEABLE forEachWith #-}
657forEachWith :: (IsStream t, Foldable f) => (t m b -> t m b -> t m b) -> f a -> (a -> t m b) -> t m b
658forEachWith = P.concatForFoldableWith
660{-# DEPRECATED serially "Please use 'Streamly.Prelude.fromSerial' instead." #-}
661serially :: IsStream t => SerialT m a -> t m a
662serially = fromSerial
664{-# DEPRECATED wSerially "Please use 'Streamly.Prelude.fromWSerial' instead." #-}
665wSerially :: IsStream t => WSerialT m a -> t m a
666wSerially = fromWSerial
668{-# DEPRECATED asyncly "Please use 'Streamly.Prelude.fromAsync' instead." #-}
669asyncly :: IsStream t => AsyncT m a -> t m a
670asyncly = fromAsync
672{-# DEPRECATED aheadly "Please use 'Streamly.Prelude.fromAhead' instead." #-}
673aheadly :: IsStream t => AheadT m a -> t m a
674aheadly = fromAhead
676{-# DEPRECATED wAsyncly "Please use 'Streamly.Prelude.fromWAsync' instead." #-}
677wAsyncly :: IsStream t => WAsyncT m a -> t m a
678wAsyncly = fromWAsync
680{-# DEPRECATED parallely "Please use 'Streamly.Prelude.fromParallel' instead." #-}
681parallely :: IsStream t => ParallelT m a -> t m a
682parallely = fromParallel
684{-# DEPRECATED zipSerially "Please use 'Streamly.Prelude.fromZipSerial' instead." #-}
685zipSerially :: IsStream t => ZipSerialM m a -> t m a
686zipSerially = fromZipSerial
688{-# DEPRECATED zipAsyncly "Please use 'Streamly.Prelude.fromZipAsync' instead." #-}
689zipAsyncly :: IsStream t => ZipAsyncM m a -> t m a
690zipAsyncly = fromZipAsync