@@ -63,8 +63,6 @@ module Streamly.Streams.StreamD
6363 -- | Generate a monadic stream from a seed.
6464 , repeat
6565 , replicate
66− , replicateGen
67− , flatten
6866 , replicateM
6967 , fromIndices
7068 , fromIndicesM
@@ -137,6 +135,7 @@ module Streamly.Streams.StreamD
137135 -- ** Flattening nested streams
138136 , concatMapM
139137 , concatMap
138+ , concatMapU
140139
141140 -- ** Grouping
142141 , groupsOf
@@ -284,6 +283,7 @@ import Streamly.Memory.Array.Types (Array(..))
284283import Streamly.Fold.Types (Fold(..))
285284import Streamly.Pipe.Types (Pipe(..), PipeState(..))
286285import Streamly.SVar (MonadAsync, defState, adaptState)
286+import Streamly.Unfold.Types (Unfold(..))
287287
288288import Streamly.Streams.StreamD.Type
289289
@@ -386,14 +386,6 @@ replicateM n p = Stream step n
386386 x <- p
387387 return $ Yield x (i - 1)
388388
389−-- | For use with flatten
390−{-# INLINE replicateGen #-}
391−replicateGen :: Monad m => (a, Int) -> m (Step (a, Int) a)
392−replicateGen (x, i) = return $
393− if i <= 0
394− then Stop
395− else Yield x (x, (i - 1))
396−
397389{-# INLINE_NORMAL replicate #-}
398390replicate :: Monad m => Int -> a -> Stream m a
399391replicate n x = replicateM n (return x)
@@ -1702,6 +1694,40 @@ stripPrefix (Stream stepa ta) (Stream stepb tb) = go (ta, tb, Nothing)
17021694mapM_ :: Monad m => (a -> m b) -> Stream m a -> m ()
17031695mapM_ m = drain . mapM m
17041696
1697+-------------------------------------------------------------------------------
1698+-- Stream transformations using Unfolds
1699+-------------------------------------------------------------------------------
1700+
1701+-- | @concatMapU unfold stream@ uses @unfold@ to map the input stream elements
1702+-- to streams and then flattens the generated streams into a single output
1703+-- stream.
1704+
1705+-- This is like 'concatMap' but uses an unfold with an explicit state to
1706+-- generate the stream instead of a 'Stream' type generator. This allows better
1707+-- optimization via fusion. This can be many times more efficient than
1708+-- 'concatMap'.
1709+
1710+{-# INLINE_NORMAL concatMapU #-}
1711+concatMapU :: Monad m => Unfold m a b -> Stream m a -> Stream m b
1712+concatMapU (Unfold istep inject) (Stream ostep u) = Stream step (Left u)
1713+ where
1714+ {-# INLINE_LATE step #-}
1715+ step gst (Left t) = do
1716+ r <- ostep (adaptState gst) t
1717+ case r of
1718+ Yield a t' -> do
1719+ s <- inject a
1720+ s `seq` return (Skip (Right (s, t')))
1721+ Skip t' -> return $ Skip (Left t')
1722+ Stop -> return $ Stop
1723+
1724+ step _ (Right (s, t)) = do
1725+ r <- istep s
1726+ return $ case r of
1727+ Yield x s' -> Yield x (Right (s', t))
1728+ Skip s' -> Skip (Right (s', t))
1729+ Stop -> Skip (Left t)
1730+
17051731------------------------------------------------------------------------------
17061732-- Exceptions
17071733------------------------------------------------------------------------------