@@ -205,6 +205,8 @@ module Streamly.Internal.Prelude
205 -- ** Mapping Filters
205 -- ** Mapping Filters
206 , mapMaybe
206 , mapMaybe
207 , mapMaybeM
207 , mapMaybeM
209 -- ** Scanning Filters
211 -- ** Scanning Filters
210 , findIndices
212 , findIndices
@@ -219,6 +221,7 @@ module Streamly.Internal.Prelude
219 , intersperseSuffixBySpan
221 , intersperseSuffixBySpan
220 -- , intersperseBySpan
222 -- , intersperseBySpan
221 , interjectSuffix
223 , interjectSuffix
223 -- ** Reordering
226 -- ** Reordering
224 , reverse
227 , reverse
@@ -344,6 +347,7 @@ module Streamly.Internal.Prelude
345 , tapAsync
348 , tapAsync
346 , tapRate
349 , tapRate
348 -- * Windowed Classification
352 -- * Windowed Classification
@@ -467,7 +471,7 @@ import Streamly.Internal.Data.Pipe.Types (Pipe (..))
467import Streamly.Internal.Data.Time.Units
471import Streamly.Internal.Data.Time.Units
468 (AbsTime, MilliSecond64(..), addToAbsTime, diffAbsTime, toRelTime,
472 (AbsTime, MilliSecond64(..), addToAbsTime, diffAbsTime, toRelTime,
469 toAbsTime)
473 toAbsTime)
470−import Streamly.Internal.Mutable.Prim.Var (MonadMut, Prim, Var)
474+import Streamly.Internal.Mutable.Prim.Var (Prim, Var)
472import Streamly.Internal.Data.Strict
476import Streamly.Internal.Data.Strict
@@ -879,7 +883,7 @@ fromHandle h = go
879-- /Internal/
883-- /Internal/
881{-# INLINE fromPrimVar #-}
885{-# INLINE fromPrimVar #-}
882−fromPrimVar :: (IsStream t, MonadMut m, Prim a) => Var m a -> t m a
886+fromPrimVar :: (IsStream t, MonadIO m, Prim a) => Var IO a -> t m a
883fromPrimVar = fromStreamD . D.fromPrimVar
887fromPrimVar = fromStreamD . D.fromPrimVar
885------------------------------------------------------------------------------
889------------------------------------------------------------------------------
@@ -1786,6 +1790,27 @@ scan (Fold step begin done) = P.scanlMx' step begin done
1786postscan :: (IsStream t, Monad m) => Fold m a b -> t m a -> t m b
1790postscan :: (IsStream t, Monad m) => Fold m a b -> t m a -> t m b
1787postscan (Fold step begin done) = P.postscanlMx' step begin done
1791postscan (Fold step begin done) = P.postscanlMx' step begin done
1793+------------------------------------------------------------------------------
1794+-- Stateful Transformations
1795+------------------------------------------------------------------------------
1797+-- | Apply a function on every two successive elements of a stream. If the
1798+-- stream consists of a single element the output is an empty stream.
1802+{-# INLINE rollingMap #-}
1803+rollingMap :: (IsStream t, Monad m) => (a -> a -> b) -> t m a -> t m b
1804+rollingMap f m = fromStreamD $ D.rollingMap f $ toStreamD m
1806+-- | Like 'rollingMap' but with an effectful map function.
1810+{-# INLINE rollingMapM #-}
1811+rollingMapM :: (IsStream t, Monad m) => (a -> a -> m b) -> t m a -> t m b
1812+rollingMapM f m = fromStreamD $ D.rollingMapM f $ toStreamD m
1789------------------------------------------------------------------------------
1814------------------------------------------------------------------------------
1790-- Transformation by Filtering
1815-- Transformation by Filtering
1791------------------------------------------------------------------------------
1816------------------------------------------------------------------------------
@@ -2004,10 +2029,9 @@ reverse' s = fromStreamD $ D.reverse' $ toStreamD s
2005-- intersperseM = intersperseBySpan 1
2030-- intersperseM = intersperseBySpan 1
2007−-- | Generate a stream by performing a monadic action between consecutive
2032+-- | Generate a stream by inserting the result of a monadic action between
2008−-- elements of the given stream.
2033+-- consecutive elements of the given stream. Note that the monadic action is
2009−--
2034+-- performed after the stream action before which its result is inserted.
2010−-- /Concurrent (do not use with 'parallely' on infinite streams)/
2013-- > S.toList $ S.intersperseM (return ',') $ S.fromList "hello"
2037-- > S.toList $ S.intersperseM (return ',') $ S.fromList "hello"
@@ -2039,6 +2063,28 @@ intersperse a = fromStreamS . S.intersperse a . toStreamS
2039intersperseSuffix :: (IsStream t, MonadAsync m) => m a -> t m a -> t m a
2063intersperseSuffix :: (IsStream t, MonadAsync m) => m a -> t m a -> t m a
2040intersperseSuffix m = fromStreamD . D.intersperseSuffix m . toStreamD
2064intersperseSuffix m = fromStreamD . D.intersperseSuffix m . toStreamD
2066+-- | Perform a side effect after each element of a stream. The output of the
2067+-- effectful action is discarded, therefore, the input stream remains
2071+-- > S.mapM_ putChar $ S.intersperseSuffix_ (threadDelay 1000000) $ S.fromList "hello"
2076+{-# INLINE intersperseSuffix_ #-}
2077+intersperseSuffix_ :: (IsStream t, Monad m) => m b -> t m a -> t m a
2078+intersperseSuffix_ m = Serial.mapM (\x -> void m >> return x)
2080+-- | Introduces a delay of specified seconds after each element of a stream.
2084+{-# INLINE delayPost #-}
2085+delayPost :: (IsStream t, MonadIO m) => Double -> t m a -> t m a
2086+delayPost n = intersperseSuffix_ $ liftIO $ threadDelay $ round $ n * 1000000
2042-- | Like 'intersperseSuffix' but intersperses a monadic action into the input
2088-- | Like 'intersperseSuffix' but intersperses a monadic action into the input
2043-- stream after every @n@ elements and after the last element.
2089-- stream after every @n@ elements and after the last element.
@@ -3614,6 +3660,30 @@ tap f xs = D.fromStreamD $ D.tap f (D.toStreamD xs)
3614tapAsync :: (IsStream t, MonadAsync m) => FL.Fold m a b -> t m a -> t m a
3660tapAsync :: (IsStream t, MonadAsync m) => FL.Fold m a b -> t m a -> t m a
3615tapAsync f xs = D.fromStreamD $ D.tapAsync f (D.toStreamD xs)
3661tapAsync f xs = D.fromStreamD $ D.tapAsync f (D.toStreamD xs)
3663+-- | Maintain the count of elements flowing in the stream and poll the count
3664+-- asynchronously from another thread. The count stream is transformed using
3665+-- the supplied transform and then folded using the supplied fold. The thread
3666+-- is automatically cleaned up if the stream stops or aborts due to exception.
3668+-- For example, to print the count of elements processed every second:
3671+-- > S.drain $ S.pollCounts (rollingMap (-) . delayPost 1) (FL.drainBy print)
3672+-- $ S.enumerateFrom 0
3675+{-# INLINE pollCounts #-}
3677+ (IsStream t, MonadAsync m)
3678+ => (t m Int -> t m Int)
3682+pollCounts transf f xs =
3684+ $ D.pollCounts (D.toStreamD . transf . D.fromStreamD) f
3617-- | Calls the supplied function with the number of elements consumed
3687-- | Calls the supplied function with the number of elements consumed
3618-- every @n@ seconds. The given function is run in a separate thread
3688-- every @n@ seconds. The given function is run in a separate thread
3619-- until the end of the stream. In case there is an exception in the
3689-- until the end of the stream. In case there is an exception in the