@@ -55,6 +55,7 @@ module Streamly.Internal.Data.Unfold
5555
5656 Unfold
5757 , unfold
58+ , fold
5859
5960 -- ** Unfolds
6061 , singleton
@@ -63,16 +64,21 @@ module Streamly.Internal.Data.Unfold
6364 )
6465where
6566
67+import GHC.Types (SPEC(..))
6668import Streamly.Streams.StreamD.Type (Stream(..), Step(..))
6769#if __GLASGOW_HASKELL__ < 800
6870import Streamly.Streams.StreamD.Type (pattern Stream)
6971#endif
7072import Streamly.Internal.Data.Unfold.Types (Unfold(..))
73+import Streamly.Internal.Data.Fold.Types (Fold(..))
7174
7275-------------------------------------------------------------------------------
7376-- Running unfolds
7477-------------------------------------------------------------------------------
7578
79+-- XXX flip the first two arguments to make it similar to unfold i.e. returning
80+-- a -> Stream m b?
81+--
7682-- | Convert an 'Unfold' into a 'Stream' by supplying it a seed.
7783--
7884{-# INLINE_NORMAL unfold #-}
@@ -88,6 +94,28 @@ unfold seed (Unfold ustep inject) = Stream step Nothing
8894 Skip s -> Skip (Just s)
8995 Stop -> Stop
9096
97+-- | Compose an 'Unfold' and a 'Fold'. Given an @Unfold m a b@ and a
98+-- @Fold m b c@, returns a monadic action @a -> m c@ representing the
99+-- application of the fold on the unfolded stream.
100+--
101+-- /Internal/
102+--
103+{-# INLINE_NORMAL fold #-}
104+fold :: Monad m => Unfold m a b -> Fold m b c -> a -> m c
105+fold (Unfold ustep inject) (Fold fstep initial extract) a =
106+ initial >>= \x -> inject a >>= go SPEC x
107+ where
108+ -- XXX !acc?
109+ {-# INLINE_LATE go #-}
110+ go !_ acc st = acc `seq` do
111+ r <- ustep st
112+ case r of
113+ Yield x s -> do
114+ acc' <- fstep acc x
115+ go SPEC acc' s
116+ Skip s -> go SPEC acc s
117+ Stop -> extract acc
118+
91119-------------------------------------------------------------------------------
92120-- Unfolds
93121-------------------------------------------------------------------------------