@@ -0,0 +1,247 @@
2+-- Module : Streamly.Data.Fold
3+-- Copyright : (c) 2019 Composewell Technologies
5+-- Maintainer : harendra@composewell.com
6+-- Stability : experimental
9+-- A left fold consumes a stream and reduces it to a single value. The fold
10+-- operations in "Streamly.Prelude" cannot be combined such that multiple of
11+-- them can run on the same stream. This module provides a 'Fold' type that
12+-- represents a left fold. Multiple such folds can be combined using
13+-- combinators; a stream can then be supplied to the combined fold and it would
14+-- distribute the input to constituent folds according to the composition.
15+-- For example, an applicative composition distributes the same input to
16+-- the constituent folds and then combines the fold outputs. Similarly, a
17+-- partitioning combinator can divide the input among constituent folds.
18+-- All the combinators in this module are of true streaming nature, stream
19+-- elements are not unnecessarily buffered in memory, guaranteeing a constant
20+-- memory consumption.
22+-- Consider this module as the consumer side dual of the "Streamly.Prelude"
23+-- module. "Streamly.Prelude" provides combinators that can combine stream
24+-- sources in interesting ways whereas this module provides combinators that
25+-- combine stream consumers in interesting ways. In other words,
26+-- "Streamly.Prelude" provides stream merging capabilities while
27+-- "Streamly.Internal.Data.Fold" provides stream splitting capabilities.
29+-- > import qualified Streamly.Internal.Data.Fold as FL
31+-- Also see the "Streamly.Sink" module that provides specialized left folds
32+-- that discard the outputs.
34+-- IMPORTANT: keep the signatures consistent with the folds in Streamly.Prelude
36+module Streamly.Data.Fold
40+ -- A 'Fold' can be run over a stream using the 'runFold' combinator in
41+ -- "Streamly.Prelude":
43+ -- >>> S.runFold FL.sum (S.enumerateFromTo 1 100)
67+ -- ** Full Folds (Monoidal)
72+ -- ** Full Folds (To Containers)
73+ -- | Avoid using these folds in scalable or performance critical
74+ -- applications, they buffer all the input in GC memory which can be
75+ -- detrimental to performance if the input is large.
95+ -- XXX these are slower than right folds even when full input is used
101+ -- * Transformations
102+ -- | Unlike stream producer types (e.g. @SerialT m a@) which have only
103+ -- output side, folds have an input side as well as an output side. In the
104+ -- type @Fold m a b@, the input type is @a@ and the output type is @b@.
105+ -- Transformations can be applied either on the input side or on the output
106+ -- side. The 'Functor' instance of a fold maps on the output of the fold:
108+ -- >>> S.runFold (fmap show FL.sum) (S.enumerateFromTo 1 100)
111+ -- However, the input side or contravariant transformations are more
112+ -- interesting for folds. The following sections describe the input
113+ -- transformation operations on a fold. The names of the operations are
114+ -- consistent with their covariant counterparts in "Streamly.Prelude", the
115+ -- only difference is that they are prefixed with 'l' which stands for
116+ -- 'left' assuming left side is the input side, notice that in @Fold m a b@
117+ -- the type variable @a@ is on the left side.
119+ -- ** Covariant Operations
136+ -- ** Mapping Filters
140+ -- ** Scanning Filters
145+ -- | Insertion adds more elements to the stream.
158+ -- , lrunFor -- time
168+ -- The 'Applicative' instance of a distributing 'Fold' distributes one copy
169+ -- of the stream to each fold and combines the results using a function.
173+ -- |-------Fold m a b--------|
174+ -- ---stream m a---| |---m (b,c,...)
175+ -- |-------Fold m a c--------|
180+ -- To compute the average of numbers in a stream without going throught he
183+ -- >>> let avg = (/) <$> FL.sum <*> fmap fromIntegral FL.length
184+ -- >>> S.runFold avg (S.enumerateFromTo 1.0 100.0)
187+ -- The 'Semigroup' and 'Monoid' instances of a distributing fold distribute
188+ -- the input to both the folds and combines the outputs using Monoid or
189+ -- Semigroup instances of the output types:
191+ -- >>> import Data.Monoid (Sum)
192+ -- >>> S.runFold (FL.head <> FL.last) (fmap Sum $ S.enumerateFromTo 1.0 100.0)
193+ -- Just (Sum {getSum = 101.0})
195+ -- The 'Num', 'Floating', and 'Fractional' instances work in the same way.
202+ -- Direct items in the input stream to different folds using a binary
210+ -- | Direct values in the input stream to different folds using an n-ary
219+ -- | In an input stream of key value pairs fold values for different keys
220+ -- in individual output buckets using the given fold.
227+ -- These can be expressed using lmap/lmapM and unzip
231+ -- -- * Nested Folds
234+ -- , duplicate -- experimental
239+ hiding (filter, drop, dropWhile, take, takeWhile, zipWith, foldr,
240+ foldl, map, mapM_, sequence, all, any, sum, product, elem,
241+ notElem, maximum, minimum, head, last, tail, length, null,
242+ reverse, iterate, init, and, or, lookup, foldr1, (!!),
243+ scanl, scanl1, replicate, concatMap, mconcat, foldMap, unzip,
244+ span, splitAt, break, mapM)
246+import Streamly.Internal.Data.Fold
247+import Streamly.Internal.Data.Fold.Types