on master help sign in
Update fold docs, implement toFold for parsers
bcf0ab1Harendra Kumar
core/src/Streamly/Internal/Data/Fold/Type.hs+31−16
@@ -493,20 +493,35 @@ import Streamly.Internal.Data.Fold.Step
493-- The "final" function could be (s -> m (Step s b)), like in parsers so that
493-- The "final" function could be (s -> m (Step s b)), like in parsers so that
494-- it can be called in a loop to drain the fold.
494-- it can be called in a loop to drain the fold.
495
495
496−-- | The type @Fold m a b@ having constructor @Fold step initial extract
497−-- final@ represents a fold over an input stream of values of type @a@ to a
496+-- | The type @Fold m a b@ represents a consumer of an input stream of values
498−-- final value of type @b@ in 'Monad' @m@.
497+-- of type @a@ and returning a final value of type @b@ in 'Monad' @m@. The
498+-- constructor of a fold is @Fold step initial extract final@.
499−--
499+--
500−-- The fold uses an intermediate state @s@ as accumulator, the type @s@ is
501−-- internal to the specific fold definition. The initial value of the fold
500+-- The fold uses an internal state of type @s@. The initial value of the state
501+-- @s@ is created by @initial@. This function is called once and only once
502+-- before the fold starts consuming input. Any resource allocation can be done
503+-- in this function.
504+--
502−-- state @s@ is returned by @initial@. The @step@ function consumes an input
505+-- The @step@ function is called on each input, it consumes an input and
503−-- and either returns the final result @b@ if the fold is done or the next
504−-- intermediate state (see 'Step'). At any point the fold driver can extract
506+-- returns the next intermediate state (see 'Step') or the final result @b@ if
505−-- the result from the intermediate state using the @extract@ function. The
507+-- the fold terminates.
506−-- "final" function is used to finalize the fold, the driver can call it
508+--
507−-- whenever it holds a valid fold state which it will not be using anymore. The
509+-- If the fold is used as a scan, the @extract@ function is used by the scan
508−-- state should not be used after finalization. Note that if the fold
510+-- driver to map the current state @s@ of the fold to the fold result. Thus
509−-- terminates itself we won't have a valid fold state.
511+-- @extract@ can be called multiple times. In some folds, where scanning does
512+-- not make sense, this function is left unimplemented; such folds cannot be
513+-- used as scans.
514+--
515+-- Before a fold terminates, @final@ is called once and only once (unless the
516+-- fold terminated in @initial@ itself). Any resources allocated by @initial@
517+-- can be released in @final@. In folds that do not require any cleanup
518+-- @extract@ and @final@ are typically the same.
519+--
520+-- When implementing fold combinators, care should be taken to cleanup any
521+-- state of the argument folds held by the fold by calling the respective
522+-- @final@ at all exit points of the fold. Also, @final@ should not be called
523+-- more than once. Note that if a fold terminates by 'Done' constructor, there
524+-- is no state to cleanup.
510--
525--
511-- NOTE: The constructor is not yet released, smart constructors are provided
526-- NOTE: The constructor is not yet released, smart constructors are provided
512-- to create folds.
527-- to create folds.
@@ -858,8 +873,8 @@ splitWith func
858 step (SeqFoldR f st) a = runR (stepR st a) f
873 step (SeqFoldR f st) a = runR (stepR st a) f
859
874
860 -- XXX splitWith should not be used for scanning
875 -- XXX splitWith should not be used for scanning
861− -- It would rarely make sense and resource cleanup would be expensive.
876+ -- It would rarely make sense and resource tracking and cleanup would be
862− -- especially when multiple splitWith are chained.
877+ -- expensive. especially when multiple splitWith are chained.
863 extract _ = error "splitWith: cannot be used for scanning"
878 extract _ = error "splitWith: cannot be used for scanning"
864
879
865 final (SeqFoldR f sR) = fmap f (finalR sR)
880 final (SeqFoldR f sR) = fmap f (finalR sR)
core/src/Streamly/Internal/Data/Parser.hs+5−8
@@ -21,8 +21,8 @@ module Streamly.Internal.Data.Parser
21 , Step (..)
21 , Step (..)
22 , Initial (..)
22 , Initial (..)
23
23
24− -- -- * Downgrade to Fold
24+ -- * Downgrade to Fold
25− -- , toFold
25+ , toFold
26
26
27 -- First order parsers
27 -- First order parsers
28 -- * Accumulators
28 -- * Accumulators
@@ -270,10 +270,6 @@ import Prelude hiding
270-- Downgrade a parser to a Fold
270-- Downgrade a parser to a Fold
271-------------------------------------------------------------------------------
271-------------------------------------------------------------------------------
272
272
273−-- XXX Parsers cannot be converted to folds, because they do not have a
274−-- scanning function. Can we move the applicative folds to parsers instead?
275−-- need to measure the performance.
276−{-
277-- | Make a 'Fold' from a 'Parser'. The fold just throws an exception if the
273-- | Make a 'Fold' from a 'Parser'. The fold just throws an exception if the
278-- parser fails or tries to backtrack.
274-- parser fails or tries to backtrack.
279--
275--
@@ -313,7 +309,9 @@ toFold (Parser pstep pinitial pextract) = Fold step initial extract final
313 Done n _ -> derror n
309 Done n _ -> derror n
314 Error err -> eerror err
310 Error err -> eerror err
315
311
312+ extract = error "toFold: parser cannot be used for scanning"
313+
316− extract st = do
314+ final st = do
317 r <- pextract st
315 r <- pextract st
318 case r of
316 case r of
319 Done 0 b -> return b
317 Done 0 b -> return b
@@ -321,7 +319,6 @@ toFold (Parser pstep pinitial pextract) = Fold step initial extract final
321 Continue n _ -> cerror n
319 Continue n _ -> cerror n
322 Done n _ -> derror n
320 Done n _ -> derror n
323 Error err -> eerror err
321 Error err -> eerror err
324−-}
325
322
326-------------------------------------------------------------------------------
323-------------------------------------------------------------------------------
327-- Upgrade folds to parses
324-- Upgrade folds to parses