@@ -191,6 +191,7 @@ module Streamly.Internal.Prelude
191 -- ** Special Maps
191 -- ** Special Maps
195 , tapOffsetEvery
196 , tapOffsetEvery
196 , tapAsync
197 , tapAsync
@@ -252,8 +253,10 @@ module Streamly.Internal.Prelude
253 , insertBy
254 , insertBy
254 , intersperseM
255 , intersperseM
255 , intersperse
257 , intersperse
256 , intersperseSuffix
258 , intersperseSuffix
259+ , interspersePrefix_
257 , intersperseSuffixBySpan
260 , intersperseSuffixBySpan
258 -- , intersperseBySpan
261 -- , intersperseBySpan
259 -- , intersperseByIndices -- using an index function/stream
262 -- , intersperseByIndices -- using an index function/stream
@@ -263,6 +266,7 @@ module Streamly.Internal.Prelude
263 -- , intersperseByEvent
266 -- , intersperseByEvent
264 , interjectSuffix
267 , interjectSuffix
265 , delayPost
268 , delayPost
267 -- ** Indexing
271 -- ** Indexing
268 , indexed
272 , indexed
@@ -2458,13 +2462,21 @@ reverse' s = fromStreamD $ D.reverse' $ toStreamD s
2459-- intersperseM = intersperseBySpan 1
2463-- intersperseM = intersperseBySpan 1
2461−-- | Generate a stream by inserting the result of a monadic action between
2465+-- | Insert the result of an effectful action between consecutive elements of
2462−-- consecutive elements of the given stream. Note that the monadic action is
2466+-- the stream.
2463−-- performed after the stream action before which its result is inserted.
2469+-- >>> S.toList $ S.trace putChar $ S.intersperseM (putChar '.' >> return ',') $ S.fromList "hello"
2470+-- > h.,e.,l.,l.,o"h,e,l,l,o"
2473+-- After yielding the first element, for every next element the effectful
2474+-- action is evaluated /after/ generating the element, however, its result is
2475+-- yielded /before/ the element.
2466−-- > S.toList $ S.intersperseM (return ',') $ S.fromList "hello"
2478+-- > S.toList $ S.intersperseM (putChar '.' >> return ',') $ S.trace putChar $ S.fromList "hello"
2467−-- "h,e,l,l,o"
2479+-- he.l.l.o."h,e,l,l,o"
2470-- @since 0.5.0
2482-- @since 0.5.0
@@ -2472,8 +2484,27 @@ reverse' s = fromStreamD $ D.reverse' $ toStreamD s
2472intersperseM :: (IsStream t, MonadAsync m) => m a -> t m a -> t m a
2484intersperseM :: (IsStream t, MonadAsync m) => m a -> t m a -> t m a
2473intersperseM m = fromStreamS . S.intersperseM m . toStreamS
2485intersperseM m = fromStreamS . S.intersperseM m . toStreamS
2475−-- | Generate a stream by inserting a given element between consecutive
2487+-- | Insert a side effect between consecutive elements of the stream.
2490+-- >>> S.drain $ S.trace putChar $ S.intersperseM_ (putChar '.') $ S.fromList "hello"
2494+-- After yielding the first element, for every next element the effect
2495+-- is evaluated after generating the element but before yielding it.
2498+-- >>> S.drain $ S.intersperseM_ (putChar '.') $ S.trace putChar $ S.fromList "hello"
2503+{-# INLINE intersperseM_ #-}
2504+intersperseM_ :: (IsStream t, MonadAsync m) => m b -> t m a -> t m a
2505+intersperseM_ m = fromStreamD . D.intersperseM_ m . toStreamD
2476−-- elements of the given stream.
2507+-- | Insert a pure value between successive elements of a stream.
2479-- > S.toList $ S.intersperse ',' $ S.fromList "hello"
2510-- > S.toList $ S.intersperse ',' $ S.fromList "hello"
@@ -2485,16 +2516,19 @@ intersperseM m = fromStreamS . S.intersperseM m . toStreamS
2485intersperse :: (IsStream t, MonadAsync m) => a -> t m a -> t m a
2516intersperse :: (IsStream t, MonadAsync m) => a -> t m a -> t m a
2486intersperse a = fromStreamS . S.intersperse a . toStreamS
2517intersperse a = fromStreamS . S.intersperse a . toStreamS
2488−-- | Insert a monadic action after each element in the stream.
2519+-- | Insert an effectful action after each element of a stream.
2522+-- >>> S.toList $ S.trace putChar $ S.intersperseSuffix (putChar '.' >> return ',') $ S.fromList "hello"
2523+-- > h.,e.,l.,l.,o.,"h,e,l,l,o,"
2490-- /Internal/
2526-- /Internal/
2491{-# INLINE intersperseSuffix #-}
2527{-# INLINE intersperseSuffix #-}
2492intersperseSuffix :: (IsStream t, MonadAsync m) => m a -> t m a -> t m a
2528intersperseSuffix :: (IsStream t, MonadAsync m) => m a -> t m a -> t m a
2493intersperseSuffix m = fromStreamD . D.intersperseSuffix m . toStreamD
2529intersperseSuffix m = fromStreamD . D.intersperseSuffix m . toStreamD
2495−-- | Perform a side effect after each element of a stream. The output of the
2531+-- | Insert a side effect after each element of a stream.
2496−-- effectful action is discarded, therefore, the input stream remains
2500-- > S.mapM_ putChar $ S.intersperseSuffix_ (threadDelay 1000000) $ S.fromList "hello"
2534-- > S.mapM_ putChar $ S.intersperseSuffix_ (threadDelay 1000000) $ S.fromList "hello"
@@ -2504,9 +2538,28 @@ intersperseSuffix m = fromStreamD . D.intersperseSuffix m . toStreamD
2505{-# INLINE intersperseSuffix_ #-}
2539{-# INLINE intersperseSuffix_ #-}
2506intersperseSuffix_ :: (IsStream t, Monad m) => m b -> t m a -> t m a
2540intersperseSuffix_ :: (IsStream t, Monad m) => m b -> t m a -> t m a
2541+intersperseSuffix_ m = fromStreamD . D.intersperseSuffix_ m . toStreamD
2543+-- | Insert a side effect before each element of a stream.
2546+-- >>> S.toList $ S.trace putChar $ S.interspersePrefix_ (putChar '.' >> return ',') $ S.fromList "hello"
2547+-- > .h.e.l.l.o"hello"
2550+-- See also: 'trace_'
2556+{-# INLINE interspersePrefix_ #-}
2557+interspersePrefix_ :: (IsStream t, MonadAsync m) => m b -> t m a -> t m a
2507−intersperseSuffix_ m = Serial.mapM (\x -> void m >> return x)
2558+interspersePrefix_ m = mapM (\x -> void m >> return x)
2560+-- Note: delay must be serial.
2509−-- | Introduces a delay of specified seconds after each element of a stream.
2562+-- | Introduce a delay of specified seconds after each element of a stream.
2511-- /Internal/
2564-- /Internal/
@@ -2514,8 +2567,18 @@ intersperseSuffix_ m = Serial.mapM (\x -> void m >> return x)
2514delayPost :: (IsStream t, MonadIO m) => Double -> t m a -> t m a
2567delayPost :: (IsStream t, MonadIO m) => Double -> t m a -> t m a
2515delayPost n = intersperseSuffix_ $ liftIO $ threadDelay $ round $ n * 1000000
2568delayPost n = intersperseSuffix_ $ liftIO $ threadDelay $ round $ n * 1000000
2570+-- Note: delay must be serial, that's why 'trace_' is used.
2572+-- | Introduce a delay of specified seconds before each element of a stream.
2576+{-# INLINE delayPre #-}
2577+delayPre :: (IsStream t, MonadIO m) => Double -> t m a -> t m a
2578+delayPre n = trace_ $ liftIO $ threadDelay $ round $ n * 1000000
2517−-- | Like 'intersperseSuffix' but intersperses a monadic action into the input
2580+-- | Like 'intersperseSuffix' but intersperses an effectful action into the
2518−-- stream after every @n@ elements and after the last element.
2581+-- input stream after every @n@ elements and after the last element.
2521-- > S.toList $ S.intersperseSuffixBySpan 2 (return ',') $ S.fromList "hello"
2584-- > S.toList $ S.intersperseSuffixBySpan 2 (return ',') $ S.fromList "hello"
@@ -4094,6 +4157,22 @@ tapRate n f xs = D.fromStreamD $ D.tapRate n f $ D.toStreamD xs
4094trace :: (IsStream t, MonadAsync m) => (a -> m b) -> t m a -> t m a
4157trace :: (IsStream t, MonadAsync m) => (a -> m b) -> t m a -> t m a
4095trace f = mapM (\x -> void (f x) >> return x)
4158trace f = mapM (\x -> void (f x) >> return x)
4160+-- | Perform a side effect before yielding each element of the stream and
4161+-- discard the results.
4164+-- > S.drain $ S.trace_ (print "got here") (S.enumerateFromTo 1 2)
4169+-- See also: 'trace', 'interspersePrefix_'
4172+{-# INLINE trace_ #-}
4173+trace_ :: (IsStream t, Monad m) => m b -> t m a -> t m a
4174+trace_ eff = Serial.mapM (\x -> eff >> return x)
4097------------------------------------------------------------------------------
4176------------------------------------------------------------------------------
4098-- Windowed classification
4177-- Windowed classification
4099------------------------------------------------------------------------------
4178------------------------------------------------------------------------------