Skip to content

Commit 818c30a

Browse files
Add some doc/comments to fold functions
1 parent 5593a49 commit 818c30a

2 files changed

Lines changed: 46 additions & 37 deletions

File tree

core/src/Streamly/Internal/Data/Fold/Combinators.hs

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -593,8 +593,7 @@ repeated = error "Not implemented yet!"
593593
-- >>> drainMapM f = Fold.lmapM f Fold.drain
594594
-- >>> drainMapM f = Fold.foldMapM (void . f)
595595
--
596-
-- Drain all input after passing it through a monadic function. This is the
597-
-- dual of mapM_ on stream producers.
596+
-- Drain all input after passing it through a monadic function.
598597
--
599598
{-# INLINE drainMapM #-}
600599
drainMapM :: Monad m => (a -> m b) -> Fold m a ()
@@ -1742,7 +1741,7 @@ tee = teeWith (,)
17421741
-- XXX use "List" instead of "[]"?, use Array for output to scale it to a large
17431742
-- number of consumers? For polymorphic case a vector could be helpful. For
17441743
-- Unboxs we can use arrays. Will need separate APIs for those.
1745-
--
1744+
17461745
-- | Distribute one copy of the stream to each fold and collect the results in
17471746
-- a container.
17481747
--
@@ -1760,8 +1759,6 @@ tee = teeWith (,)
17601759
--
17611760
-- >>> distribute = Prelude.foldr (Fold.teeWith (:)) (Fold.fromPure [])
17621761
--
1763-
-- This is the consumer side dual of the producer side 'sequence' operation.
1764-
--
17651762
-- Stops when all the folds stop.
17661763
--
17671764
{-# INLINE distribute #-}
@@ -1877,8 +1874,6 @@ partitionByMUsing t f fld1 fld2 =
18771874
-- (67,33)
18781875
--
18791876
--
1880-
-- This is the consumer side dual of the producer side 'mergeBy' operation.
1881-
--
18821877
-- When one fold is done, any input meant for it is ignored until the other
18831878
-- fold is also done.
18841879
--
@@ -1922,7 +1917,9 @@ partitionByMinM = partitionByMUsing teeWithMin
19221917
-- :}
19231918
-- ("Even 50","Odd 50")
19241919
--
1925-
-- /Pre-release/
1920+
-- NOTE: This is the exact analogue of the @choose@ method of the Contravariant
1921+
-- functor typeclass Decidable.
1922+
--
19261923
{-# INLINE partitionBy #-}
19271924
partitionBy :: Monad m
19281925
=> (a -> Either b c) -> Fold m b x -> Fold m c y -> Fold m a (x, y)
@@ -2005,7 +2002,9 @@ unzipWithMinM = unzipWithMUsing teeWithMin
20052002
--
20062003
-- This fold terminates when both the input folds terminate.
20072004
--
2008-
-- /Pre-release/
2005+
-- NOTE: This is the exact analogue of the @divide@ method of the Contravariant
2006+
-- functor typeclass Divisible.
2007+
--
20092008
{-# INLINE unzipWith #-}
20102009
unzipWith :: Monad m
20112010
=> (a -> (b,c)) -> Fold m b x -> Fold m c y -> Fold m a (x,y)
@@ -2026,8 +2025,6 @@ unzipWith f = unzipWithM (return . f)
20262025
--
20272026
-- >>> unzip = Fold.unzipWith id
20282027
--
2029-
-- This is the consumer side dual of the producer side 'zip' operation.
2030-
--
20312028
{-# INLINE unzip #-}
20322029
unzip :: Monad m => Fold m a x -> Fold m b y -> Fold m (a,b) (x,y)
20332030
unzip = unzipWith id

core/src/Streamly/Internal/Data/Fold/Type.hs

Lines changed: 38 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,16 @@
342342
-- can be expressed using 'mconcat' and a suitable 'Monoid'. Instead of
343343
-- writing folds we can write Monoids and turn them into folds.
344344
--
345+
-- = Initial, Final Duality
346+
--
347+
-- Currently there is a discrepancy between folds and streams, folds have an
348+
-- "initial" to initialize the fold without any input. A producer side dual
349+
-- would be a finalizer called whenever the stream stops.
350+
--
351+
-- However, the initial action in folds creates a discrepancy with the CPS
352+
-- folds, and the same may be the case if we have a stop/cleanup operation in
353+
-- streams.
354+
345355
module Streamly.Internal.Data.Fold.Type
346356
(
347357
module Streamly.Internal.Data.Fold.Step
@@ -816,6 +826,8 @@ fromRefold (Refold step inject extract) c =
816826
-- Basic Folds
817827
------------------------------------------------------------------------------
818828

829+
-- drain is a dual of infinite streams. This is the /dev/null of folds.
830+
819831
-- | A fold that drains all its input, running the effects and discarding the
820832
-- results.
821833
--
@@ -830,6 +842,8 @@ drain = fromScanl Scanl.drain
830842
-- To Containers
831843
------------------------------------------------------------------------------
832844

845+
-- toList is a dual of Stream.fromList.
846+
833847
-- | Folds the input stream to a list.
834848
--
835849
-- /Warning!/ working on large lists accumulated as buffers in memory could be
@@ -876,6 +890,8 @@ toListRev = foldl' (flip (:)) []
876890
toStreamKRev :: Monad m => Fold m a (K.StreamK n a)
877891
toStreamKRev = fromScanl Scanl.toStreamKRev
878892

893+
-- toStreamK is a dual of Stream.fromStreamK
894+
879895
-- | A fold that buffers its input to a pure stream.
880896
--
881897
-- >>> toStreamK = foldr StreamK.cons StreamK.nil
@@ -909,6 +925,9 @@ genericLength = fromScanl Scanl.genericLength
909925
length :: Monad m => Fold m a Int
910926
length = fromScanl Scanl.length
911927

928+
-- Naming: "last" makes better sense for folds whereas "latest" makes better
929+
-- sense for scans.
930+
912931
-- | Returns the latest element of the input stream, if any.
913932
--
914933
-- >>> latest = Fold.foldl1' (\_ x -> x)
@@ -939,39 +958,27 @@ instance Functor m => Functor (Fold m a) where
939958
step s b = fmap2 f (step1 s b)
940959
fmap2 g = fmap (fmap g)
941960

942-
-- XXX These are singleton folds that are closed for input. The correspondence
943-
-- to a nil stream would be a nil fold that returns "Done" in "initial" i.e. it
944-
-- does not produce any accumulator value. However, we do not have a
945-
-- representation of an empty value in folds, because the Done constructor
946-
-- always produces a value (Done b). We can potentially use "Partial s b" and
947-
-- "Done" to make the type correspond to the stream type. That may be possible
948-
-- if we introduce the "Skip" constructor as well because after the last
949-
-- "Partial s b" we have to emit a "Skip to Done" state to keep cranking the
950-
-- fold until it is done.
951-
--
952-
-- There is also the asymmetry between folds and streams because folds have an
953-
-- "initial" to initialize the fold without any input. A similar concept is
954-
-- possible in streams as well to stop the stream. That would be a "closing"
955-
-- operation for the stream which can be called even without consuming any item
956-
-- from the stream or when we are done consuming.
961+
-- NOTE: Canonical producer side dual of this is "Stream.nil" which generates a
962+
-- nil stream regardless of the seed. This folds a nil stream to some known
963+
-- value, reversing the producer side process.
957964
--
958-
-- However, the initial action in folds creates a discrepancy with the CPS
959-
-- folds, and the same may be the case if we have a stop/cleanup operation in
960-
-- streams.
965+
-- Alternate names: const
961966

962-
-- | Make a fold that yields the supplied value without consuming any further
963-
-- input.
964-
--
965-
-- /Pre-release/
967+
-- | Make a fold that immediately returns a constant output without consuming
968+
-- any input.
966969
--
967970
{-# INLINE fromPure #-}
968971
fromPure :: Applicative m => b -> Fold m a b
969972
fromPure b = Fold undefined (pure $ Done b) pure pure
970973

971-
-- | Make a fold that yields the result of the supplied effectful action
972-
-- without consuming any further input.
974+
-- NOTE: Canonical producer side dual of this is "Stream.nilM" which generates
975+
-- a nil stream and an effect. This folds a nil stream to some known value and
976+
-- an effect, reverse of the producer.
973977
--
974-
-- /Pre-release/
978+
-- Alternative names: constM
979+
980+
-- | Make a fold that immediately returns a constant output along with an
981+
-- effect without consuming any input.
975982
--
976983
{-# INLINE fromEffect #-}
977984
fromEffect :: Applicative m => m b -> Fold m a b
@@ -980,6 +987,9 @@ fromEffect b = Fold undefined (Done <$> b) pure pure
980987
{-# ANN type SeqFoldState Fuse #-}
981988
data SeqFoldState sl f sr = SeqFoldL !sl | SeqFoldR !f !sr
982989

990+
-- dual of Stream.append
991+
-- Alternative names: appendWith, serialWith.
992+
983993
-- | Sequential fold application. Apply two folds sequentially to an input
984994
-- stream. The input is provided to the first fold, when it is done - the
985995
-- remaining input is provided to the second fold. When the second fold is done
@@ -2054,6 +2064,8 @@ ifThen predicate
20542064
-- 'duplicate' essentially appends a stream to the fold without finishing the
20552065
-- fold. Compare with 'snoc' which appends a singleton value to the fold.
20562066
--
2067+
-- See 'Fold.addStream' as well.
2068+
--
20572069
-- /Pre-release/
20582070
{-# INLINE duplicate #-}
20592071
duplicate :: Monad m => Fold m a b -> Fold m a (Fold m a b)
@@ -2086,7 +2098,7 @@ reduce (Fold step initial extract final) = do
20862098
i <- initial
20872099
return $ Fold step (return i) extract final
20882100

2089-
-- This is the dual of Stream @cons@.
2101+
-- This is a fold builder equivalent of the stream builder @cons@.
20902102

20912103
-- | Append an effect to the fold lazily, in other words run a single
20922104
-- step of the fold.

0 commit comments

Comments
 (0)