on master help sign in
Add intersperse to Streamly.Prelude.

- Also adds benchmarking code for intersperse.

commitd4bef2e352fd5f0b47c7685595a2d193bbdadbd9 authorPranay Sashank <pranaysashank@gmail.com> dateMon 10 Jun 2019, 14:15 (7 years ago) parent254f27f
10 files changed+75−5
Changelog.md+2 benchmark/BaseStreams.hs+6 benchmark/Linear.hs+2 benchmark/LinearOps.hs+3−1 benchmark/StreamDOps.hs+3−1 benchmark/StreamKOps.hs+4−1 src/Streamly/Prelude.hs+15−1 src/Streamly/Streams/StreamD.hs+34 src/Streamly/Streams/StreamK.hs+5 src/Streamly/String.hs+1−1
Changelog.md+2
@@ -66,6 +66,8 @@ example, concat streams concurrently using this.
6666 * `reverse'` a several times faster reverse using Storable instance
6767 * `intersperseByTime` intersperse a mondadic action in a stream
6868 periodically
69+ * `intersperse` intersperse an element in between consecutive elements in
70+ stream
6971
7072### Deprecations
7173
benchmark/BaseStreams.hs+6
@@ -101,6 +101,8 @@ main =
101101 , benchIO "mapMaybeM" (D.mapMaybeM 1) D.sourceUnfoldrM
102102 , benchIO "concatMap" (D.concatMap 1) (D.sourceUnfoldrMN D.value2)
103103 , benchIO "concatMapPure" (D.concatMap 1) (D.sourceUnfoldrN D.value2)
104+ , benchIO "intersperse" (D.intersperse 1) (D.sourceUnfoldrMN D.value2)
105+ , benchIO "interspersePure" (D.intersperse 1) (D.sourceUnfoldrN D.value2)
104106 -- , benchIO "foldrS" (D.foldrS 1) D.sourceUnfoldrM
105107 -- This has horrible performance, never finishes
106108 -- , benchIO "foldlS" (D.foldlS 1) D.sourceUnfoldrM
@@ -113,6 +115,7 @@ main =
113115 , benchIO "mapMaybe" (D.mapMaybe 4) D.sourceUnfoldrM
114116 , benchIO "mapMaybeM" (D.mapMaybeM 4) D.sourceUnfoldrM
115117 -- , benchIO "concatMap" (D.concatMap 4) (D.sourceUnfoldrMN D.value16)
118+ , benchIO "intersperse" (D.intersperse 4) (D.sourceUnfoldrMN D.value16)
116119 ]
117120 , bgroup "filtering"
118121 [ benchIO "filter-even" (D.filterEven 1) D.sourceUnfoldrM
@@ -242,6 +245,8 @@ main =
242245 -- , benchIOSrcK "concatMap" K.concatMap
243246 , benchIO "concatMap" (K.concatMap 1) (K.sourceUnfoldrMN K.value2)
244247 , benchIO "concatMapPure" (K.concatMap 1) (K.sourceUnfoldrN K.value2)
248+ , benchIO "intersperse" (K.intersperse 1) (K.sourceUnfoldrMN K.value2)
249+ , benchIO "interspersePure" (K.intersperse 1) (K.sourceUnfoldrN K.value2)
245250 , benchIO "foldlS" (K.foldlS 1) K.sourceUnfoldrM
246251 ]
247252 , bgroup "transformationX4"
@@ -251,6 +256,7 @@ main =
251256 , benchIO "mapM" (K.mapM 4) K.sourceUnfoldrM
252257 , benchIO "mapMSerial" (K.mapMSerial 4) K.sourceUnfoldrM
253258 -- , benchIO "concatMap" (K.concatMap 4) (K.sourceUnfoldrMN K.value16)
259+ , benchIO "intersperse" (K.intersperse 4) (K.sourceUnfoldrMN K.value16)
254260 ]
255261 , bgroup "filtering"
256262 [ benchIO "filter-even" (K.filterEven 1) K.sourceUnfoldrM
benchmark/Linear.hs+2
@@ -300,6 +300,7 @@ main =
300300 --, benchIOSink "dropWhileM-true" (Ops.dropWhileMTrue 1)
301301 , benchIOSink "dropWhile-false" (Ops.dropWhileFalse 1)
302302 , benchIOSink "deleteBy" (Ops.deleteBy 1)
303+ , benchIOSink "intersperse" (Ops.intersperse 1)
303304 , benchIOSink "insertBy" (Ops.insertBy 1)
304305 ]
305306 , bgroup "filteringX4"
@@ -315,6 +316,7 @@ main =
315316 --, benchIOSink "dropWhileM-true" (Ops.dropWhileMTrue 4)
316317 , benchIOSink "dropWhile-false" (Ops.dropWhileFalse 4)
317318 , benchIOSink "deleteBy" (Ops.deleteBy 4)
319+ , benchIOSink "intersperse" (Ops.intersperse 4)
318320 , benchIOSink "insertBy" (Ops.insertBy 4)
319321 ]
320322 , bgroup "multi-stream"
benchmark/LinearOps.hs+3−1
@@ -357,7 +357,8 @@ scan, scanl1', map, fmap, mapMaybe, filterEven, filterAllOut,
357357 => Int -> Stream m Int -> m ()
358358
359359{-# INLINE mapMaybeM #-}
360−mapMaybeM :: S.MonadAsync m => Int -> Stream m Int -> m ()
360+{-# INLINE intersperse #-}
361+mapMaybeM, intersperse :: S.MonadAsync m => Int -> Stream m Int -> m ()
361362
362363{-# INLINE mapM #-}
363364{-# INLINE transformMapM #-}
@@ -415,6 +416,7 @@ dropWhileMTrue n = composeN n $ S.dropWhileM (return . (<= maxValue))
415416dropWhileFalse n = composeN n $ S.dropWhile (> maxValue)
416417findIndices n = composeN n $ S.findIndices (== maxValue)
417418elemIndices n = composeN n $ S.elemIndices maxValue
419+intersperse n = composeN n $ S.intersperse maxValue
418420insertBy n = composeN n $ S.insertBy compare maxValue
419421deleteBy n = composeN n $ S.deleteBy (>=) maxValue
420422reverse n = composeN n $ S.reverse
benchmark/StreamDOps.hs+3−1
@@ -177,10 +177,11 @@ composeN n f =
177177{-# INLINE foldrS #-}
178178{-# INLINE foldlS #-}
179179{-# INLINE concatMap #-}
180+{-# INLINE intersperse #-}
180181scan, map, fmap, mapM, mapMaybe, mapMaybeM, filterEven, filterAllOut,
181182 filterAllIn, takeOne, takeAll, takeWhileTrue, takeWhileMTrue, dropOne,
182183 dropAll, dropWhileTrue, dropWhileMTrue, dropWhileFalse, foldrS, foldlS,
183− concatMap
184+ concatMap, intersperse
184185 :: Monad m
185186 => Int -> Stream m Int -> m ()
186187
@@ -207,6 +208,7 @@ dropWhileFalse n = composeN n $ S.dropWhile (> maxValue)
207208foldrS n = composeN n $ S.foldrS S.cons S.nil
208209foldlS n = composeN n $ S.foldlS (flip S.cons) S.nil
209210concatMap n = composeN n $ (\s -> S.concatMap (\_ -> s) s)
211+intersperse n = composeN n $ S.intersperse maxValue
210212
211213-------------------------------------------------------------------------------
212214-- Iteration
benchmark/StreamKOps.hs+4−1
@@ -205,7 +205,9 @@ scan, map, fmap, filterEven, filterAllOut,
205205
206206{-# INLINE mapM #-}
207207{-# INLINE mapMSerial #-}
208−mapM, mapMSerial :: S.MonadAsync m => Int -> Stream m Int -> m ()
208+{-# INLINE intersperse #-}
209+mapM, mapMSerial, intersperse
210+ :: S.MonadAsync m => Int -> Stream m Int -> m ()
209211
210212scan n = composeN n $ S.scanl' (+) 0
211213map n = composeN n $ P.fmap (+1)
@@ -224,6 +226,7 @@ dropWhileTrue n = composeN n $ S.dropWhile (<= maxValue)
224226dropWhileFalse n = composeN n $ S.dropWhile (<= 1)
225227foldlS n = composeN n $ S.foldlS (flip S.cons) S.nil
226228concatMap n = composeN n $ (\s -> S.concatMap (\_ -> s) s)
229+intersperse n = composeN n $ S.intersperse maxValue
227230
228231-------------------------------------------------------------------------------
229232-- Iteration
src/Streamly/Prelude.hs+15−1
@@ -369,6 +369,7 @@ module Streamly.Prelude
369369
370370 , insertBy
371371 , intersperseM
372+ , intersperse
372373 -- , intersperseBySpan
373374 , intersperseByTime
374375
@@ -1933,7 +1934,20 @@ reverse' s = fromStreamD $ D.reverse' $ toStreamD s
19331934-- @since 0.5.0
19341935{-# INLINE intersperseM #-}
19351936intersperseM :: (IsStream t, MonadAsync m) => m a -> t m a -> t m a
1936−intersperseM = K.intersperseM
1937+intersperseM m = fromStreamS . S.intersperseM m . toStreamS
1938+
1939+-- | Generate a stream by inserting a given element between consecutive
1940+-- elements of the given stream.
1941+--
1942+-- @
1943+-- > S.toList $ S.intersperse ',' $ S.fromList "hello"
1944+-- "h,e,l,l,o"
1945+-- @
1946+--
1947+-- @since 0.7.0
1948+{-# INLINE intersperse #-}
1949+intersperse :: (IsStream t, MonadAsync m) => a -> t m a -> t m a
1950+intersperse a = fromStreamS . S.intersperse a . toStreamS
19371951
19381952{-
19391953-- | Intersperse a monadic action into the input stream after every @n@
src/Streamly/Streams/StreamD.hs+34
@@ -203,6 +203,8 @@ module Streamly.Streams.StreamD
203203 , sequence
204204
205205 -- * Inserting
206+ , intersperseM
207+ , intersperse
206208 , insertBy
207209
208210 -- * Deleting
@@ -2174,6 +2176,38 @@ sequence (Stream step state) = Stream step' state
21742176-- Inserting
21752177------------------------------------------------------------------------------
21762178
2179+data LoopState x s = FirstYield s
2180+ | InterspersingYield s
2181+ | YieldAndCarry x s
2182+
2183+{-# INLINE_NORMAL intersperseM #-}
2184+intersperseM :: Monad m => m a -> Stream m a -> Stream m a
2185+intersperseM m (Stream step state) = Stream step' (FirstYield state)
2186+ where
2187+ {-# INLINE_LATE step' #-}
2188+ step' gst (FirstYield st) = do
2189+ r <- step gst st
2190+ return $
2191+ case r of
2192+ Yield x s -> Skip (YieldAndCarry x s)
2193+ Skip s -> Skip (FirstYield s)
2194+ Stop -> Stop
2195+
2196+ step' gst (InterspersingYield st) = do
2197+ r <- step gst st
2198+ case r of
2199+ Yield x s -> do
2200+ a <- m
2201+ return $ Yield a (YieldAndCarry x s)
2202+ Skip s -> return $ Skip $ InterspersingYield s
2203+ Stop -> return Stop
2204+
2205+ step' _ (YieldAndCarry x st) = return $ Yield x (InterspersingYield st)
2206+
2207+{-# INLINE intersperse #-}
2208+intersperse :: Monad m => a -> Stream m a -> Stream m a
2209+intersperse a = intersperseM (return a)
2210+
21772211{-# INLINE_NORMAL insertBy #-}
21782212insertBy :: Monad m => (a -> a -> Ordering) -> a -> Stream m a -> Stream m a
21792213insertBy cmp a (Stream step state) = Stream step' (state, False, Nothing)
src/Streamly/Streams/StreamK.hs+5
@@ -143,6 +143,7 @@ module Streamly.Streams.StreamK
143143
144144 -- ** Inserting
145145 , intersperseM
146+ , intersperse
146147 , insertBy
147148
148149 -- ** Deleting
@@ -826,6 +827,10 @@ intersperseM a m = prependingStart m
826827 yieldk i x = foldStreamShared st yld sng stp $ a |: return i |: go x
827828 in foldStream st yieldk single stp m2
828829
830+{-# INLINE intersperse #-}
831+intersperse :: (IsStream t, MonadAsync m) => a -> t m a -> t m a
832+intersperse a = intersperseM (return a)
833+
829834{-# INLINE insertBy #-}
830835insertBy :: IsStream t => (a -> a -> Ordering) -> a -> t m a -> t m a
831836insertBy cmp x m = go m
src/Streamly/String.hs+1−1
@@ -191,4 +191,4 @@ unlines = D.fromStreamD . A.unlines . D.toStreamD
191191
192192{-# INLINE unwords #-}
193193unwords :: (MonadAsync m, IsStream t) => t m (Array Char) -> t m Char
194−unwords = A.flattenArrays . (S.intersperseM (return $ A.fromList " "))
194+unwords = A.flattenArrays . (S.intersperse (A.fromList " "))