on master help sign in
update fold and unfold documentation
commitf25400833837f395b1738932883bea2c427794ca authorHarendra Kumar <harendra.kumar@gmail.com> dateTue 5 Nov 2019, 00:44 (7 years ago) parentcce1c6e
2 files changed+50−38
src/Streamly/Data/Fold.hs+41−28 src/Streamly/Data/Unfold.hs+9−10
src/Streamly/Data/Fold.hs+41−28
@@ -2,45 +2,58 @@
22-- Module : Streamly.Data.Fold
33-- Copyright : (c) 2019 Composewell Technologies
44-- License : BSD3
5−-- Maintainer : harendra@composewell.com
5+-- Maintainer : streamly@composewell.com
66-- Stability : experimental
77-- Portability : GHC
88--
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
9+-- 'Fold' type represents an effectful action that consumes a value from an
10+-- input stream and combines it with a single final value often called an
11+-- accumulator, returning the resulting output accumulator. Values from a
12+-- stream can be /pushed/ to the fold and consumed one at a time. It can also
13+-- be called a consumer of stream or a sink. It is a data representation of
14+-- the standard 'Streamly.Prelude.foldl'' function. A 'Fold' can be turned
15+-- into an effect (@m b@) using 'Streamly.Prelude.fold' by supplying it the
16+-- input stream.
17+--
18+-- Using this representation multiple folds can be combined efficiently using
1319-- 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.
20+-- distribute the input to constituent folds according to the composition. For
21+-- example, an applicative composition distributes the same input to the
22+-- constituent folds and then combines the resulting fold outputs. Similarly,
23+-- a partitioning combinator divides the input among constituent folds.
2124--
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.
25+-- = Performance Notes
2826--
29−-- > import qualified Streamly.Internal.Data.Fold as FL
30−
31−-- Also see the "Streamly.Internal.Data.Sink" module that provides specialized left folds
32−-- that discard the outputs.
27+-- 'Fold' representation is more efficient than using streams when splitting
28+-- streams. @Fold m a b@ can be considered roughly equivalent to a fold action
29+-- @m b -> t m a -> m b@ (where @t@ is a stream type and @m@ is a 'Monad').
30+-- Instead of using a 'Fold' type one could just use a fold action of the shape
31+-- @m b -> t m a -> m b@ for folding streams. However, multiple such actions
32+-- cannot be composed into a single fold function in an efficient manner.
33+-- Using the 'Fold' type we can efficiently split the stream across mutliple
34+-- folds because it allows the compiler to perform stream fusion optimizations.
35+--
36+-- On the other hand, transformation operations (e.g. 'Streamly.Prelude.map')
37+-- on stream types can be as efficient as transformations on 'Fold' (e.g.
38+-- 'Streamly.Internal.Data.Fold.lmap').
3339--
40+-- = Programmer Notes
41+--
42+-- > import qualified Streamly.Data.Fold as FL
43+--
44+-- More, not yet exposed, fold combinators can be found in
45+-- "Streamly.Internal.Data.Fold".
46+
3447-- IMPORTANT: keep the signatures consistent with the folds in Streamly.Prelude
3548
3649module Streamly.Data.Fold
3750 (
3851 -- * Fold Type
3952 -- |
40− -- A 'Fold' can be run over a stream using the 'runFold' combinator in
41− -- "Streamly.Prelude":
53+ -- A 'Fold' can be run over a stream using the 'Streamly.Prelude.fold'
54+ -- combinator:
4255 --
43− -- >>> S.runFold FL.sum (S.enumerateFromTo 1 100)
56+ -- >>> S.fold FL.sum (S.enumerateFromTo 1 100)
4457 -- 5050
4558
4659 Fold -- (..)
@@ -105,7 +118,7 @@ module Streamly.Data.Fold
105118 -- Transformations can be applied either on the input side or on the output
106119 -- side. The 'Functor' instance of a fold maps on the output of the fold:
107120 --
108− -- >>> S.runFold (fmap show FL.sum) (S.enumerateFromTo 1 100)
121+ -- >>> S.fold (fmap show FL.sum) (S.enumerateFromTo 1 100)
109122 -- "5050"
110123 --
111124 -- However, the input side or contravariant transformations are more
@@ -181,7 +194,7 @@ module Streamly.Data.Fold
181194 -- stream twice:
182195 --
183196 -- >>> let avg = (/) <$> FL.sum <*> fmap fromIntegral FL.length
184− -- >>> S.runFold avg (S.enumerateFromTo 1.0 100.0)
197+ -- >>> S.fold avg (S.enumerateFromTo 1.0 100.0)
185198 -- 50.5
186199 --
187200 -- The 'Semigroup' and 'Monoid' instances of a distributing fold distribute
@@ -189,7 +202,7 @@ module Streamly.Data.Fold
189202 -- Semigroup instances of the output types:
190203 --
191204 -- >>> import Data.Monoid (Sum)
192− -- >>> S.runFold (FL.head <> FL.last) (fmap Sum $ S.enumerateFromTo 1.0 100.0)
205+ -- >>> S.fold (FL.head <> FL.last) (fmap Sum $ S.enumerateFromTo 1.0 100.0)
193206 -- Just (Sum {getSum = 101.0})
194207 --
195208 -- The 'Num', 'Floating', and 'Fractional' instances work in the same way.
src/Streamly/Data/Unfold.hs+9−10
@@ -19,16 +19,18 @@
1919-- Portability : GHC
2020--
2121-- 'Unfold' type represents an effectful action that generates a stream of
22−-- values from a single starting value often called a seed value. It can also
23−-- be called a producer or a source of stream. It is a data representation of
24−-- the standard 'S.unfoldr' function. An 'Unfold' can be converted into a
25−-- stream using 'S.unfold' by supplying the seed.
22+-- values from a single starting value often called a seed value. Values can be
23+-- generated and /pulled/ from the 'Unfold' one at a time. It can also be
24+-- called a producer or a source of stream. It is a data representation of the
25+-- standard 'S.unfoldr' function. An 'Unfold' can be converted into a stream
26+-- type using 'S.unfold' by supplying the seed.
2627--
2728-- = Performance Notes
2829--
29−-- 'Unfold' type allows multiple unfold actions to be composed into a single
30−-- unfold function in an efficient manner by enabling the compiler to perform
31−-- stream fusion optimization.
30+-- 'Unfold' representation is more efficient than using streams when combining
31+-- streams. 'Unfold' type allows multiple unfold actions to be composed into a
32+-- single unfold function in an efficient manner by enabling the compiler to
33+-- perform stream fusion optimization.
3234-- @Unfold m a b@ can be considered roughly equivalent to an action @a -> t m
3335-- b@ (where @t@ is a stream type). Instead of using an 'Unfold' one could just
3436-- use a function of the shape @a -> t m b@. However, working with stream types
@@ -68,6 +70,3 @@ where
6870
6971import Prelude hiding (concat, map, takeWhile, take, filter, const)
7072import Streamly.Internal.Data.Unfold
71−
72−-- imported for documentation links
73−import qualified Streamly.Prelude as S