@@ -172,6 +172,10 @@ module Streamly.Internal.Data.Fold.Types
172 , Fold (..)
172 , Fold (..)
174 -- * Fold constructors
174 -- * Fold constructors
175 , mkAccum
179 , mkAccum
176 , mkAccum_
180 , mkAccum_
177 , mkAccumM
181 , mkAccumM
@@ -230,10 +234,10 @@ module Streamly.Internal.Data.Fold.Types
237+import Control.Monad (void, (>=>))
233import Control.Concurrent (threadDelay, forkIO, killThread)
238import Control.Concurrent (threadDelay, forkIO, killThread)
234import Control.Concurrent.MVar (MVar, newMVar, swapMVar, readMVar)
239import Control.Concurrent.MVar (MVar, newMVar, swapMVar, readMVar)
235import Control.Exception (SomeException(..), catch, mask)
240import Control.Exception (SomeException(..), catch, mask)
236−import Control.Monad (void)
237import Control.Monad.IO.Class (MonadIO(..))
241import Control.Monad.IO.Class (MonadIO(..))
238import Control.Monad.Trans.Control (control)
242import Control.Monad.Trans.Control (control)
239import Data.Bifunctor (Bifunctor(..))
243import Data.Bifunctor (Bifunctor(..))
@@ -296,6 +300,11 @@ instance Functor (Step s) where
296 {-# INLINE fmap #-}
300 {-# INLINE fmap #-}
297 fmap = second
301 fmap = second
303+-- The Step functor around b allows expressing early termination like a right
304+-- fold. Traditional list right folds use function composition and laziness to
305+-- terminate early whereas we use data constructors. It allows stream fusion in
306+-- contrast to the foldr/build fusion when composing with functions.
299-- | The type @Fold m a b@ having constructor @Fold step initial extract@
308-- | The type @Fold m a b@ having constructor @Fold step initial extract@
300-- represents a left fold over an input stream of values of type @a@ to a
309-- represents a left fold over an input stream of values of type @a@ to a
301-- single value of type @b@ in 'Monad' @m@. The constructor is not exposed via
310-- single value of type @b@ in 'Monad' @m@. The constructor is not exposed via
@@ -318,16 +327,41 @@ data Fold m a b =
318 forall s. Fold (s -> a -> m (Step s b)) (m (Step s b)) (s -> m b)
327 forall s. Fold (s -> a -> m (Step s b)) (m (Step s b)) (s -> m b)
320------------------------------------------------------------------------------
329------------------------------------------------------------------------------
321−-- Smart constructors
330+-- Left fold constructors
322------------------------------------------------------------------------------
331------------------------------------------------------------------------------
333+-- | Make a fold from a left fold style pure step function and initial value of
338+{-# INLINE mkFoldl #-}
339+mkFoldl :: Monad m => (b -> a -> b) -> b -> Fold m a b
340+mkFoldl step initial =
342+ (\s a -> return $ Partial $ step s a)
343+ (return (Partial initial))
346+-- | Make a fold from a left fold style monadic step function and initial value
347+-- of the accumulator.
351+{-# INLINE mkFoldlM #-}
352+mkFoldlM :: Monad m => (b -> a -> m b) -> m b -> Fold m a b
353+mkFoldlM step initial =
354+ Fold (\s a -> Partial <$> step s a) (Partial <$> initial) return
324-- | Make an accumulating (non-terminating) fold using a pure step function, a
356-- | Make an accumulating (non-terminating) fold using a pure step function, a
325-- pure initial state and a pure state extraction function.
357-- pure initial state and a pure state extraction function.
327-- If your 'Fold' returns only 'Partial' (i.e. never returns a 'Done') then you
359-- If your 'Fold' returns only 'Partial' (i.e. never returns a 'Done') then you
328-- can use @mkAccum*@ constructors.
360-- can use @mkAccum*@ constructors.
330−-- /Pre-release/
362+-- > mkAccum step initial extract = fmap extract (mkFoldl step initial)
332{-# INLINE mkAccum #-}
366{-# INLINE mkAccum #-}
333mkAccum :: Monad m => (s -> a -> s) -> s -> (s -> b) -> Fold m a b
367mkAccum :: Monad m => (s -> a -> s) -> s -> (s -> b) -> Fold m a b
@@ -344,16 +378,18 @@ mkAccum step initial extract =
344-- mkAccum_ step initial = mkAccum step initial id
378-- mkAccum_ step initial = mkAccum step initial id
347−-- /Pre-release/
381+-- /Internal/
349{-# INLINE mkAccum_ #-}
383{-# INLINE mkAccum_ #-}
350mkAccum_ :: Monad m => (b -> a -> b) -> b -> Fold m a b
384mkAccum_ :: Monad m => (b -> a -> b) -> b -> Fold m a b
351−mkAccum_ step initial = mkAccum step initial id
385+mkAccum_ = mkFoldl
353-- | Make an accumulating (non-terminating) fold with an effectful step
387-- | Make an accumulating (non-terminating) fold with an effectful step
354-- function, an initial state, and a state extraction function.
388-- function, an initial state, and a state extraction function.
356−-- /Pre-release/
390+-- > mkAccumM step initial extract = rmapM extract (mkFoldlM step initial)
358{-# INLINE mkAccumM #-}
394{-# INLINE mkAccumM #-}
359mkAccumM :: Functor m => (s -> a -> m s) -> m s -> (s -> m b) -> Fold m a b
395mkAccumM :: Functor m => (s -> a -> m s) -> m s -> (s -> m b) -> Fold m a b
@@ -367,11 +403,45 @@ mkAccumM step initial =
367-- mkAccumM_ step initial = mkAccumM step initial return
403-- mkAccumM_ step initial = mkAccumM step initial return
370−-- /Pre-release/
406+-- /Internal/
372{-# INLINE mkAccumM_ #-}
408{-# INLINE mkAccumM_ #-}
373mkAccumM_ :: Monad m => (b -> a -> m b) -> m b -> Fold m a b
409mkAccumM_ :: Monad m => (b -> a -> m b) -> m b -> Fold m a b
374−mkAccumM_ step initial = mkAccumM step initial return
410+mkAccumM_ = mkFoldlM
412+------------------------------------------------------------------------------
413+-- Right fold constructors
414+------------------------------------------------------------------------------
416+-- | Make a fold using a right fold style step function and a terminal value.
417+-- It performs a right fold via a left fold using function composition.
418+-- This can be useful for constructing structures. For reductions this may be
419+-- very inefficient compared to using a direct fold implementation using
424+-- > toList = mkFoldr (:) []
427+{-# INLINE mkFoldr #-}
428+mkFoldr :: Monad m => (a -> b -> b) -> b -> Fold m a b
429+mkFoldr g z = mkAccum (\f x -> f . g x) id ($ z)
431+-- | Like 'mkFoldr' but with a monadic step function.
435+-- > toList = mkFoldrM (\a xs -> return $ a : xs) (return [])
438+{-# INLINE mkFoldrM #-}
439+mkFoldrM :: Monad m => (a -> b -> m b) -> m b -> Fold m a b
440+mkFoldrM g z = mkAccumM (\f x -> return $ g x >=> f) (return return) (z >>=)
442+------------------------------------------------------------------------------
443+-- General fold constructors
444+------------------------------------------------------------------------------
376-- | Make a terminating fold using a pure step function, a pure initial state
446-- | Make a terminating fold using a pure step function, a pure initial state
377-- and a pure state extraction function.
447-- and a pure state extraction function.
@@ -464,11 +534,9 @@ drain = mkAccum_ (\_ _ -> ()) ()
464-- instead.
534-- instead.
466-- @since 0.7.0
536-- @since 0.7.0
468−-- id . (x1 :) . (x2 :) . (x3 :) . ... . (xn :) $ []
469{-# INLINABLE toList #-}
537{-# INLINABLE toList #-}
470toList :: Monad m => Fold m a [a]
538toList :: Monad m => Fold m a [a]
471−toList = mkAccum (\f x -> f . (x :)) id ($ [])
539+toList = mkFoldr (:) []
473------------------------------------------------------------------------------
541------------------------------------------------------------------------------
474-- Instances
542-- Instances