on master help sign in
Fix documentation for movement of APIs to prelude
2506636Harendra Kumar
src/Streamly.hs+135−72
@@ -7,22 +7,49 @@
7-- Stability : experimental
7-- Stability : experimental
8-- Portability : GHC
8-- Portability : GHC
9--
9--
10−-- Haskell lists provide a simple and powerful API but they are limited to
10+-- Streamly is a general purpose programming framework using cocnurrent data
11−-- holding only pure values. Streamly streams are a logical extension of
11+-- flow programming paradigm. It can be considered as a generalization of
12−-- Haskell lists to support monadic sequences and powerful declarative
12+-- Haskell lists to monadic streaming with concurrent composition capability.
13−-- concurrency. They provide almost the same API as lists (See
13+-- The serial stream type in streamly @SerialT m a@ is like the list type @[a]@
14−-- "Streamly.Prelude"). In fact, Haskell lists can be expressed as pure
14+-- parameterized by the monad @m@. For example, @SerialT IO a@ is a moral
15−-- streams, a special case of monadic streams, with similar or better
15+-- equivalent of @[a]@ in the IO monad. Streams are constructed very much like
16−-- performance and almost drop-in replacement.
16+-- lists, except that they use 'nil' and 'cons' instead of '[]' and ':'.
17−--
17+--
18−-- Streams are designed for high performance applications and do not exhibit
18+-- @
19−-- issues that are usually associated with lists. For example, streams
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
20−-- express strings as streams of 'Char' and bytestrings as streams of 'Word8'
46+-- as streams of 'Char', encode and decode the streams to/from UTF8 and
21−-- without any issues, obviating the need for special purpose libraries like
47+-- serialize them to @Array Word8@ obviating the need for special purpose
22−-- bytestring and text, and various lazy and strict falvors of those. Streamly
48+-- libraries like @bytestring@ and @text@.
23−-- arrays (See "Streamly.Array") complement streams for storing or buffering
49+--
24−-- data efficiently and facilitating efficient interfacing of streams with IO
50+-- For more details
25−-- systems.
51+-- please see the "Streamly.Tutorial" module and the examples directory in this
52+-- package.
26
53
27{-# LANGUAGE CPP #-}
54{-# LANGUAGE CPP #-}
28{-# LANGUAGE MultiParamTypeClasses #-}
55{-# LANGUAGE MultiParamTypeClasses #-}
@@ -35,12 +62,19 @@
35
62
36module Streamly
63module Streamly
37 (
64 (
38− -- * Streams and Folds
39− -- $overview
40−
41− -- * Streams Overview
65+ -- * Concepts Overview
66+ -- ** Streams
42 -- $streams
67 -- $streams
43
68
69+ -- ** Folds
70+ -- $folds
71+
72+ -- ** Arrays
73+ -- $arrays
74+
75+ -- * Module Overview
76+ -- $streamtypes
77+
44 -- * Type Synonyms
78 -- * Type Synonyms
45 MonadAsync
79 MonadAsync
46
80
@@ -165,43 +199,52 @@ import qualified Streamly.Streams.StreamK as K
165-- XXX provide good succinct examples of pipelining, merging, splitting ect.
199-- XXX provide good succinct examples of pipelining, merging, splitting ect.
166-- below.
200-- below.
167--
201--
168−-- $overview
202+-- $streams
169−-- Streamly is a general purpose concurrent data flow programming engine
170−-- expressing a program as a network of streams and folds. Stream types (e.g.
171−-- 'SerialT') exported from this module represent streams or more specifically
172−-- stream producers while the fold type exported from "Streamly.Fold"
173−-- represents stream consumers. Both producers and consumers can be
174−-- transformed in many ways e.g. using map, scan, filter etc. Transformations
175−-- can be chained into a pipeline, multiple streams can be merged together or a
176−-- stream can be split into multiple independent data flows. All these
177−-- compositions can be combined together to form an arbitrary data flow network
178−-- expressing any kind of general purpose computing in a declarative manner.
179−--
180−-- The simplest way to compose a data processing pipeline is to generate a
181−-- stream of data (e.g. from a file or network), chain pipelines of
182−-- transformations on the stream and finally pass it to a fold. Folds represent
183−-- specific ways to consume a stream (e.g. producing a sum of numbers).
184−-- Transformations can also be applied on folds before they are attached with a
185−-- stream.
186--
203--
187−-- @
204+-- A program is expressed as a network of streams and folds. A stream is a
205+-- source or generator of data elements and a fold is a consumer of data elements that
206+-- reduces multiple input elements to a single value.
188--
207--
189−-- ---Stream m a-->stream transforms-->fold transforms-->Fold m a b
208+-- In the following example, a 'Word8' stream is generated by using
190−-- @
209+-- 'Streamly.FileSystem.Handle.read' on a file handle, then the
210+-- 'Streamly.Prelude.splitBySuffix' transformation splits the stream on
211+-- newlines (ascii value 10); it uses the 'Streamly.Fold.drain' fold to reduce
212+-- the resulting lines to unit values (@()@), 'Streamly.Prelude.length' fold
213+-- then counts the unit elements in the resulting stream which gives us the
214+-- number of lines in the file:
191--
215--
192−-- Stream producers can be appended, merged, zipped or nested to build an
216+-- > S.length $ S.splitOnSuffix FL.drain 10 $ FH.read fh
193−-- arbitrarily complex composed stream producer. Transformations can be applied
194−-- at any point in the composition tree. See "Streamly.Prelude" module for more
195−-- details on the combinators.
196--
217--
197−-- @
218+-- The following example folds the lines to arrays of 'Word8' using the
219+-- 'Streamly.Mem.Array.writeF' fold and then wraps the lines in square
220+-- brackets before writing them to standard output using
221+-- 'Streamly.FileSystem.Handle.write':
198--
222--
199−-- -------Stream m a-->transform-->|
223+-- > wrapLine ln = S.fromList "[" <> A.read ln <> S.fromList "]\n"
224+-- > readLines = S.splitOnSuffix A.writeF 10
225+-- > FH.write stdout $ S.concatMap wrapLine $ readLines fh1
226+--
227+-- One stream can be appended after another:
228+--
229+-- > FH.write stdout $ S.concatMap wrapLine $ readLines fh1 <> readLines fh2
200−-- |
230+--
201−-- -------Stream m a-->transform-->|=>---transform-->Stream m a--->
231+-- The following example reads two files concurrently, merges the lines from
202−-- |
232+-- the two streams and writes the resulting stream to another file:
203−-- -------Stream m a-->transform-->|
233+--
204−-- @
234+-- > FH.write stdout $ S.concatMap wrapLine $ readLines fh1 `parallel` readLines fh2
235+--
236+-- There are many ways to generate, merge, zip, transform and fold data
237+-- streams. Many transformations can be chained in a stream pipeline. See
238+-- "Streamly.Prelude" module for combinators to manipulate streams.
239+
240+-- $folds
241+--
242+-- The way stream types in this module like 'SerialT' represent data sources,
243+-- the same way the 'Fold' type from "Streamly.Fold" represents data sinks or
244+-- reducers of streams. Reducers can be combined to consume a stream source in
245+-- many ways. The simplest is to reduce a stream source using a fold e.g.:
246+--
247+-- > S.runFold FL.length $ S.enumerateTo 100
205--
248--
206-- Folds are consumers of streams and can be used to split a stream into
249-- Folds are consumers of streams and can be used to split a stream into
207-- multiple independent flows. Grouping transforms a stream by applying a fold
250-- multiple independent flows. Grouping transforms a stream by applying a fold
@@ -222,7 +265,37 @@ import qualified Streamly.Streams.StreamK as K
222-- @
265-- @
223--
266--
224
267
225−-- $streams
268+-- $arrays
269+--
270+-- Streamly arrays (See "Streamly.Mem.Array") complement streams to provide an
271+-- efficient computing paradigm. Streams are suitable for immutable
272+-- transformations of /potentially infinite/ data using /sequential access/ and
273+-- pipelined transformations whereas arrays are suitable for in-place
274+-- transformations of /necessarily finite/ data using /random access/. Streams
275+-- are synonymous with /sequential pipelined processing/ whereas arrays are
276+-- synonymous with /efficient buffering and random access/.
277+--
278+-- In general, a data processing pipeline reads data from some IO device, does
279+-- some processing on it and finally writes the output to another IO device.
280+-- Streams provide the overall framework of sequential processing pipeline in
281+-- which arrays are used as buffering elements in the middle. In addition to
282+-- buffering in the middle, arrays can also be used at the boundaries of the
283+-- pipeline to efficiently interface with external storage systems like memory,
284+-- files and network. If streams are the pipes in a water pipeline network
285+-- then arrays are like the storage tanks in the middle. On the input side,
286+-- think of arrays as buckets to fetch water to feed the pipeline and on the
287+-- output side buckets to remove the processed water.
288+--
289+-- 'ByteString' data type from the 'bytestring' package and the 'Text' data
290+-- type from the 'text' package are special cases of arrays. 'ByteString' is
291+-- like @Array Word8@ and 'Text' is like @utf16@ encoded @Array Word8@.
292+-- Streamly arrays can be transformed as efficiently as @bytestring@ or @text@
293+-- by using stream operations on them.
294+
295+-- Streams and arrays are equally important in computing. They are computing
296+-- duals of each other.
297+
298+-- $streamtypes
226-- The basic stream type is 'Serial', it represents a sequence of IO actions,
299-- The basic stream type is 'Serial', it represents a sequence of IO actions,
227-- and is a 'Monad'. The type 'SerialT' is a monad transformer that can
300-- and is a 'Monad'. The type 'SerialT' is a monad transformer that can
228-- represent a sequence of actions in an arbitrary monad. The type 'Serial' is
301-- represent a sequence of actions in an arbitrary monad. The type 'Serial' is
@@ -236,32 +309,22 @@ import qualified Streamly.Streams.StreamK as K
236-- explicit stream type combinators are used, the default stream type is
309-- explicit stream type combinators are used, the default stream type is
237-- inferred as 'Serial'.
310-- inferred as 'Serial'.
238--
311--
239−-- Here is a simple console echo program example:
312+-- This module exports stream types, instances and combinators for:
240−--
241−-- @
242−-- > drain $ S.repeatM getLine & S.mapM putStrLn
243−-- @
244−--
245−-- For more details please see the "Streamly.Tutorial" module and the examples
246−-- directory in this package.
247--
313--
248−-- This module exports stream types, instances and some basic operations.
314+-- * converting between different stream types
249−-- Functionality exported by this module include:
315+-- * appending and concurrently merging streams
250−--
316+-- * Concurrency control
251−-- * Semigroup append ('<>') instances as well as explicit operations for merging streams
317+-- * Concurrent function application
252−-- * Monad and Applicative instances for looping over streams
318+-- * Stream rate control
253−-- * Zip Applicatives for zipping streams
254−-- * Stream type combinators to convert between different composition styles
255−-- * Some basic utilities to run and fold streams
256−--
257−-- See the "Streamly.Prelude" module for comprehensive APIs for construction,
258−-- generation, elimination and transformation of streams.
259--
319--
260-- This module is designed to be imported unqualified:
320-- This module is designed to be imported unqualified:
261--
321--
262-- @
322-- @
263-- import Streamly
323-- import Streamly
264-- @
324-- @
325+--
326+-- See the "Streamly.Prelude" module for APIs for construction,
327+-- generation, elimination and transformation of streams.
265
328
266------------------------------------------------------------------------------
329------------------------------------------------------------------------------
267-- Eliminating a stream
330-- Eliminating a stream
src/Streamly/Fold.hs+43−44
@@ -15,14 +15,15 @@
15-- Stability : experimental
15-- Stability : experimental
16-- Portability : GHC
16-- Portability : GHC
17--
17--
18−-- A left fold consumes a stream and reduces it to a single value. Using the
18+-- A left fold consumes a stream and reduces it to a single value. The fold
19−-- fold combinators in "Streamly.Prelude" module only one fold operation can be
19+-- operations in "Streamly.Prelude" cannot be combined such that multiple of
20−-- applied to a stream. This module provides a 'Fold' type that represents a
20+-- them can run on the same stream. This module provides a 'Fold' type that
21−-- left fold. Multiple such folds can be combined in different ways; a stream
21+-- represents a left fold. Multiple such folds can be combined using
22−-- can then be supplied to the combined fold.
22+-- combinators; a stream can then be supplied to the combined fold and it would
23+-- distribute the input to constituent folds according to the composition.
23−-- For example, a distributive applicative composition distributes the input to
24+-- For example, an applicative composition distributes the same input to
24-- the constituent folds and then combines the fold outputs. Similarly, a
25-- the constituent folds and then combines the fold outputs. Similarly, a
25−-- partitioning composition can partition the input among constituent folds.
26+-- partitioning combinator can divide the input among constituent folds.
26-- All the combinators in this module are of true streaming nature, stream
27-- All the combinators in this module are of true streaming nature, stream
27-- elements are not unnecessarily buffered in memory, guaranteeing a constant
28-- elements are not unnecessarily buffered in memory, guaranteeing a constant
28-- memory consumption.
29-- memory consumption.
@@ -32,18 +33,9 @@
32-- sources in interesting ways whereas this module provides combinators that
33-- sources in interesting ways whereas this module provides combinators that
33-- combine stream consumers in interesting ways. In other words,
34-- combine stream consumers in interesting ways. In other words,
34-- "Streamly.Prelude" provides stream merging capabilities while
35-- "Streamly.Prelude" provides stream merging capabilities while
35−-- "Streamly.Fold" provides stream splitting capabilities. Both the modules
36+-- "Streamly.Fold" provides stream splitting capabilities.
36−-- are organized in the same way so that you can easily find the corresponding
37−-- operations.
38--
37--
39-- > import qualified Streamly.Fold as FL
38-- > import qualified Streamly.Fold as FL
40−--
41−-- A left fold is represented by the type 'Fold'. @Fold m a b@ folds an
42−-- input stream consisting of values of type @a@ to a structure of type
43−-- @b@. The fold can be run using the 'foldl'' combinator and an input stream.
44−--
45−-- >>> FL.foldl' FL.sum (S.enumerateFromTo 1 100)
46−-- 5050
47
39
48-- Also see the "Streamly.Sink" module that provides specialized left folds
40-- Also see the "Streamly.Sink" module that provides specialized left folds
49-- that discard the outputs.
41-- that discard the outputs.
@@ -53,6 +45,13 @@
53module Streamly.Fold
45module Streamly.Fold
54 (
46 (
55 -- * Fold Type
47 -- * Fold Type
48+ -- |
49+ -- A 'Fold' can be run over a stream using the 'runFold' combinator in
50+ -- "Streamly.Prelude":
51+ --
52+ -- >>> S.runFold FL.sum (S.enumerateFromTo 1 100)
53+ -- 5050
54+
56 Fold -- (..)
55 Fold -- (..)
57
56
58 -- , tail
57 -- , tail
@@ -118,7 +117,7 @@ module Streamly.Fold
118 -- Transformations can be applied either on the input side or on the output
117 -- Transformations can be applied either on the input side or on the output
119 -- side. The 'Functor' instance of a fold maps on the output of the fold:
118 -- side. The 'Functor' instance of a fold maps on the output of the fold:
120 --
119 --
121− -- >>> FL.foldl' (fmap show FL.sum) (S.enumerateFromTo 1 100)
120+ -- >>> S.runFold (fmap show FL.sum) (S.enumerateFromTo 1 100)
122 -- "5050"
121 -- "5050"
123 --
122 --
124 -- However, the input side or contravariant transformations are more
123 -- However, the input side or contravariant transformations are more
@@ -164,12 +163,12 @@ module Streamly.Fold
164 , lreverse
163 , lreverse
165 -}
164 -}
166
165
166+ {-
167 -- * Parsing
167 -- * Parsing
168 -- ** Trimming
168 -- ** Trimming
169 , ltake
169 , ltake
170 -- , lrunFor -- time
170 -- , lrunFor -- time
171 , ltakeWhile
171 , ltakeWhile
172− {-
173 , ltakeWhileM
172 , ltakeWhileM
174 , ldrop
173 , ldrop
175 , ldropWhile
174 , ldropWhile
@@ -194,7 +193,7 @@ module Streamly.Fold
194 -- stream twice:
193 -- stream twice:
195 --
194 --
196 -- >>> let avg = (/) <$> FL.sum <*> fmap fromIntegral FL.length
195 -- >>> let avg = (/) <$> FL.sum <*> fmap fromIntegral FL.length
197− -- >>> FL.foldl' avg (S.enumerateFromTo 1.0 100.0)
196+ -- >>> S.runFold avg (S.enumerateFromTo 1.0 100.0)
198 -- 50.5
197 -- 50.5
199 --
198 --
200 -- The 'Semigroup' and 'Monoid' instances of a distributing fold distribute
199 -- The 'Semigroup' and 'Monoid' instances of a distributing fold distribute
@@ -202,7 +201,7 @@ module Streamly.Fold
202 -- Semigroup instances of the output types:
201 -- Semigroup instances of the output types:
203 --
202 --
204 -- >>> import Data.Monoid (Sum)
203 -- >>> import Data.Monoid (Sum)
205− -- >>> FL.foldl' (FL.head <> FL.last) (fmap Sum $ S.enumerateFromTo 1.0 100.0)
204+ -- >>> S.runFold (FL.head <> FL.last) (fmap Sum $ S.enumerateFromTo 1.0 100.0)
206 -- Just (Sum {getSum = 101.0})
205 -- Just (Sum {getSum = 101.0})
207 --
206 --
208 -- The 'Num', 'Floating', and 'Fractional' instances work in the same way.
207 -- The 'Num', 'Floating', and 'Fractional' instances work in the same way.
@@ -339,7 +338,7 @@ _transform (Pipe pstep1 pstep2 pinitial) (Fold fstep finitial fextract) =
339
338
340-- | @(lmap f fold)@ maps the function @f@ on the input of the fold.
339-- | @(lmap f fold)@ maps the function @f@ on the input of the fold.
341--
340--
342−-- >>> FL.foldl' (FL.lmap (\x -> x * x) FL.sum) (S.enumerateFromTo 1 100)
341+-- >>> S.runFold (FL.lmap (\x -> x * x) FL.sum) (S.enumerateFromTo 1 100)
343-- 338350
342-- 338350
344--
343--
345-- @since 0.7.0
344-- @since 0.7.0
@@ -547,7 +546,7 @@ stdDev = sqrt variance
547-- | Fold an input stream consisting of monoidal elements using 'mappend'
546-- | Fold an input stream consisting of monoidal elements using 'mappend'
548-- and 'mempty'.
547-- and 'mempty'.
549--
548--
550−-- > FL.foldl FL.mconcat (S.map Sum $ S.enumerateFromTo 1 10)
549+-- > S.runFold FL.mconcat (S.map Sum $ S.enumerateFromTo 1 10)
551--
550--
552-- @since 0.7.0
551-- @since 0.7.0
553{-# INLINABLE mconcat #-}
552{-# INLINABLE mconcat #-}
@@ -560,7 +559,7 @@ mconcat = Fold (\x a -> return $ mappend x a) (return mempty) return
560-- Make a fold from a pure function that folds the output of the function
559-- Make a fold from a pure function that folds the output of the function
561-- using 'mappend' and 'mempty'.
560-- using 'mappend' and 'mempty'.
562--
561--
563−-- > FL.foldl (FL.foldMap Sum) $ S.enumerateFromTo 1 10
562+-- > S.runFold (FL.foldMap Sum) $ S.enumerateFromTo 1 10
564--
563--
565-- @since 0.7.0
564-- @since 0.7.0
566{-# INLINABLE foldMap #-}
565{-# INLINABLE foldMap #-}
@@ -573,7 +572,7 @@ foldMap f = lmap f mconcat
573-- Make a fold from a monadic function that folds the output of the function
572-- Make a fold from a monadic function that folds the output of the function
574-- using 'mappend' and 'mempty'.
573-- using 'mappend' and 'mempty'.
575--
574--
576−-- > FL.foldM (FL.foldMapM (return . Sum)) $ S.enumerateFromTo 1 10
575+-- > S.runFold (FL.foldMapM (return . Sum)) $ S.enumerateFromTo 1 10
577--
576--
578-- @since 0.7.0
577-- @since 0.7.0
579{-# INLINABLE foldMapM #-}
578{-# INLINABLE foldMapM #-}
@@ -781,7 +780,7 @@ or = Fold (\x a -> return $ x || a) (return False) return
781
780
782-- | Include only those elements that pass a predicate.
781-- | Include only those elements that pass a predicate.
783--
782--
784−-- >>> FL.foldl (lfilter (> 5) FL.sum) [1..10]
783+-- >>> S.runFold (lfilter (> 5) FL.sum) [1..10]
785-- 40
784-- 40
786--
785--
787-- @since 0.7.0
786-- @since 0.7.0
@@ -805,9 +804,9 @@ _lfilterM f (Fold step begin done) = Fold step' begin done
805-- | Take first 'n' elements from the stream and discard the rest.
804-- | Take first 'n' elements from the stream and discard the rest.
806--
805--
807-- @since 0.7.0
806-- @since 0.7.0
808−{-# INLINABLE ltake #-}
807+{-# INLINABLE _ltake #-}
809−ltake :: Monad m => Int -> Fold m a b -> Fold m a b
808+_ltake :: Monad m => Int -> Fold m a b -> Fold m a b
810−ltake n (Fold step initial done) = Fold step' initial' done'
809+_ltake n (Fold step initial done) = Fold step' initial' done'
811 where
810 where
812 initial' = fmap (Tuple' 0) initial
811 initial' = fmap (Tuple' 0) initial
813 step' (Tuple' i r) a = do
812 step' (Tuple' i r) a = do
@@ -821,9 +820,9 @@ ltake n (Fold step initial done) = Fold step' initial' done'
821-- | Takes elements from the input as long as the predicate succeeds.
820-- | Takes elements from the input as long as the predicate succeeds.
822--
821--
823-- @since 0.7.0
822-- @since 0.7.0
824−{-# INLINABLE ltakeWhile #-}
823+{-# INLINABLE _ltakeWhile #-}
825−ltakeWhile :: Monad m => (a -> Bool) -> Fold m a b -> Fold m a b
824+_ltakeWhile :: Monad m => (a -> Bool) -> Fold m a b -> Fold m a b
826−ltakeWhile predicate (Fold step initial done) = Fold step' initial' done'
825+_ltakeWhile predicate (Fold step initial done) = Fold step' initial' done'
827 where
826 where
828 initial' = fmap Left' initial
827 initial' = fmap Left' initial
829 step' (Left' r) a = do
828 step' (Left' r) a = do
@@ -845,7 +844,7 @@ ltakeWhile predicate (Fold step initial done) = Fold step' initial' done'
845-- ---stream m a---| |---m (b,c)
844-- ---stream m a---| |---m (b,c)
846-- |-------Fold m a c--------|
845-- |-------Fold m a c--------|
847-- @
846-- @
848−-- >>> FL.foldl' (FL.tee FL.sum FL.length) (S.enumerateFromTo 1.0 100.0)
847+-- >>> S.runFold (FL.tee FL.sum FL.length) (S.enumerateFromTo 1.0 100.0)
849-- (5050.0,100)
848-- (5050.0,100)
850--
849--
851-- @since 0.7.0
850-- @since 0.7.0
@@ -887,7 +886,7 @@ foldCons (Fold stepL beginL doneL) (Fold stepR beginR doneR) =
887-- ...
886-- ...
888-- @
887-- @
889--
888--
890−-- >>> FL.foldl' (FL.distribute [FL.sum, FL.length]) (S.enumerateFromTo 1 5)
889+-- >>> S.runFold (FL.distribute [FL.sum, FL.length]) (S.enumerateFromTo 1 5)
891-- [15,5]
890-- [15,5]
892--
891--
893-- This is the consumer side dual of the producer side 'sequence' operation.
892-- This is the consumer side dual of the producer side 'sequence' operation.
@@ -916,7 +915,7 @@ distribute (x:xs) = foldCons x (distribute xs)
916--
915--
917-- >>> import System.Random (randomIO)
916-- >>> import System.Random (randomIO)
918-- >>> randomly a = randomIO >>= \x -> return $ if x then Left a else Right a
917-- >>> randomly a = randomIO >>= \x -> return $ if x then Left a else Right a
919−-- >>> FL.foldl' (FL.partitionByM randomly FL.length FL.length) (S.enumerateFromTo 1 100)
918+-- >>> S.runFold (FL.partitionByM randomly FL.length FL.length) (S.enumerateFromTo 1 100)
920-- (59,41)
919-- (59,41)
921--
920--
922-- Send input to the two folds in a proportion of 2:1:
921-- Send input to the two folds in a proportion of 2:1:
@@ -932,7 +931,7 @@ distribute (x:xs) = foldCons x (distribute xs)
932--
931--
933-- main = do
932-- main = do
934-- f <- proportionately 2 1
933-- f <- proportionately 2 1
935−-- r <- FL.foldl' (FL.partitionByM f FL.length FL.length) (S.enumerateFromTo (1 :: Int) 100)
934+-- r <- S.runFold (FL.partitionByM f FL.length FL.length) (S.enumerateFromTo (1 :: Int) 100)
936-- print r
935-- print r
937-- @
936-- @
938-- @
937-- @
@@ -971,7 +970,7 @@ partitionByM f (Fold stepL beginL doneL) (Fold stepR beginR doneR) =
971-- >>> let f = FL.partitionBy (\\n -> if even n then Left n else Right n)
970-- >>> let f = FL.partitionBy (\\n -> if even n then Left n else Right n)
972-- (fmap (("Even " ++) . show) FL.length)
971-- (fmap (("Even " ++) . show) FL.length)
973-- (fmap (("Odd " ++) . show) FL.length)
972-- (fmap (("Odd " ++) . show) FL.length)
974−-- in FL.foldl' f (S.enumerateFromTo 1 100)
973+-- in S.runFold f (S.enumerateFromTo 1 100)
975-- ("Even 50","Odd 50")
974-- ("Even 50","Odd 50")
976-- @
975-- @
977--
976--
@@ -1058,7 +1057,7 @@ demuxWith f kv = Fold step initial extract
1058-- @
1057-- @
1059-- > let table = Data.Map.fromList [(\"SUM", FL.sum), (\"PRODUCT", FL.product)]
1058-- > let table = Data.Map.fromList [(\"SUM", FL.sum), (\"PRODUCT", FL.product)]
1060-- input = S.fromList [(\"SUM",1),(\"PRODUCT",2),(\"SUM",3),(\"PRODUCT",4)]
1059-- input = S.fromList [(\"SUM",1),(\"PRODUCT",2),(\"SUM",3),(\"PRODUCT",4)]
1061−-- in FL.foldl' (FL.demux table) input
1060+-- in S.runFold (FL.demux table) input
1062-- One 1
1061-- One 1
1063-- Two 2
1062-- Two 2
1064-- @
1063-- @
@@ -1116,7 +1115,7 @@ demuxWith_ f kv = Fold step initial extract
1116-- > let prn = FL.drainBy print
1115-- > let prn = FL.drainBy print
1117-- > let table = Data.Map.fromList [(\"ONE", prn), (\"TWO", prn)]
1116-- > let table = Data.Map.fromList [(\"ONE", prn), (\"TWO", prn)]
1118-- input = S.fromList [(\"ONE",1),(\"TWO",2)]
1117-- input = S.fromList [(\"ONE",1),(\"TWO",2)]
1119−-- in FL.foldl' (FL.demux_ table) input
1118+-- in S.runFold (FL.demux_ table) input
1120-- One 1
1119-- One 1
1121-- Two 2
1120-- Two 2
1122-- @
1121-- @
@@ -1136,7 +1135,7 @@ demux_ fs = demuxWith_ fst (Map.map (lmap snd) fs)
1136--
1135--
1137-- @
1136-- @
1138-- > let input = S.fromList [(\"ONE",1),(\"ONE",1.1),(\"TWO",2), (\"TWO",2.2)]
1137-- > let input = S.fromList [(\"ONE",1),(\"ONE",1.1),(\"TWO",2), (\"TWO",2.2)]
1139−-- in FL.foldl' (FL.classify FL.toListRev) input
1138+-- in S.runFold (FL.classify FL.toListRev) input
1140-- fromList [(\"ONE",[1.1,1.0]),(\"TWO",[2.2,2.0])]
1139-- fromList [(\"ONE",[1.1,1.0]),(\"TWO",[2.2,2.0])]
1141-- @
1140-- @
1142--
1141--
@@ -1166,7 +1165,7 @@ classifyWith f (Fold step initial extract) = Fold step' initial' extract'
1166--
1165--
1167-- @
1166-- @
1168-- > let input = S.fromList [(\"ONE",1),(\"ONE",1.1),(\"TWO",2), (\"TWO",2.2)]
1167-- > let input = S.fromList [(\"ONE",1),(\"ONE",1.1),(\"TWO",2), (\"TWO",2.2)]
1169−-- in FL.foldl' (FL.classify FL.toListRev) input
1168+-- in S.runFold (FL.classify FL.toListRev) input
1170-- fromList [(\"ONE",[1.1,1.0]),(\"TWO",[2.2,2.0])]
1169-- fromList [(\"ONE",[1.1,1.0]),(\"TWO",[2.2,2.0])]
1171-- @
1170-- @
1172--
1171--
@@ -1238,9 +1237,9 @@ unzip = unzipWith id
1238-- accumulator. Thus we can resume the fold later and feed it more input.
1237-- accumulator. Thus we can resume the fold later and feed it more input.
1239--
1238--
1240-- >> do
1239-- >> do
1241−-- > more <- FL.foldl (FL.duplicate FL.sum) (S.enumerateFromTo 1 10)
1240+-- > more <- S.runFold (FL.duplicate FL.sum) (S.enumerateFromTo 1 10)
1242−-- > evenMore <- FL.foldl (FL.duplicate more) (S.enumerateFromTo 11 20)
1241+-- > evenMore <- S.runFold (FL.duplicate more) (S.enumerateFromTo 11 20)
1243−-- > FL.foldl evenMore (S.enumerateFromTo 21 30)
1242+-- > S.runFold evenMore (S.enumerateFromTo 21 30)
1244-- > 465
1243-- > 465
1245--
1244--
1246-- @since 0.7.0
1245-- @since 0.7.0
src/Streamly/Fold/Types.hs+4−4
@@ -25,13 +25,14 @@ import Streamly.Strict (Tuple'(..))
25
25
26-- | Represents a left fold over an input stream of values of type @a@ to a
26-- | Represents a left fold over an input stream of values of type @a@ to a
27-- single value of type @b@ in 'Monad' @m@.
27-- single value of type @b@ in 'Monad' @m@.
28+--
29+-- @since 0.7.0
28
30
29-- The fold uses an intermediate type @x@ as accumulator. The fold accumulator
31-- The fold uses an intermediate type @x@ as accumulator. The fold accumulator
30-- is initialized by calling the @init@ function and is then driven by calling
32-- is initialized by calling the @init@ function and is then driven by calling
31-- the step function repeatedly. When the fold is done the @extract@ function
33-- the step function repeatedly. When the fold is done the @extract@ function
32-- is used to map the intermediate type @x@ to the final type @b@. This allows
34-- is used to map the intermediate type @x@ to the final type @b@. This allows
33-- the state of the fold to be embedded in an arbitrary type @x@.
35-- the state of the fold to be embedded in an arbitrary type @x@.
34−--
35data Fold m a b =
36data Fold m a b =
36 -- | @Fold @ @ step @ @ initial @ @ extract@
37 -- | @Fold @ @ step @ @ initial @ @ extract@
37 forall x. Fold (x -> a -> m x) (m x) (x -> m b)
38 forall x. Fold (x -> a -> m x) (m x) (x -> m b)
@@ -46,9 +47,8 @@ instance Applicative m => Functor (Fold m a) where
46 {-# INLINE (<$) #-}
47 {-# INLINE (<$) #-}
47 (<$) b = \_ -> pure b
48 (<$) b = \_ -> pure b
48
49
49−-- | The input (type @a@) of the composed fold is distributed to both the
50+-- | The fold resulting from '<*>' distributes its input to both the argument
50−-- constituent folds. The outputs of the constituent folds (type @b@) are
51+-- folds and combines their output using the supplied function.
51−-- applied to a function.
52instance Applicative m => Applicative (Fold m a) where
52instance Applicative m => Applicative (Fold m a) where
53 {-# INLINE pure #-}
53 {-# INLINE pure #-}
54 pure b = Fold (\() _ -> pure ()) (pure ()) (\() -> pure b)
54 pure b = Fold (\() _ -> pure ()) (pure ()) (\() -> pure b)
src/Streamly/Prelude.hs+40−35
@@ -170,16 +170,18 @@ module Streamly.Prelude
170-- the previous step. However, it is possible to fold parts of the stream in
170-- the previous step. However, it is possible to fold parts of the stream in
171-- parallel and then combine the results using a monoid.
171-- parallel and then combine the results using a monoid.
172
172
173+ -- ** Right Folds
173 , foldrM
174 , foldrM
174 , foldrS
175 , foldrS
175 , foldrT
176 , foldrT
176 , foldr
177 , foldr
177
178
179+ -- ** Left Folds
178 , foldl'
180 , foldl'
179 , foldl1'
181 , foldl1'
180 , foldlM'
182 , foldlM'
181
183
182− -- * Running Folds
184+ -- ** Composable Left Folds
183 -- $runningfolds
185 -- $runningfolds
184
186
185 , runFold
187 , runFold
@@ -316,6 +318,7 @@ module Streamly.Prelude
316 -- > foldl f z xs = last $ scanl f z xs
318 -- > foldl f z xs = last $ scanl f z xs
317 -- > foldr f z xs = head $ scanr f z xs
319 -- > foldr f z xs = head $ scanr f z xs
318
320
321+ -- ** Left scans
319 , scanl'
322 , scanl'
320 , scanlM'
323 , scanlM'
321 , postscanl'
324 , postscanl'
@@ -325,7 +328,7 @@ module Streamly.Prelude
325 , scanl1'
328 , scanl1'
326 , scanl1M'
329 , scanl1M'
327
330
328− -- ** Running Scans
331+ -- ** Scan Using Fold
329 , runScan
332 , runScan
330 , runPostscan
333 , runPostscan
331
334
@@ -339,6 +342,7 @@ module Streamly.Prelude
339 -- , lprescanl'
342 -- , lprescanl'
340 -- , lprescanlM'
343 -- , lprescanlM'
341
344
345+ -- ** Indexing
342 , indexed
346 , indexed
343 , indexedR
347 , indexedR
344 -- , timestamped
348 -- , timestamped
@@ -460,7 +464,7 @@ module Streamly.Prelude
460 -- , interposeBy
464 -- , interposeBy
461 -- , intercalate
465 -- , intercalate
462
466
463− -- ** Breaking
467+ -- -- ** Breaking
464
468
465 -- By chunks
469 -- By chunks
466 -- , splitAt -- spanN
470 -- , splitAt -- spanN
@@ -490,14 +494,14 @@ module Streamly.Prelude
490
494
491 -- , groupScan
495 -- , groupScan
492
496
493− -- *** Chunks
497+ -- -- *** Chunks
494 , chunksOf
498 , chunksOf
495 , sessionsOf
499 , sessionsOf
496
500
497 -- , lchunksOf
501 -- , lchunksOf
498 -- , lsessionsOf
502 -- , lsessionsOf
499
503
500− -- *** Using Element Separators
504+ -- -- *** Using Element Separators
501 -- On == Dropping the separator
505 -- On == Dropping the separator
502 , splitOn
506 , splitOn
503 , splitOnSuffix
507 , splitOnSuffix
@@ -1346,19 +1350,20 @@ foldlM' step begin m = S.foldlM' step begin $ toStreamS m
1346
1350
1347-- $runningfolds
1351-- $runningfolds
1348--
1352--
1349−-- We can use the left folds in this module instead of the folds in
1353+-- "Streamly.Fold" module defines composable left folds which can be combined
1350−-- "Streamly.Prelude". For example the following two ways of folding are
1354+-- together in many interesting ways. Those folds can be run using 'runFold'.
1351−-- equivalent in functionality and performance,
1355+-- The following two ways of folding are equivalent in functionality and
1356+-- performance,
1352--
1357--
1353−-- >>> FL.foldl' FL.sum (S.enumerateFromTo 1 100)
1358+-- >>> S.runFold FL.sum (S.enumerateFromTo 1 100)
1354-- 5050
1359-- 5050
1355-- >>> S.sum (S.enumerateFromTo 1 100)
1360-- >>> S.sum (S.enumerateFromTo 1 100)
1356-- 5050
1361-- 5050
1357--
1362--
1358−-- However, left folds are push type folds. That means we push the entire input
1363+-- However, left folds cannot terminate early even if it does not need to
1359−-- to a fold before we can get the output. Therefore, the performance is
1364+-- consume more input to determine the result. Therefore, the performance is
1360-- equivalent only for full folds like 'sum' and 'length'. For partial folds
1365-- equivalent only for full folds like 'sum' and 'length'. For partial folds
1361−-- like 'head' or 'any' the folds in "Streamly.Prelude" may be much more
1366+-- like 'head' or 'any' the the folds defined in this module may be much more
1362-- efficient because they are implemented as right folds that terminate as soon
1367-- efficient because they are implemented as right folds that terminate as soon
1363-- as we get the result. Note that when a full fold is composed with a partial
1368-- as we get the result. Note that when a full fold is composed with a partial
1364-- fold in parallel the performance is not impacted as we anyway have to
1369-- fold in parallel the performance is not impacted as we anyway have to
@@ -1366,13 +1371,13 @@ foldlM' step begin m = S.foldlM' step begin $ toStreamS m
1366--
1371--
1367-- >>> S.head (1 `S.cons` undefined)
1372-- >>> S.head (1 `S.cons` undefined)
1368-- Just 1
1373-- Just 1
1369−-- >>> FL.foldl' FL.head (1 `S.cons` undefined)
1374+-- >>> S.runFold FL.head (1 `S.cons` undefined)
1370-- *** Exception: Prelude.undefined
1375-- *** Exception: Prelude.undefined
1371--
1376--
1372-- However, we can wrap the fold in a scan to convert it into a lazy stream of
1377-- However, we can wrap the fold in a scan to convert it into a lazy stream of
1373-- fold steps. We can then terminate the stream whenever we want. For example,
1378-- fold steps. We can then terminate the stream whenever we want. For example,
1374--
1379--
1375−-- >>> S.toList $ S.take 1 $ FL.scanl' FL.head (1 `S.cons` undefined)
1380+-- >>> S.toList $ S.take 1 $ S.runScan FL.head (1 `S.cons` undefined)
1376-- [Nothing]
1381-- [Nothing]
1377--
1382--
1378-- The following example extracts the input stream up to a point where the
1383-- The following example extracts the input stream up to a point where the
@@ -1382,15 +1387,15 @@ foldlM' step begin m = S.foldlM' step begin $ toStreamS m
1382-- > S.toList
1387-- > S.toList
1383-- $ S.map (fromJust . fst)
1388-- $ S.map (fromJust . fst)
1384-- $ S.takeWhile (\\(_,x) -> x <= 10)
1389-- $ S.takeWhile (\\(_,x) -> x <= 10)
1385−-- $ FL.postscanl' ((,) \<$> FL.last \<*> avg) (S.enumerateFromTo 1.0 100.0)
1390+-- $ S.runPostscan ((,) \<$> FL.last \<*> avg) (S.enumerateFromTo 1.0 100.0)
1386-- @
1391-- @
1387-- @
1392-- @
1388-- [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]
1393-- [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]
1389-- @
1394-- @
1390
1395
1391−-- | Fold a stream using the supplied monadic fold.
1396+-- | Fold a stream using the supplied left fold.
1392--
1397--
1393−-- >>> S.foldlStream FL.sum (S.enumerateFromTo 1 100)
1398+-- >>> S.runFold FL.sum (S.enumerateFromTo 1 100)
1394-- 5050
1399-- 5050
1395--
1400--
1396-- @since 0.7.0
1401-- @since 0.7.0
@@ -2181,15 +2186,15 @@ mapMaybeMSerial f m = fromStreamD $ D.mapMaybeM f $ toStreamD m
2181-- XXX Use a compact region list to temporarily store the list, in both reverse
2186-- XXX Use a compact region list to temporarily store the list, in both reverse
2182-- as well as in reverse'.
2187-- as well as in reverse'.
2183--
2188--
2189+-- /Note:/ 'reverse'' is much faster than this, use that when performance
2190+-- matters.
2191+--
2184-- |
2192-- |
2185-- > reverse = S.foldlT (flip S.cons) S.nil
2193-- > reverse = S.foldlT (flip S.cons) S.nil
2186--
2194--
2187-- Returns the elements of the stream in reverse order. The stream must be
2195-- Returns the elements of the stream in reverse order. The stream must be
2188-- finite. Note that this necessarily buffers the entire stream in memory.
2196-- finite. Note that this necessarily buffers the entire stream in memory.
2189--
2197--
2190−-- /Note:/ 'reverse'' is much faster than this, use that when performance
2191−-- matters.
2192−--
2193-- /Since 0.7.0 (Monad m constraint)/
2198-- /Since 0.7.0 (Monad m constraint)/
2194--
2199--
2195-- /Since: 0.1.1/
2200-- /Since: 0.1.1/
@@ -2567,7 +2572,7 @@ intercalate :: (IsStream t, MonadAsync m) => t m a -> t m a -> t m a
2567-- elements of its input are consumed by fold @f1@ and the rest of the stream
2572-- elements of its input are consumed by fold @f1@ and the rest of the stream
2568-- is consumed by fold @f2@.
2573-- is consumed by fold @f2@.
2569--
2574--
2570−-- > let splitAt_ n xs = FL.foldl' (FL.splitAt n FL.toList FL.toList) $ S.fromList xs
2575+-- > let splitAt_ n xs = S.runFold (FL.splitAt n FL.toList FL.toList) $ S.fromList xs
2571--
2576--
2572-- >>> splitAt_ 6 "Hello World!"
2577-- >>> splitAt_ 6 "Hello World!"
2573-- > ("Hello ","World!")
2578-- > ("Hello ","World!")
@@ -2656,7 +2661,7 @@ groupScan split fold m = undefined
2656-- | Group the input stream into groups of @n@ elements each and then fold each
2661-- | Group the input stream into groups of @n@ elements each and then fold each
2657-- group using the provided fold function.
2662-- group using the provided fold function.
2658--
2663--
2659−-- >> S.toList $ FL.chunksOf 2 FL.sum (S.enumerateFromTo 1 10)
2664+-- >> S.toList $ S.chunksOf 2 FL.sum (S.enumerateFromTo 1 10)
2660-- > [3,7,11,15,19]
2665-- > [3,7,11,15,19]
2661--
2666--
2662-- This can be considered as an n-fold version of 'ltake' where we apply
2667-- This can be considered as an n-fold version of 'ltake' where we apply
@@ -2736,7 +2741,7 @@ _spanBy cmp (Fold stepL initialL extractL) (Fold stepR initialR extractR) =
2736-- input as long as the predicate @p@ is 'True'. @f2@ consumes the rest of the
2741-- input as long as the predicate @p@ is 'True'. @f2@ consumes the rest of the
2737-- input.
2742-- input.
2738--
2743--
2739−-- > let span_ p xs = FL.foldl' (FL.span p FL.toList FL.toList) $ S.fromList xs
2744+-- > let span_ p xs = S.runFold (S.span p FL.toList FL.toList) $ S.fromList xs
2740--
2745--
2741-- >>> span_ (< 1) [1,2,3]
2746-- >>> span_ (< 1) [1,2,3]
2742-- > ([],[1,2,3])
2747-- > ([],[1,2,3])
@@ -2781,7 +2786,7 @@ span p (Fold stepL initialL extractL) (Fold stepR initialR extractR) =
2781--
2786--
2782-- This is the binary version of 'splitBy'.
2787-- This is the binary version of 'splitBy'.
2783--
2788--
2784−-- > let break_ p xs = FL.foldl' (FL.break p FL.toList FL.toList) $ S.fromList xs
2789+-- > let break_ p xs = S.runFold (S.break p FL.toList FL.toList) $ S.fromList xs
2785--
2790--
2786-- >>> break_ (< 1) [3,2,1]
2791-- >>> break_ (< 1) [3,2,1]
2787-- > ([3,2,1],[])
2792-- > ([3,2,1],[])
@@ -2838,7 +2843,7 @@ _spanRollingBy cmp (Fold stepL initialL extractL) (Fold stepR initialR extractR)
2838-- group is folded using the fold @f@ and the result of the fold is emitted in
2843-- group is folded using the fold @f@ and the result of the fold is emitted in
2839-- the output stream.
2844-- the output stream.
2840--
2845--
2841−-- >>> S.toList $ FL.groupsBy (>) FL.toList $ S.fromList [1,3,7,0,2,5]
2846+-- >>> S.toList $ S.groupsBy (>) FL.toList $ S.fromList [1,3,7,0,2,5]
2842-- > [[1,3,7],[0,2,5]]
2847-- > [[1,3,7],[0,2,5]]
2843--
2848--
2844-- @since 0.7.0
2849-- @since 0.7.0
@@ -2859,7 +2864,7 @@ groupsBy cmp f m = D.fromStreamD $ D.groupsBy cmp f (D.toStreamD m)
2859-- comparison fails a new group is started. Each group is folded using the fold
2864-- comparison fails a new group is started. Each group is folded using the fold
2860-- @f@.
2865-- @f@.
2861--
2866--
2862−-- >>> S.toList $ FL.groupsByRolling (\a b -> a + 1 == b) FL.toList $ S.fromList [1,2,3,7,8,9]
2867+-- >>> S.toList $ S.groupsByRolling (\a b -> a + 1 == b) FL.toList $ S.fromList [1,2,3,7,8,9]
2863-- > [[1,2,3],[7,8,9]]
2868-- > [[1,2,3],[7,8,9]]
2864--
2869--
2865-- @since 0.7.0
2870-- @since 0.7.0
@@ -2878,7 +2883,7 @@ groupsByRolling cmp f m = D.fromStreamD $ D.groupsRollingBy cmp f (D.toStreamD
2878--
2883--
2879-- Groups contiguous spans of equal elements together in individual groups.
2884-- Groups contiguous spans of equal elements together in individual groups.
2880--
2885--
2881−-- >>> S.toList $ FL.groups FL.toList $ S.fromList [1,1,2,2]
2886+-- >>> S.toList $ S.groups FL.toList $ S.fromList [1,1,2,2]
2882-- > [[1,1],[2,2]]
2887-- > [[1,1],[2,2]]
2883--
2888--
2884-- @since 0.7.0
2889-- @since 0.7.0
@@ -2895,7 +2900,7 @@ groups = groupsBy (==)
2895-- stream before the sequence and the second part consisting of the sequence
2900-- stream before the sequence and the second part consisting of the sequence
2896-- and the rest of the stream.
2901-- and the rest of the stream.
2897--
2902--
2898−-- > let breakOn_ pat xs = FL.foldl' (FL.breakOn pat FL.toList FL.toList) $ S.fromList xs
2903+-- > let breakOn_ pat xs = S.runFold (S.breakOn pat FL.toList FL.toList) $ S.fromList xs
2899--
2904--
2900-- >>> breakOn_ "dear" "Hello dear world!"
2905-- >>> breakOn_ "dear" "Hello dear world!"
2901-- > ("Hello ","dear world!")
2906-- > ("Hello ","dear world!")
@@ -2931,7 +2936,7 @@ breakOn pat f m = undefined
2931--
2936--
2932-- Let's use the following definition for illustration:
2937-- Let's use the following definition for illustration:
2933--
2938--
2934−-- > splitOn' p xs = S.toList $ FL.splitOn p (FL.toList) (S.fromList xs)
2939+-- > splitOn' p xs = S.toList $ S.splitOn p (FL.toList) (S.fromList xs)
2935--
2940--
2936-- >>> splitOn' (== '.') ""
2941-- >>> splitOn' (== '.') ""
2937-- [""]
2942-- [""]
@@ -2975,7 +2980,7 @@ splitOn predicate f m =
2975-- ".--." => "" "--"
2980-- ".--." => "" "--"
2976-- @
2981-- @
2977--
2982--
2978−-- > splitOnSuffix' p xs = S.toList $ FL.splitSuffixBy p (FL.toList) (S.fromList xs)
2983+-- > splitOnSuffix' p xs = S.toList $ S.splitSuffixBy p (FL.toList) (S.fromList xs)
2979--
2984--
2980-- >>> splitOnSuffix' (== '.') ""
2985-- >>> splitOnSuffix' (== '.') ""
2981-- []
2986-- []
@@ -3021,7 +3026,7 @@ splitOnSuffix predicate f m =
3021-- @["a","b"]@. In other words, it treats the input like words separated by
3026-- @["a","b"]@. In other words, it treats the input like words separated by
3022-- whitespace elements determined by the predicate.
3027-- whitespace elements determined by the predicate.
3023--
3028--
3024−-- > wordsBy' p xs = S.toList $ FL.wordsBy p (FL.toList) (S.fromList xs)
3029+-- > wordsBy' p xs = S.toList $ S.wordsBy p (FL.toList) (S.fromList xs)
3025--
3030--
3026-- >>> wordsBy' (== ',') ""
3031-- >>> wordsBy' (== ',') ""
3027-- > []
3032-- > []
@@ -3045,7 +3050,7 @@ wordsBy predicate f m =
3045-- | Like 'splitOnSuffix' but keeps the suffix attached to the resulting
3050-- | Like 'splitOnSuffix' but keeps the suffix attached to the resulting
3046-- splits.
3051-- splits.
3047--
3052--
3048−-- > splitBySuffix' p xs = S.toList $ FL.splitBySuffix p (FL.toList) (S.fromList xs)
3053+-- > splitBySuffix' p xs = S.toList $ S.splitBySuffix p (FL.toList) (S.fromList xs)
3049--
3054--
3050-- >>> splitBySuffix' (== '.') ""
3055-- >>> splitBySuffix' (== '.') ""
3051-- []
3056-- []
@@ -3119,7 +3124,7 @@ splitBySuffix predicate f m =
3119-- For illustration, let's define a function that operates on pure lists:
3124-- For illustration, let's define a function that operates on pure lists:
3120--
3125--
3121-- @
3126-- @
3122−-- splitOnSeq' pat xs = S.toList $ FL.splitOnSeq (A.fromList pat) (FL.toList) (S.fromList xs)
3127+-- splitOnSeq' pat xs = S.toList $ S.splitOnSeq (A.fromList pat) (FL.toList) (S.fromList xs)
3123-- @
3128-- @
3124--
3129--
3125-- >>> splitOnSeq' "" "hello"
3130-- >>> splitOnSeq' "" "hello"
@@ -3184,7 +3189,7 @@ splitOnAny subseq f m = undefined -- D.fromStreamD $ D.splitOnAny f subseq (D.to
3184-- | Like 'splitSuffixBy' but the separator is a sequence of elements, instead
3189-- | Like 'splitSuffixBy' but the separator is a sequence of elements, instead
3185-- of a predicate for a single element.
3190-- of a predicate for a single element.
3186--
3191--
3187−-- > splitSuffixOn_ pat xs = S.toList $ FL.splitSuffixOn (A.fromList pat) (FL.toList) (S.fromList xs)
3192+-- > splitSuffixOn_ pat xs = S.toList $ S.splitSuffixOn (A.fromList pat) (FL.toList) (S.fromList xs)
3188--
3193--
3189-- >>> splitSuffixOn_ "." ""
3194-- >>> splitSuffixOn_ "." ""
3190-- [""]
3195-- [""]
@@ -3234,7 +3239,7 @@ wordsOn subseq f m = undefined -- D.fromStreamD $ D.wordsOn f subseq (D.toStream
3234--
3239--
3235-- | Like 'splitOnSeq' but splits the separator as well, as an infix token.
3240-- | Like 'splitOnSeq' but splits the separator as well, as an infix token.
3236--
3241--
3237−-- > splitOn'_ pat xs = S.toList $ FL.splitOn' (A.fromList pat) (FL.toList) (S.fromList xs)
3242+-- > splitOn'_ pat xs = S.toList $ S.splitOn' (A.fromList pat) (FL.toList) (S.fromList xs)
3238--
3243--
3239-- >>> splitOn'_ "" "hello"
3244-- >>> splitOn'_ "" "hello"
3240-- > ["h","","e","","l","","l","","o"]
3245-- > ["h","","e","","l","","l","","o"]