on master help sign in
Add unfoldWords/interpose/intercalate etc.
a9f3f9aHarendra Kumar
benchmark/FileIO.hs+20−8
@@ -201,20 +201,32 @@ main = do
201 Handles inh _ <- readIORef href
201 Handles inh _ <- readIORef href
202 BFS.chunksOf 1000 inh
202 BFS.chunksOf 1000 inh
203 ]
203 ]
204− , bgroup "group-ungroup"
204+ , bgroup "group-ungroup-stream"
205− [ mkBench "lines-unlines" href $ do
205+ [ mkBench "lines-unlines-[Char]" href $ do
206 Handles inh outh <- readIORef href
206 Handles inh outh <- readIORef href
207 BFS.linesUnlinesCopy inh outh
207 BFS.linesUnlinesCopy inh outh
208− , mkBench "lines-unlines-arrays" href $ do
208+ , mkBench "lines-unlines-Word8Array" href $ do
209 Handles inh outh <- readIORef href
209 Handles inh outh <- readIORef href
210− BFA.linesUnlinesCopy inh outh
210+ BFS.linesUnlinesArrayWord8Copy inh outh
211− , mkBench "words-unwords" href $ do
211+ , mkBench "lines-unlines-CharArray" href $ do
212 Handles inh outh <- readIORef href
212 Handles inh outh <- readIORef href
213− BFS.wordsUnwordsCopy inh outh
213+ BFS.linesUnlinesArrayCharCopy inh outh
214− , mkBench "words-unwords-word8" href $ do
214+ , mkBench "words-unwords-[Word8]" href $ do
215 Handles inh outh <- readIORef href
215 Handles inh outh <- readIORef href
216 BFS.wordsUnwordsCopyWord8 inh outh
216 BFS.wordsUnwordsCopyWord8 inh outh
217− , mkBench "words-unwords-arrays" href $ do
217+ , mkBench "words-unwords-[Char]" href $ do
218+ Handles inh outh <- readIORef href
219+ BFS.wordsUnwordsCopy inh outh
220+ , mkBench "words-unwords-CharArray" href $ do
221+ Handles inh outh <- readIORef href
222+ BFS.wordsUnwordsCharArrayCopy inh outh
223+ ]
224+
225+ , bgroup "group-ungroup-array-stream"
226+ [ mkBench "lines-unlines-Word8Array" href $ do
227+ Handles inh outh <- readIORef href
228+ BFA.linesUnlinesCopy inh outh
229+ , mkBench "words-unwords-Word8Array" href $ do
218 Handles inh outh <- readIORef href
230 Handles inh outh <- readIORef href
219 BFA.wordsUnwordsCopy inh outh
231 BFA.wordsUnwordsCopy inh outh
220 ]
232 ]
src/Streamly/Benchmark/FileIO/Array.hs+5−6
@@ -48,7 +48,6 @@ import qualified Streamly.Prelude as S
48import qualified Streamly.Data.String as SS
48import qualified Streamly.Data.String as SS
49
49
50import qualified Streamly.Internal.FileSystem.Handle as IFH
50import qualified Streamly.Internal.FileSystem.Handle as IFH
51−import qualified Streamly.Internal.Prelude as Internal
52import qualified Streamly.Internal.Memory.Array as IA
51import qualified Streamly.Internal.Memory.Array as IA
53import qualified Streamly.Internal.Memory.ArrayStream as AS
52import qualified Streamly.Internal.Memory.ArrayStream as AS
54import qualified Streamly.Internal.Data.Unfold as IUF
53import qualified Streamly.Internal.Data.Unfold as IUF
@@ -186,8 +185,8 @@ inspect $ 'copy `hasNoType` ''Step
186{-# INLINE linesUnlinesCopy #-}
185{-# INLINE linesUnlinesCopy #-}
187linesUnlinesCopy :: Handle -> Handle -> IO ()
186linesUnlinesCopy :: Handle -> Handle -> IO ()
188linesUnlinesCopy inh outh =
187linesUnlinesCopy inh outh =
189− S.fold (IFH.writeArraysInChunksOf (1024*1024) outh)
188+ S.fold (IFH.writeInChunksOf (1024*1024) outh)
190− $ Internal.insertAfterEach (return $ A.fromList [10])
189+ $ AS.interposeSuffix 10
191 $ AS.splitOnSuffix 10
190 $ AS.splitOnSuffix 10
192 $ IFH.toStreamArraysOf (1024*1024) inh
191 $ IFH.toStreamArraysOf (1024*1024) inh
193
192
@@ -200,9 +199,9 @@ inspect $ hasNoTypeClassesExcept 'linesUnlinesCopy [''Storable]
200{-# INLINE wordsUnwordsCopy #-}
199{-# INLINE wordsUnwordsCopy #-}
201wordsUnwordsCopy :: Handle -> Handle -> IO ()
200wordsUnwordsCopy :: Handle -> Handle -> IO ()
202wordsUnwordsCopy inh outh =
201wordsUnwordsCopy inh outh =
203− S.fold (IFH.writeArraysInChunksOf (1024*1024) outh)
202+ S.fold (IFH.writeInChunksOf (1024*1024) outh)
204− $ S.intersperse (A.fromList [32])
203+ $ AS.interpose 32
205− -- XXX use a word splitting combinator
204+ -- XXX this is not correct word splitting combinator
206 $ AS.splitOn 32
205 $ AS.splitOn 32
207 $ IFH.toStreamArraysOf (1024*1024) inh
206 $ IFH.toStreamArraysOf (1024*1024) inh
208
207
src/Streamly/Benchmark/FileIO/Stream.hs+56−16
@@ -40,8 +40,12 @@ module Streamly.Benchmark.FileIO.Stream
40 , catFinallyStream
40 , catFinallyStream
41 , copy
41 , copy
42 , linesUnlinesCopy
42 , linesUnlinesCopy
43+ , linesUnlinesArrayWord8Copy
44+ , linesUnlinesArrayCharCopy
45+ -- , linesUnlinesArrayUtf8Copy
43 , wordsUnwordsCopyWord8
46 , wordsUnwordsCopyWord8
44 , wordsUnwordsCopy
47 , wordsUnwordsCopy
48+ , wordsUnwordsCharArrayCopy
45 , readWord8
49 , readWord8
46 , decodeChar8
50 , decodeChar8
47 , copyCodecChar8
51 , copyCodecChar8
@@ -68,9 +72,11 @@ import Prelude hiding (last, length)
68import qualified Streamly.FileSystem.Handle as FH
72import qualified Streamly.FileSystem.Handle as FH
69import qualified Streamly.Internal.FileSystem.Handle as IFH
73import qualified Streamly.Internal.FileSystem.Handle as IFH
70import qualified Streamly.Memory.Array as A
74import qualified Streamly.Memory.Array as A
75+-- import qualified Streamly.Internal.Memory.Array as IA
71import qualified Streamly.Internal.Memory.Array.Types as AT
76import qualified Streamly.Internal.Memory.Array.Types as AT
72import qualified Streamly.Prelude as S
77import qualified Streamly.Prelude as S
73import qualified Streamly.Data.Fold as FL
78import qualified Streamly.Data.Fold as FL
79+-- import qualified Streamly.Internal.Data.Fold as IFL
74import qualified Streamly.Data.String as SS
80import qualified Streamly.Data.String as SS
75import qualified Streamly.Internal.Data.Unfold as IUF
81import qualified Streamly.Internal.Data.Unfold as IUF
76import qualified Streamly.Internal.Prelude as IP
82import qualified Streamly.Internal.Prelude as IP
@@ -400,11 +406,29 @@ inspect $ 'chunksOfD `hasNoType` ''AT.FlattenState
400inspect $ 'chunksOfD `hasNoType` ''D.ConcatMapUState
406inspect $ 'chunksOfD `hasNoType` ''D.ConcatMapUState
401#endif
407#endif
402
408
403−-- XXX splitSuffixOn requires -funfolding-use-threshold=150 for better fusion
404−-- | Lines and unlines
405{-# INLINE linesUnlinesCopy #-}
409{-# INLINE linesUnlinesCopy #-}
406linesUnlinesCopy :: Handle -> Handle -> IO ()
410linesUnlinesCopy :: Handle -> Handle -> IO ()
407linesUnlinesCopy inh outh =
411linesUnlinesCopy inh outh =
412+ S.fold (FH.write outh)
413+ $ SS.encodeChar8
414+ $ SS.unfoldLines IUF.fromList
415+ $ S.splitOnSuffix (== '\n') FL.toList
416+ $ SS.decodeChar8
417+ $ S.unfold FH.read inh
418+
419+{-# INLINE linesUnlinesArrayWord8Copy #-}
420+linesUnlinesArrayWord8Copy :: Handle -> Handle -> IO ()
421+linesUnlinesArrayWord8Copy inh outh =
422+ S.fold (FH.write outh)
423+ $ IP.interposeSuffix 10 A.read
424+ $ S.splitOnSuffix (== 10) A.write
425+ $ S.unfold FH.read inh
426+
427+-- XXX splitSuffixOn requires -funfolding-use-threshold=150 for better fusion
428+-- | Lines and unlines
429+{-# INLINE linesUnlinesArrayCharCopy #-}
430+linesUnlinesArrayCharCopy :: Handle -> Handle -> IO ()
431+linesUnlinesArrayCharCopy inh outh =
408 S.fold (FH.write outh)
432 S.fold (FH.write outh)
409 $ SS.encodeChar8
433 $ SS.encodeChar8
410 $ SS.unlines
434 $ SS.unlines
@@ -413,12 +437,26 @@ linesUnlinesCopy inh outh =
413 $ S.unfold FH.read inh
437 $ S.unfold FH.read inh
414
438
415#ifdef INSPECTION
439#ifdef INSPECTION
416−inspect $ hasNoTypeClassesExcept 'linesUnlinesCopy [''Storable]
440+inspect $ hasNoTypeClassesExcept 'linesUnlinesArrayCharCopy [''Storable]
417−-- inspect $ 'linesUnlinesCopy `hasNoType` ''Step
441+-- inspect $ 'linesUnlinesArrayCharCopy `hasNoType` ''Step
418−-- inspect $ 'linesUnlinesCopy `hasNoType` ''AT.FlattenState
442+-- inspect $ 'linesUnlinesArrayCharCopy `hasNoType` ''AT.FlattenState
419−-- inspect $ 'linesUnlinesCopy `hasNoType` ''D.ConcatMapUState
443+-- inspect $ 'linesUnlinesArrayCharCopy `hasNoType` ''D.ConcatMapUState
420#endif
444#endif
421
445
446+-- XXX to write this we need to be able to map decodeUtf8 on the A.read fold.
447+-- For that we have to write decodeUtf8 as a Pipe.
448+{-
449+{-# INLINE linesUnlinesArrayUtf8Copy #-}
450+linesUnlinesArrayUtf8Copy :: Handle -> Handle -> IO ()
451+linesUnlinesArrayUtf8Copy inh outh =
452+ S.fold (FH.write outh)
453+ $ SS.encodeChar8
454+ $ IP.intercalate (A.fromList [10]) (pipe SS.decodeUtf8P A.read)
455+ $ S.splitOnSuffix (== '\n') (IFL.lmap SS.encodeUtf8 A.write)
456+ $ SS.decodeChar8
457+ $ S.unfold FH.read inh
458+-}
459+
422foreign import ccall unsafe "u_iswspace"
460foreign import ccall unsafe "u_iswspace"
423 iswspace :: Int -> Int
461 iswspace :: Int -> Int
424
462
@@ -446,8 +484,7 @@ isSp = isSpace . chr . fromIntegral
446wordsUnwordsCopyWord8 :: Handle -> Handle -> IO ()
484wordsUnwordsCopyWord8 :: Handle -> Handle -> IO ()
447wordsUnwordsCopyWord8 inh outh =
485wordsUnwordsCopyWord8 inh outh =
448 S.fold (FH.write outh)
486 S.fold (FH.write outh)
449− $ S.concatUnfold IUF.fromList
487+ $ IP.interposeSuffix 32 IUF.fromList
450− $ S.intersperse [32]
451 $ S.wordsBy isSp FL.toList
488 $ S.wordsBy isSp FL.toList
452 $ S.unfold FH.read inh
489 $ S.unfold FH.read inh
453
490
@@ -463,14 +500,7 @@ wordsUnwordsCopy :: Handle -> Handle -> IO ()
463wordsUnwordsCopy inh outh =
500wordsUnwordsCopy inh outh =
464 S.fold (FH.write outh)
501 S.fold (FH.write outh)
465 $ SS.encodeChar8
502 $ SS.encodeChar8
466− $ S.concatUnfold IUF.fromList
503+ $ SS.unfoldWords IUF.fromList
467− $ S.intersperse " "
468− -- Array allocation is too expensive for such small strings. So just use
469− -- lists instead.
470− --
471− -- -- $ SS.unwords
472− -- -- $ SS.words
473− --
474 -- XXX This pipeline does not fuse with wordsBy but fuses with splitOn
504 -- XXX This pipeline does not fuse with wordsBy but fuses with splitOn
475 -- with -funfolding-use-threshold=300. With wordsBy it does not fuse
505 -- with -funfolding-use-threshold=300. With wordsBy it does not fuse
476 -- even with high limits for inlining and spec-constr ghc options. With
506 -- even with high limits for inlining and spec-constr ghc options. With
@@ -490,6 +520,16 @@ wordsUnwordsCopy inh outh =
490-- inspect $ 'wordsUnwordsCopy `hasNoType` ''D.ConcatMapUState
520-- inspect $ 'wordsUnwordsCopy `hasNoType` ''D.ConcatMapUState
491#endif
521#endif
492
522
523+{-# INLINE wordsUnwordsCharArrayCopy #-}
524+wordsUnwordsCharArrayCopy :: Handle -> Handle -> IO ()
525+wordsUnwordsCharArrayCopy inh outh =
526+ S.fold (FH.write outh)
527+ $ SS.encodeChar8
528+ $ SS.unwords
529+ $ SS.words
530+ $ SS.decodeChar8
531+ $ S.unfold FH.read inh
532+
493lf :: Word8
533lf :: Word8
494lf = fromIntegral (ord '\n')
534lf = fromIntegral (ord '\n')
495
535
src/Streamly/Data/String.hs+12−8
@@ -74,6 +74,7 @@ module Streamly.Data.String
74 , foldLines
74 , foldLines
75 , foldWords
75 , foldWords
76 , unfoldLines
76 , unfoldLines
77+ , unfoldWords
77
78
78 -- * Streams of Strings
79 -- * Streams of Strings
79 , lines
80 , lines
@@ -95,9 +96,7 @@ import Streamly.Internal.Data.Unfold (Unfold)
95
96
96import qualified Streamly.Internal.Prelude as S
97import qualified Streamly.Internal.Prelude as S
97import qualified Streamly.Memory.Array as A
98import qualified Streamly.Memory.Array as A
98−import qualified Streamly.Internal.Memory.ArrayStream as AS
99import qualified Streamly.Streams.StreamD as D
99import qualified Streamly.Streams.StreamD as D
100−import qualified Streamly.Internal.Data.Unfold as UF
101
100
102-- type String = List Char
101-- type String = List Char
103
102
@@ -269,11 +268,9 @@ words = foldWords A.write
269-- | Unfold a stream to character streams using the supplied 'Unfold'
268-- | Unfold a stream to character streams using the supplied 'Unfold'
270-- and concat the results suffixing a newline character @\\n@ to each stream.
269-- and concat the results suffixing a newline character @\\n@ to each stream.
271--
270--
272−-- > unfoldLines = S.intercalateSuffix UF.identity '\n'
273−--
274{-# INLINE unfoldLines #-}
271{-# INLINE unfoldLines #-}
275unfoldLines :: (MonadIO m, IsStream t) => Unfold m a Char -> t m a -> t m Char
272unfoldLines :: (MonadIO m, IsStream t) => Unfold m a Char -> t m a -> t m Char
276−unfoldLines unf = S.intercalateSuffix UF.identity '\n' unf
273+unfoldLines = S.interposeSuffix '\n'
277
274
278-- | Flattens the stream of @Array Char@, after appending a terminating
275-- | Flattens the stream of @Array Char@, after appending a terminating
279-- newline to each string.
276-- newline to each string.
@@ -292,6 +289,14 @@ unfoldLines unf = S.intercalateSuffix UF.identity '\n' unf
292unlines :: (MonadIO m, IsStream t) => t m (Array Char) -> t m Char
289unlines :: (MonadIO m, IsStream t) => t m (Array Char) -> t m Char
293unlines = unfoldLines A.read
290unlines = unfoldLines A.read
294
291
292+-- | Unfold the elements of a stream to character streams using the supplied
293+-- 'Unfold' and concat the results with a whitespace character infixed between
294+-- the streams.
295+--
296+{-# INLINE unfoldWords #-}
297+unfoldWords :: (MonadIO m, IsStream t) => Unfold m a Char -> t m a -> t m Char
298+unfoldWords = S.interpose ' '
299+
295-- | Flattens the stream of @Array Char@, after appending a separating
300-- | Flattens the stream of @Array Char@, after appending a separating
296-- space to each string.
301-- space to each string.
297--
302--
@@ -300,12 +305,11 @@ unlines = unfoldLines A.read
300-- >>> S.toList $ unwords $ S.fromList ["unwords", "this", "string"]
305-- >>> S.toList $ unwords $ S.fromList ["unwords", "this", "string"]
301-- "unwords this string"
306-- "unwords this string"
302--
307--
303−--
308+-- > unwords = unfoldWords A.read
304−-- > unwords = A.concat . (S.intersperse (A.fromList " "))
305--
309--
306-- Note that, in general
310-- Note that, in general
307--
311--
308-- > unwords . words /= id
312-- > unwords . words /= id
309{-# INLINE unwords #-}
313{-# INLINE unwords #-}
310unwords :: (MonadAsync m, IsStream t) => t m (Array Char) -> t m Char
314unwords :: (MonadAsync m, IsStream t) => t m (Array Char) -> t m Char
311−unwords = AS.concat . (S.intersperse (A.fromList " "))
315+unwords = unfoldWords A.read
src/Streamly/Internal/Data/Unfold.hs+10−2
@@ -83,6 +83,7 @@ module Streamly.Internal.Data.Unfold
83 , effect
83 , effect
84 , singleton
84 , singleton
85 , identity
85 , identity
86+ , const
86 , replicateM
87 , replicateM
87 , fromList
88 , fromList
88 , fromListM
89 , fromListM
@@ -119,7 +120,7 @@ where
119import Control.Exception (Exception)
120import Control.Exception (Exception)
120import Data.Void (Void)
121import Data.Void (Void)
121import GHC.Types (SPEC(..))
122import GHC.Types (SPEC(..))
122−import Prelude hiding (concat, map, takeWhile, take, filter)
123+import Prelude hiding (concat, map, takeWhile, take, filter, const)
123
124
124import Streamly.Streams.StreamD.Type (Stream(..), Step(..))
125import Streamly.Streams.StreamD.Type (Stream(..), Step(..))
125#if __GLASGOW_HASKELL__ < 800
126#if __GLASGOW_HASKELL__ < 800
@@ -130,6 +131,7 @@ import Streamly.Internal.Data.Fold.Types (Fold(..))
130import Streamly.Internal.Data.SVar (defState)
131import Streamly.Internal.Data.SVar (defState)
131import Control.Monad.Catch (MonadCatch)
132import Control.Monad.Catch (MonadCatch)
132
133
134+import qualified Prelude
133import qualified Control.Monad.Catch as MC
135import qualified Control.Monad.Catch as MC
134import qualified Data.Tuple as Tuple
136import qualified Data.Tuple as Tuple
135import qualified Streamly.Streams.StreamK as K
137import qualified Streamly.Streams.StreamK as K
@@ -152,7 +154,7 @@ lmap f (Unfold ustep uinject) = Unfold ustep (uinject . f)
152--
154--
153{-# INLINE_NORMAL supply #-}
155{-# INLINE_NORMAL supply #-}
154supply :: Unfold m a b -> a -> Unfold m Void b
156supply :: Unfold m a b -> a -> Unfold m Void b
155−supply unf a = lmap (const a) unf
157+supply unf a = lmap (Prelude.const a) unf
156
158
157-- | Supply the first component of the tuple to an unfold that accepts a tuple
159-- | Supply the first component of the tuple to an unfold that accepts a tuple
158-- as a seed resulting in a fold that accepts the second component of the tuple
160-- as a seed resulting in a fold that accepts the second component of the tuple
@@ -344,6 +346,12 @@ singleton f = Unfold step inject
344identity :: Monad m => Unfold m a a
346identity :: Monad m => Unfold m a a
345identity = singleton return
347identity = singleton return
346
348
349+const :: Monad m => m b -> Unfold m a b
350+const m = Unfold step inject
351+ where
352+ inject _ = return ()
353+ step () = m >>= \r -> return $ Yield r ()
354+
347-- | Generates a stream replicating the seed @n@ times.
355-- | Generates a stream replicating the seed @n@ times.
348--
356--
349{-# INLINE replicateM #-}
357{-# INLINE replicateM #-}
src/Streamly/Internal/Memory/ArrayStream.hs+11−3
@@ -26,6 +26,7 @@ module Streamly.Internal.Memory.ArrayStream
26 -- * Flattening to elements
26 -- * Flattening to elements
27 , concat
27 , concat
28 , concatRev
28 , concatRev
29+ , interpose
29 , interposeSuffix
30 , interposeSuffix
30 , intercalateSuffix
31 , intercalateSuffix
31
32
@@ -51,7 +52,6 @@ import Streamly.Internal.Memory.Array.Types (Array(..), length)
51import Streamly.Streams.Serial (SerialT)
52import Streamly.Streams.Serial (SerialT)
52import Streamly.Streams.StreamK.Type (IsStream)
53import Streamly.Streams.StreamK.Type (IsStream)
53
54
54−import qualified Streamly.Internal.Data.Unfold as UF
55import qualified Streamly.Internal.Memory.Array as A
55import qualified Streamly.Internal.Memory.Array as A
56import qualified Streamly.Internal.Memory.Array.Types as A
56import qualified Streamly.Internal.Memory.Array.Types as A
57import qualified Streamly.Internal.Prelude as S
57import qualified Streamly.Internal.Prelude as S
@@ -86,10 +86,18 @@ concat m = D.fromStreamD $ D.concatMapU A.read (D.toStreamD m)
86concatRev :: (IsStream t, MonadIO m, Storable a) => t m (Array a) -> t m a
86concatRev :: (IsStream t, MonadIO m, Storable a) => t m (Array a) -> t m a
87concatRev m = D.fromStreamD $ A.flattenArraysRev (D.toStreamD m)
87concatRev m = D.fromStreamD $ A.flattenArraysRev (D.toStreamD m)
88
88
89+-- | Flatten a stream of arrays after inserting the given element between
90+-- arrays.
91+--
92+-- /Internal/
93+{-# INLINE interpose #-}
94+interpose :: (MonadIO m, IsStream t, Storable a) => a -> t m (Array a) -> t m a
95+interpose x = S.interpose x A.read
96+
89{-# INLINE intercalateSuffix #-}
97{-# INLINE intercalateSuffix #-}
90intercalateSuffix :: (MonadIO m, IsStream t, Storable a)
98intercalateSuffix :: (MonadIO m, IsStream t, Storable a)
91 => Array a -> t m (Array a) -> t m a
99 => Array a -> t m (Array a) -> t m a
92−intercalateSuffix arr = S.intercalateSuffix A.read arr A.read
100+intercalateSuffix arr = S.intercalateSuffix arr A.read
93
101
94-- | Flatten a stream of arrays appending the given element after each
102-- | Flatten a stream of arrays appending the given element after each
95-- array.
103-- array.
@@ -99,7 +107,7 @@ intercalateSuffix arr = S.intercalateSuffix A.read arr A.read
99interposeSuffix :: (MonadIO m, IsStream t, Storable a)
107interposeSuffix :: (MonadIO m, IsStream t, Storable a)
100 => a -> t m (Array a) -> t m a
108 => a -> t m (Array a) -> t m a
101-- interposeSuffix x = D.fromStreamD . A.unlines x . D.toStreamD
109-- interposeSuffix x = D.fromStreamD . A.unlines x . D.toStreamD
102−interposeSuffix x = S.intercalateSuffix UF.identity x A.read
110+interposeSuffix x = S.interposeSuffix x A.read
103
111
104-- | Split a stream of arrays on a given separator byte, dropping the separator
112-- | Split a stream of arrays on a given separator byte, dropping the separator
105-- and coalescing all the arrays between two separators into a single array.
113-- and coalescing all the arrays between two separators into a single array.
src/Streamly/Internal/Prelude.hs+192−41
@@ -33,7 +33,7 @@ module Streamly.Internal.Prelude
33 -- ** From Values
33 -- ** From Values
34 , yield
34 , yield
35 , yieldM
35 , yieldM
36− , K.repeat
36+ , repeat
37 , repeatM
37 , repeatM
38 , replicate
38 , replicate
39 , replicateM
39 , replicateM
@@ -205,9 +205,9 @@ module Streamly.Internal.Prelude
205 , insertBy
205 , insertBy
206 , intersperseM
206 , intersperseM
207 , intersperse
207 , intersperse
208− , insertAfterEach
208+ , intersperseSuffix
209 -- , intersperseBySpan
209 -- , intersperseBySpan
210− , interject
210+ , interjectSuffix
211
211
212 -- ** Reordering
212 -- ** Reordering
213 , reverse
213 , reverse
@@ -220,8 +220,9 @@ module Streamly.Internal.Prelude
220
220
221 -- ** Interleaving
221 -- ** Interleaving
222 , interleave
222 , interleave
223− , interleaveFst
224 , interleaveMin
223 , interleaveMin
224+ , interleaveSuffix
225+ , interleaveInfix
225
226
226 , Serial.wSerialFst
227 , Serial.wSerialFst
227 , Serial.wSerialMin
228 , Serial.wSerialMin
@@ -254,8 +255,12 @@ module Streamly.Internal.Prelude
254 , concatUnfoldRoundrobin
255 , concatUnfoldRoundrobin
255 , concatMap
256 , concatMap
256 , concatMapWith
257 , concatMapWith
258+ , gintercalate
259+ , gintercalateSuffix
257− -- , intercalate
260+ , intercalate
258 , intercalateSuffix
261 , intercalateSuffix
262+ , interpose
263+ , interposeSuffix
259
264
260 -- -- ** Breaking
265 -- -- ** Breaking
261
266
@@ -400,7 +405,8 @@ import Prelude
400 foldl, map, mapM, mapM_, sequence, all, any, sum, product, elem,
405 foldl, map, mapM, mapM_, sequence, all, any, sum, product, elem,
401 notElem, maximum, minimum, head, last, tail, length, null,
406 notElem, maximum, minimum, head, last, tail, length, null,
402 reverse, iterate, init, and, or, lookup, foldr1, (!!),
407 reverse, iterate, init, and, or, lookup, foldr1, (!!),
403− scanl, scanl1, replicate, concatMap, span, splitAt, break)
408+ scanl, scanl1, replicate, concatMap, span, splitAt, break,
409+ repeat)
404
410
405import qualified Data.Heap as H
411import qualified Data.Heap as H
406import qualified Data.Map.Strict as Map
412import qualified Data.Map.Strict as Map
@@ -671,6 +677,14 @@ replicateMSerial n = fromStreamS . S.replicateM n
671replicate :: (IsStream t, Monad m) => Int -> a -> t m a
677replicate :: (IsStream t, Monad m) => Int -> a -> t m a
672replicate n = fromStreamS . S.replicate n
678replicate n = fromStreamS . S.replicate n
673
679
680+-- |
681+-- Generate an infinite stream by repeating a pure value.
682+--
683+-- @since 0.4.0
684+{-# INLINE_NORMAL repeat #-}
685+repeat :: (IsStream t, Monad m) => a -> t m a
686+repeat = fromStreamS . S.repeat
687+
674-- |
688-- |
675-- @
689-- @
676-- repeatM = fix . consM
690-- repeatM = fix . consM
@@ -687,9 +701,14 @@ replicate n = fromStreamS . S.replicate n
687-- /Concurrent, infinite (do not use with 'parallely')/
701-- /Concurrent, infinite (do not use with 'parallely')/
688--
702--
689-- @since 0.2.0
703-- @since 0.2.0
704+{-# INLINE_EARLY repeatM #-}
690repeatM :: (IsStream t, MonadAsync m) => m a -> t m a
705repeatM :: (IsStream t, MonadAsync m) => m a -> t m a
691−repeatM = go
706+repeatM = K.repeatM
692− where go m = m |: go m
707+
708+{-# RULES "repeatM serial" repeatM = repeatMSerial #-}
709+{-# INLINE repeatMSerial #-}
710+repeatMSerial :: MonadAsync m => m a -> SerialT m a
711+repeatMSerial = fromStreamS . S.repeatM
693
712
694-- |
713-- |
695-- @
714-- @
@@ -1831,9 +1850,9 @@ intersperse a = fromStreamS . S.intersperse a . toStreamS
1831-- | Insert a monadic action after each element in the stream.
1850-- | Insert a monadic action after each element in the stream.
1832--
1851--
1833-- @since 0.7.0
1852-- @since 0.7.0
1834−{-# INLINE insertAfterEach #-}
1853+{-# INLINE intersperseSuffix #-}
1835−insertAfterEach :: (IsStream t, MonadAsync m) => m a -> t m a -> t m a
1854+intersperseSuffix :: (IsStream t, MonadAsync m) => m a -> t m a -> t m a
1836−insertAfterEach m = fromStreamD . D.insertAfterEach m . toStreamD
1855+intersperseSuffix m = fromStreamD . D.intersperseSuffix m . toStreamD
1837
1856
1838{-
1857{-
1839-- | Intersperse a monadic action into the input stream after every @n@
1858-- | Intersperse a monadic action into the input stream after every @n@
@@ -1854,16 +1873,16 @@ intersperseBySpan _n _f _xs = undefined
1854-- seconds.
1873-- seconds.
1855--
1874--
1856-- @
1875-- @
1857−-- > S.drain $ S.interject 1 (putChar ',') $ S.mapM (\\x -> threadDelay 1000000 >> putChar x) $ S.fromList "hello"
1876+-- > S.drain $ S.interjectSuffix 1 (putChar ',') $ S.mapM (\\x -> threadDelay 1000000 >> putChar x) $ S.fromList "hello"
1858-- "h,e,l,l,o"
1877-- "h,e,l,l,o"
1859-- @
1878-- @
1860--
1879--
1861-- @since 0.7.0
1880-- @since 0.7.0
1862−{-# INLINE interject #-}
1881+{-# INLINE interjectSuffix #-}
1863−interject
1882+interjectSuffix
1864 :: (IsStream t, MonadAsync m)
1883 :: (IsStream t, MonadAsync m)
1865 => Double -> m a -> t m a -> t m a
1884 => Double -> m a -> t m a -> t m a
1866−interject n f xs = xs `Par.parallelFst` repeatM timed
1885+interjectSuffix n f xs = xs `Par.parallelFst` repeatM timed
1867 where timed = liftIO (threadDelay (round $ n * 1000000)) >> f
1886 where timed = liftIO (threadDelay (round $ n * 1000000)) >> f
1868
1887
1869-- | @insertBy cmp elem stream@ inserts @elem@ before the first element in
1888-- | @insertBy cmp elem stream@ inserts @elem@ before the first element in
@@ -2144,13 +2163,26 @@ concatMap f m = fromStreamD $ D.concatMap (toStreamD . f) (toStreamD m)
2144append ::(IsStream t, Monad m) => t m b -> t m b -> t m b
2163append ::(IsStream t, Monad m) => t m b -> t m b -> t m b
2145append m1 m2 = fromStreamD $ D.append (toStreamD m1) (toStreamD m2)
2164append m1 m2 = fromStreamD $ D.append (toStreamD m1) (toStreamD m2)
2146
2165
2147−-- Same as 'wSerial'. We should perhaps rename wSerial. If named explicitly
2166+-- XXX Same as 'wSerial'. We should perhaps rename wSerial to interleave.
2148−-- this would be interleaveMax.
2167+-- XXX Document the interleaving behavior of side effects in all the
2168+-- interleaving combinators.
2169+-- XXX Write time-domain equivalents of these. In the time domain we can
2170+-- interleave two streams such that the value of second stream is always taken
2171+-- from its last value even if no new value is being yielded, like
2172+-- zipWithLatest. It would be something like interleaveWithLatest.
2149--
2173--
2150-- | Interleaves the outputs of two streams, yielding elements from each stream
2174-- | Interleaves the outputs of two streams, yielding elements from each stream
2151-- alternately, starting from the first stream. If any of the streams finishes
2175-- alternately, starting from the first stream. If any of the streams finishes
2152-- early the other stream continues alone until it too finishes.
2176-- early the other stream continues alone until it too finishes.
2153--
2177--
2178+-- >>> :set -XOverloadedStrings
2179+-- >>> interleave "ab" ",,,," :: SerialT Identity Char
2180+-- fromList "a,b,,,"
2181+-- >>> interleave "abcd" ",," :: SerialT Identity Char
2182+-- fromList "a,b,cd"
2183+--
2184+-- 'interleave' is dual to 'interleaveMin', it can be called @interleaveMax@.
2185+--
2154-- Do not use at scale in concatMapWith.
2186-- Do not use at scale in concatMapWith.
2155--
2187--
2156-- @since 0.7.0
2188-- @since 0.7.0
@@ -2160,18 +2192,63 @@ interleave m1 m2 = fromStreamD $ D.interleave (toStreamD m1) (toStreamD m2)
2160
2192
2161-- | Interleaves the outputs of two streams, yielding elements from each stream
2193-- | Interleaves the outputs of two streams, yielding elements from each stream
2162-- alternately, starting from the first stream. As soon as the first stream
2194-- alternately, starting from the first stream. As soon as the first stream
2163−-- finishes the output stops discarding the second stream.
2195+-- finishes, the output stops, discarding the remaining part of the second
2196+-- stream. In this case, the last element in the resulting stream would be from
2197+-- the second stream. If the second stream finishes early then the first stream
2198+-- still continues to yield elements until it finishes.
2199+--
2200+-- >>> :set -XOverloadedStrings
2201+-- >>> interleaveSuffix "abc" ",,,," :: SerialT Identity Char
2202+-- fromList "a,b,c,"
2203+-- >>> interleaveSuffix "abc" "," :: SerialT Identity Char
2204+-- fromList "a,bc"
2205+--
2206+-- 'interleaveSuffix' is a dual of 'interleaveInfix'.
2207+--
2208+-- Do not use at scale in concatMapWith.
2209+--
2210+-- @since 0.7.0
2211+{-# INLINE interleaveSuffix #-}
2212+interleaveSuffix ::(IsStream t, Monad m) => t m b -> t m b -> t m b
2213+interleaveSuffix m1 m2 =
2214+ fromStreamD $ D.interleaveSuffix (toStreamD m1) (toStreamD m2)
2215+
2216+-- | Interleaves the outputs of two streams, yielding elements from each stream
2217+-- alternately, starting from the first stream and ending at the first stream.
2218+-- If the second stream is longer than the first, elements from the second
2219+-- stream are infixed with elements from the first stream. If the first stream
2220+-- is longer then it continues yielding elements even after the second stream
2221+-- has finished.
2222+--
2223+-- >>> :set -XOverloadedStrings
2224+-- >>> interleaveInfix "abc" ",,,," :: SerialT Identity Char
2225+-- fromList "a,b,c"
2226+-- >>> interleaveInfix "abc" "," :: SerialT Identity Char
2227+-- fromList "a,bc"
2228+--
2229+-- 'interleaveInfix' is a dual of 'interleaveSuffix'.
2164--
2230--
2165-- Do not use at scale in concatMapWith.
2231-- Do not use at scale in concatMapWith.
2166--
2232--
2167-- @since 0.7.0
2233-- @since 0.7.0
2168−{-# INLINE interleaveFst #-}
2234+{-# INLINE interleaveInfix #-}
2169−interleaveFst ::(IsStream t, Monad m) => t m b -> t m b -> t m b
2235+interleaveInfix ::(IsStream t, Monad m) => t m b -> t m b -> t m b
2236+interleaveInfix m1 m2 =
2170−interleaveFst m1 m2 = fromStreamD $ D.interleaveFst (toStreamD m1) (toStreamD m2)
2237+ fromStreamD $ D.interleaveInfix (toStreamD m1) (toStreamD m2)
2171
2238
2172-- | Interleaves the outputs of two streams, yielding elements from each stream
2239-- | Interleaves the outputs of two streams, yielding elements from each stream
2173-- alternately, starting from the first stream. The output stops as soon as any
2240-- alternately, starting from the first stream. The output stops as soon as any
2174−-- of the two streams finishes discarding the other.
2241+-- of the two streams finishes, discarding the remaining part of the other
2242+-- stream. The last element of the resulting stream would be from the longer
2243+-- stream.
2244+--
2245+-- >>> :set -XOverloadedStrings
2246+-- >>> interleaveMin "ab" ",,,," :: SerialT Identity Char
2247+-- fromList "a,b,"
2248+-- >>> interleaveMin "abcd" ",," :: SerialT Identity Char
2249+-- fromList "a,b,c"
2250+--
2251+-- 'interleaveMin' is dual to 'interleave'.
2175--
2252--
2176-- Do not use at scale in concatMapWith.
2253-- Do not use at scale in concatMapWith.
2177--
2254--
@@ -2235,29 +2312,103 @@ concatUnfoldRoundrobin ::(IsStream t, Monad m)
2235concatUnfoldRoundrobin u m =
2312concatUnfoldRoundrobin u m =
2236 fromStreamD $ D.concatUnfoldRoundrobin u (toStreamD m)
2313 fromStreamD $ D.concatUnfoldRoundrobin u (toStreamD m)
2237
2314
2238−{-
2315+-- XXX we can swap the order of arguments to gintercalate so that the
2239−-- | Insert a stream between segements of streams and flatten.
2316+-- definition of concatUnfold becomes simpler? The first stream should be
2317+-- infixed inside the second one. However, if we change the order in
2318+-- "interleave" as well similarly, then that will make it a bit unintuitive.
2319+--
2320+-- > concatUnfold unf str =
2321+-- > gintercalate unf str (UF.nilM (\_ -> return ())) (repeat ())
2322+--
2323+-- | 'interleaveInfix' followed by unfold and concat.
2324+--
2325+-- /Internal/
2326+{-# INLINE gintercalate #-}
2327+gintercalate
2240−intercalate :: (IsStream t, MonadAsync m)
2328+ :: (IsStream t, Monad m)
2241− => SerialT Identity b -> (a -> t m b) -> t m a -> t m b
2329+ => Unfold m a c -> t m a -> Unfold m b c -> t m b -> t m c
2242−intercalate = undefined
2330+gintercalate unf1 str1 unf2 str2 =
2243−-}
2331+ D.fromStreamD $ D.gintercalate
2332+ unf1 (D.toStreamD str1)
2333+ unf2 (D.toStreamD str2)
2244
2334
2245−-- | @intercalateSuffix genSuffix seed gen stream@ generates streams from seeds
2335+-- XXX The order of arguments in "intercalate" is consistent with the list
2246−-- in the input @stream@ using the generator @gen@ and concatenates them
2336+-- intercalate but inconsistent with gintercalate and other stream interleaving
2247−-- after suffixing the stream generated by @genSuffix@ using @seed@.
2337+-- combinators. We can change the order of the arguments in other combinators
2338+-- but then 'interleave' combinator may become a bit unintuitive because we
2339+-- will be starting with the second stream.
2340+
2341+-- > intercalate seed unf str = gintercalate unf str unf (repeatM seed)
2342+-- > intercalate a unf str = concatUnfold unf $ intersperse a str
2248--
2343--
2249−-- For example to insert CRLF in a stream of character strings:
2344+-- | 'intersperse' followed by unfold and concat.
2250--
2345--
2251−-- > unlines = intercalateSuffix UF.fromList "\r\n" UF.fromList
2346+-- > unwords = intercalate " " UF.fromList
2252--
2347--
2253−{-# INLINE intercalateSuffix #-}
2348+-- >>> intercalate " " UF.fromList ["abc", "def", "ghi"]
2254−intercalateSuffix
2349+-- > "abc def ghi"
2350+--
2351+{-# INLINE intercalate #-}
2352+intercalate :: (IsStream t, Monad m)
2353+ => b -> Unfold m b c -> t m b -> t m c
2354+intercalate seed unf str = D.fromStreamD $
2355+ D.concatMapU unf $ D.intersperse seed (toStreamD str)
2356+
2357+-- > interpose x unf str = gintercalate unf str UF.identity (repeat x)
2358+--
2359+-- | Unfold the elements of a stream, intersperse the given element between the
2360+-- unfolded streams and then concat them into a single stream.
2361+--
2362+-- > unwords = S.interpose ' '
2363+--
2364+-- /Internal/
2365+{-# INLINE interpose #-}
2366+interpose :: (IsStream t, Monad m)
2367+ => c -> Unfold m b c -> t m b -> t m c
2368+interpose x unf str =
2369+ D.fromStreamD $ D.interpose (return x) unf (D.toStreamD str)
2370+
2371+-- | 'interleaveSuffix' followed by unfold and concat.
2372+--
2373+-- /Internal/
2374+{-# INLINE gintercalateSuffix #-}
2375+gintercalateSuffix
2255 :: (IsStream t, Monad m)
2376 :: (IsStream t, Monad m)
2256− => Unfold m a c -> a -> Unfold m b c -> t m b -> t m c
2377+ => Unfold m a c -> t m a -> Unfold m b c -> t m b -> t m c
2257−intercalateSuffix suffix seed unf str =
2378+gintercalateSuffix unf1 str1 unf2 str2 =
2258− D.fromStreamD $ D.interleaveFstThenConcat
2379+ D.fromStreamD $ D.gintercalateSuffix
2259− unf (D.toStreamD str)
2380+ unf1 (D.toStreamD str1)
2260− suffix (D.repeat seed)
2381+ unf2 (D.toStreamD str2)
2382+
2383+-- > intercalateSuffix seed unf str = gintercalateSuffix unf str unf (repeatM seed)
2384+-- > intercalateSuffix a unf str = concatUnfold unf $ intersperseSuffix a str
2385+--
2386+-- | 'intersperseSuffix' followed by unfold and concat.
2387+--
2388+-- > unlines = intercalateSuffix "\n" UF.fromList
2389+--
2390+-- >>> intercalate "\n" UF.fromList ["abc", "def", "ghi"]
2391+-- > "abc\ndef\nghi\n"
2392+--
2393+{-# INLINE intercalateSuffix #-}
2394+intercalateSuffix :: (IsStream t, Monad m)
2395+ => b -> Unfold m b c -> t m b -> t m c
2396+intercalateSuffix seed unf str = fromStreamD $ D.concatMapU unf
2397+ $ D.intersperseSuffix (return seed) (D.toStreamD str)
2398+
2399+-- interposeSuffix x unf str = gintercalateSuffix unf str UF.identity (repeat x)
2400+--
2401+-- | Unfold the elements of a stream, append the given element after each
2402+-- unfolded stream and then concat them into a single stream.
2403+--
2404+-- > unlines = S.interposeSuffix '\n'
2405+--
2406+-- /Internal/
2407+{-# INLINE interposeSuffix #-}
2408+interposeSuffix :: (IsStream t, Monad m)
2409+ => c -> Unfold m b c -> t m b -> t m c
2410+interposeSuffix x unf str =
2411+ D.fromStreamD $ D.interposeSuffix (return x) unf (D.toStreamD str)
2261
2412
2262------------------------------------------------------------------------------
2413------------------------------------------------------------------------------
2263-- Grouping/Splitting
2414-- Grouping/Splitting
@@ -2407,7 +2558,7 @@ intervalsOf
2407 => Double -> Fold m a b -> t m a -> t m b
2558 => Double -> Fold m a b -> t m a -> t m b
2408intervalsOf n f xs =
2559intervalsOf n f xs =
2409 splitWithSuffix isNothing (FL.lcatMaybes f)
2560 splitWithSuffix isNothing (FL.lcatMaybes f)
2410− (interject n (return Nothing) (Serial.map Just xs))
2561+ (interjectSuffix n (return Nothing) (Serial.map Just xs))
2411
2562
2412------------------------------------------------------------------------------
2563------------------------------------------------------------------------------
2413-- Element Aware APIs
2564-- Element Aware APIs
src/Streamly/Streams/StreamD.hs+329−12
@@ -65,6 +65,7 @@ module Streamly.Streams.StreamD
65 -- ** Specialized Generation
65 -- ** Specialized Generation
66 -- | Generate a monadic stream from a seed.
66 -- | Generate a monadic stream from a seed.
67 , repeat
67 , repeat
68+ , repeatM
68 , replicate
69 , replicate
69 , replicateM
70 , replicateM
70 , fromIndices
71 , fromIndices
@@ -148,9 +149,13 @@ module Streamly.Streams.StreamD
148 , InterleaveState(..)
149 , InterleaveState(..)
149 , interleave
150 , interleave
150 , interleaveMin
151 , interleaveMin
151− , interleaveFst
152+ , interleaveSuffix
153+ , interleaveInfix
152 , roundRobin -- interleaveFair?/ParallelFair
154 , roundRobin -- interleaveFair?/ParallelFair
153− , interleaveFstThenConcat
155+ , gintercalateSuffix
156+ , interposeSuffix
157+ , gintercalate
158+ , interpose
154
159
155 -- ** Grouping
160 -- ** Grouping
156 , groupsOf
161 , groupsOf
@@ -229,7 +234,7 @@ module Streamly.Streams.StreamD
229 -- * Inserting
234 -- * Inserting
230 , intersperseM
235 , intersperseM
231 , intersperse
236 , intersperse
232− , insertAfterEach
237+ , intersperseSuffix
233 , insertBy
238 , insertBy
234
239
235 -- * Deleting
240 -- * Deleting
@@ -419,6 +424,9 @@ unfold (Unfold ustep inject) seed = Stream step Nothing
419-- Specialized Generation
424-- Specialized Generation
420------------------------------------------------------------------------------
425------------------------------------------------------------------------------
421
426
427+repeatM :: Monad m => m a -> Stream m a
428+repeatM x = Stream (\_ _ -> x >>= \r -> return $ Yield r ()) ()
429+
422repeat :: Monad m => a -> Stream m a
430repeat :: Monad m => a -> Stream m a
423repeat x = Stream (\_ _ -> return $ Yield x ()) ()
431repeat x = Stream (\_ _ -> return $ Yield x ()) ()
424
432
@@ -2103,9 +2111,9 @@ interleaveMin (Stream step1 state1) (Stream step2 state2) =
2103 step _ (InterleaveFirstOnly _) = undefined
2111 step _ (InterleaveFirstOnly _) = undefined
2104 step _ (InterleaveSecondOnly _) = undefined
2112 step _ (InterleaveSecondOnly _) = undefined
2105
2113
2106−{-# INLINE_NORMAL interleaveFst #-}
2114+{-# INLINE_NORMAL interleaveSuffix #-}
2107−interleaveFst :: Monad m => Stream m a -> Stream m a -> Stream m a
2115+interleaveSuffix :: Monad m => Stream m a -> Stream m a -> Stream m a
2108−interleaveFst (Stream step1 state1) (Stream step2 state2) =
2116+interleaveSuffix (Stream step1 state1) (Stream step2 state2) =
2109 Stream step (InterleaveFirst state1 state2)
2117 Stream step (InterleaveFirst state1 state2)
2110
2118
2111 where
2119 where
@@ -2134,6 +2142,52 @@ interleaveFst (Stream step1 state1) (Stream step2 state2) =
2134
2142
2135 step _ (InterleaveSecondOnly _) = undefined
2143 step _ (InterleaveSecondOnly _) = undefined
2136
2144
2145+data InterleaveInfixState s1 s2 a
2146+ = InterleaveInfixFirst s1 s2
2147+ | InterleaveInfixSecondBuf s1 s2
2148+ | InterleaveInfixSecondYield s1 s2 a
2149+ | InterleaveInfixFirstYield s1 s2 a
2150+ | InterleaveInfixFirstOnly s1
2151+
2152+{-# INLINE_NORMAL interleaveInfix #-}
2153+interleaveInfix :: Monad m => Stream m a -> Stream m a -> Stream m a
2154+interleaveInfix (Stream step1 state1) (Stream step2 state2) =
2155+ Stream step (InterleaveInfixFirst state1 state2)
2156+
2157+ where
2158+
2159+ {-# INLINE_LATE step #-}
2160+ step gst (InterleaveInfixFirst st1 st2) = do
2161+ r <- step1 gst st1
2162+ return $ case r of
2163+ Yield a s -> Yield a (InterleaveInfixSecondBuf s st2)
2164+ Skip s -> Skip (InterleaveInfixFirst s st2)
2165+ Stop -> Stop
2166+
2167+ step gst (InterleaveInfixSecondBuf st1 st2) = do
2168+ r <- step2 gst st2
2169+ return $ case r of
2170+ Yield a s -> Skip (InterleaveInfixSecondYield st1 s a)
2171+ Skip s -> Skip (InterleaveInfixSecondBuf st1 s)
2172+ Stop -> Skip (InterleaveInfixFirstOnly st1)
2173+
2174+ step gst (InterleaveInfixSecondYield st1 st2 x) = do
2175+ r <- step1 gst st1
2176+ return $ case r of
2177+ Yield a s -> Yield x (InterleaveInfixFirstYield s st2 a)
2178+ Skip s -> Skip (InterleaveInfixSecondYield s st2 x)
2179+ Stop -> Stop
2180+
2181+ step _ (InterleaveInfixFirstYield st1 st2 x) = do
2182+ return $ Yield x (InterleaveInfixSecondBuf st1 st2)
2183+
2184+ step gst (InterleaveInfixFirstOnly st1) = do
2185+ r <- step1 gst st1
2186+ return $ case r of
2187+ Yield a s -> Yield a (InterleaveInfixFirstOnly s)
2188+ Skip s -> Skip (InterleaveInfixFirstOnly s)
2189+ Stop -> Stop
2190+
2137{-# INLINE_NORMAL roundRobin #-}
2191{-# INLINE_NORMAL roundRobin #-}
2138roundRobin :: Monad m => Stream m a -> Stream m a -> Stream m a
2192roundRobin :: Monad m => Stream m a -> Stream m a -> Stream m a
2139roundRobin (Stream step1 state1) (Stream step2 state2) =
2193roundRobin (Stream step1 state1) (Stream step2 state2) =
@@ -2190,11 +2244,11 @@ data ICUState s1 s2 i1 i2 =
2190-- => [streamA1, streamB1, streamA2...StreamAn, streamBn]
2244-- => [streamA1, streamB1, streamA2...StreamAn, streamBn]
2191-- => [a11, a12, ...a1j, b11, b12, ...b1k, a21, a22, ...]
2245-- => [a11, a12, ...a1j, b11, b12, ...b1k, a21, a22, ...]
2192--
2246--
2193−{-# INLINE_NORMAL interleaveFstThenConcat #-}
2247+{-# INLINE_NORMAL gintercalateSuffix #-}
2194−interleaveFstThenConcat
2248+gintercalateSuffix
2195 :: Monad m
2249 :: Monad m
2196 => Unfold m a c -> Stream m a -> Unfold m b c -> Stream m b -> Stream m c
2250 => Unfold m a c -> Stream m a -> Unfold m b c -> Stream m b -> Stream m c
2197−interleaveFstThenConcat
2251+gintercalateSuffix
2198 (Unfold istep1 inject1) (Stream step1 state1)
2252 (Unfold istep1 inject1) (Stream step1 state1)
2199 (Unfold istep2 inject2) (Stream step2 state2) =
2253 (Unfold istep2 inject2) (Stream step2 state2) =
2200 Stream step (ICUFirst state1 state2)
2254 Stream step (ICUFirst state1 state2)
@@ -2253,6 +2307,269 @@ interleaveFstThenConcat
2253 step _ (ICUSecondOnly _s2) = undefined
2307 step _ (ICUSecondOnly _s2) = undefined
2254 step _ (ICUSecondOnlyInner _s2 _i2) = undefined
2308 step _ (ICUSecondOnlyInner _s2 _i2) = undefined
2255
2309
2310+data InterposeSuffixState s1 i1 =
2311+ InterposeSuffixFirst s1
2312+ -- | InterposeSuffixFirstYield s1 i1
2313+ | InterposeSuffixFirstInner s1 i1
2314+ | InterposeSuffixSecond s1
2315+
2316+-- Note that if an unfolded layer turns out to be nil we still emit the
2317+-- separator effect. An alternate behavior could be to emit the separator
2318+-- effect only if at least one element has been yielded by the unfolding.
2319+-- However, that becomes a bit complicated, so we have chosen the former
2320+-- behvaior for now.
2321+{-# INLINE_NORMAL interposeSuffix #-}
2322+interposeSuffix
2323+ :: Monad m
2324+ => m c -> Unfold m b c -> Stream m b -> Stream m c
2325+interposeSuffix
2326+ action
2327+ (Unfold istep1 inject1) (Stream step1 state1) =
2328+ Stream step (InterposeSuffixFirst state1)
2329+
2330+ where
2331+
2332+ {-# INLINE_LATE step #-}
2333+ step gst (InterposeSuffixFirst s1) = do
2334+ r <- step1 (adaptState gst) s1
2335+ case r of
2336+ Yield a s -> do
2337+ i <- inject1 a
2338+ i `seq` return (Skip (InterposeSuffixFirstInner s i))
2339+ -- i `seq` return (Skip (InterposeSuffixFirstYield s i))
2340+ Skip s -> return $ Skip (InterposeSuffixFirst s)
2341+ Stop -> return Stop
2342+
2343+ {-
2344+ step _ (InterposeSuffixFirstYield s1 i1) = do
2345+ r <- istep1 i1
2346+ return $ case r of
2347+ Yield x i' -> Yield x (InterposeSuffixFirstInner s1 i')
2348+ Skip i' -> Skip (InterposeSuffixFirstYield s1 i')
2349+ Stop -> Skip (InterposeSuffixFirst s1)
2350+ -}
2351+
2352+ step _ (InterposeSuffixFirstInner s1 i1) = do
2353+ r <- istep1 i1
2354+ return $ case r of
2355+ Yield x i' -> Yield x (InterposeSuffixFirstInner s1 i')
2356+ Skip i' -> Skip (InterposeSuffixFirstInner s1 i')
2357+ Stop -> Skip (InterposeSuffixSecond s1)
2358+
2359+ step _ (InterposeSuffixSecond s1) = do
2360+ r <- action
2361+ return $ Yield r (InterposeSuffixFirst s1)
2362+
2363+data ICALState s1 s2 i1 i2 a =
2364+ ICALFirst s1 s2
2365+ -- | ICALFirstYield s1 s2 i1
2366+ | ICALFirstInner s1 s2 i1
2367+ | ICALFirstOnly s1
2368+ | ICALFirstOnlyInner s1 i1
2369+ | ICALSecondInject s1 s2
2370+ | ICALFirstInject s1 s2 i2
2371+ -- | ICALFirstBuf s1 s2 i1 i2
2372+ | ICALSecondInner s1 s2 i1 i2
2373+ -- -- | ICALSecondInner s1 s2 i1 i2 a
2374+ -- -- | ICALFirstResume s1 s2 i1 i2 a
2375+
2376+-- | Interleave streams (full streams, not the elements) unfolded from two
2377+-- input streams and concat. Stop when the first stream stops. If the second
2378+-- stream ends before the first one then first stream still keeps running alone
2379+-- without any interleaving with the second stream.
2380+--
2381+-- [a1, a2, ... an] [b1, b2 ...]
2382+-- => [streamA1, streamA2, ... streamAn] [streamB1, streamB2, ...]
2383+-- => [streamA1, streamB1, streamA2...StreamAn, streamBn]
2384+-- => [a11, a12, ...a1j, b11, b12, ...b1k, a21, a22, ...]
2385+--
2386+{-# INLINE_NORMAL gintercalate #-}
2387+gintercalate
2388+ :: Monad m
2389+ => Unfold m a c -> Stream m a -> Unfold m b c -> Stream m b -> Stream m c
2390+gintercalate
2391+ (Unfold istep1 inject1) (Stream step1 state1)
2392+ (Unfold istep2 inject2) (Stream step2 state2) =
2393+ Stream step (ICALFirst state1 state2)
2394+
2395+ where
2396+
2397+ {-# INLINE_LATE step #-}
2398+ step gst (ICALFirst s1 s2) = do
2399+ r <- step1 (adaptState gst) s1
2400+ case r of
2401+ Yield a s -> do
2402+ i <- inject1 a
2403+ i `seq` return (Skip (ICALFirstInner s s2 i))
2404+ -- i `seq` return (Skip (ICALFirstYield s s2 i))
2405+ Skip s -> return $ Skip (ICALFirst s s2)
2406+ Stop -> return Stop
2407+
2408+ {-
2409+ step _ (ICALFirstYield s1 s2 i1) = do
2410+ r <- istep1 i1
2411+ return $ case r of
2412+ Yield x i' -> Yield x (ICALFirstInner s1 s2 i')
2413+ Skip i' -> Skip (ICALFirstYield s1 s2 i')
2414+ Stop -> Skip (ICALFirst s1 s2)
2415+ -}
2416+
2417+ step _ (ICALFirstInner s1 s2 i1) = do
2418+ r <- istep1 i1
2419+ return $ case r of
2420+ Yield x i' -> Yield x (ICALFirstInner s1 s2 i')
2421+ Skip i' -> Skip (ICALFirstInner s1 s2 i')
2422+ Stop -> Skip (ICALSecondInject s1 s2)
2423+
2424+ step gst (ICALFirstOnly s1) = do
2425+ r <- step1 (adaptState gst) s1
2426+ case r of
2427+ Yield a s -> do
2428+ i <- inject1 a
2429+ i `seq` return (Skip (ICALFirstOnlyInner s i))
2430+ Skip s -> return $ Skip (ICALFirstOnly s)
2431+ Stop -> return Stop
2432+
2433+ step _ (ICALFirstOnlyInner s1 i1) = do
2434+ r <- istep1 i1
2435+ return $ case r of
2436+ Yield x i' -> Yield x (ICALFirstOnlyInner s1 i')
2437+ Skip i' -> Skip (ICALFirstOnlyInner s1 i')
2438+ Stop -> Skip (ICALFirstOnly s1)
2439+
2440+ -- We inject the second stream even before checking if the first stream
2441+ -- would yield any more elements. There is no clear choice whether we
2442+ -- should do this before or after that. Doing it after may make the state
2443+ -- machine a bit simpler though.
2444+ step gst (ICALSecondInject s1 s2) = do
2445+ r <- step2 (adaptState gst) s2
2446+ case r of
2447+ Yield a s -> do
2448+ i <- inject2 a
2449+ i `seq` return (Skip (ICALFirstInject s1 s i))
2450+ Skip s -> return $ Skip (ICALSecondInject s1 s)
2451+ Stop -> return $ Skip (ICALFirstOnly s1)
2452+
2453+ step gst (ICALFirstInject s1 s2 i2) = do
2454+ r <- step1 (adaptState gst) s1
2455+ case r of
2456+ Yield a s -> do
2457+ i <- inject1 a
2458+ i `seq` return (Skip (ICALSecondInner s s2 i i2))
2459+ -- i `seq` return (Skip (ICALFirstBuf s s2 i i2))
2460+ Skip s -> return $ Skip (ICALFirstInject s s2 i2)
2461+ Stop -> return Stop
2462+
2463+ {-
2464+ step _ (ICALFirstBuf s1 s2 i1 i2) = do
2465+ r <- istep1 i1
2466+ return $ case r of
2467+ Yield x i' -> Skip (ICALSecondInner s1 s2 i' i2 x)
2468+ Skip i' -> Skip (ICALFirstBuf s1 s2 i' i2)
2469+ Stop -> Stop
2470+
2471+ step _ (ICALSecondInner s1 s2 i1 i2 v) = do
2472+ r <- istep2 i2
2473+ return $ case r of
2474+ Yield x i' -> Yield x (ICALSecondInner s1 s2 i1 i' v)
2475+ Skip i' -> Skip (ICALSecondInner s1 s2 i1 i' v)
2476+ Stop -> Skip (ICALFirstResume s1 s2 i1 i2 v)
2477+ -}
2478+
2479+ step _ (ICALSecondInner s1 s2 i1 i2) = do
2480+ r <- istep2 i2
2481+ return $ case r of
2482+ Yield x i' -> Yield x (ICALSecondInner s1 s2 i1 i')
2483+ Skip i' -> Skip (ICALSecondInner s1 s2 i1 i')
2484+ Stop -> Skip (ICALFirstInner s1 s2 i1)
2485+ -- Stop -> Skip (ICALFirstResume s1 s2 i1 i2)
2486+
2487+ {-
2488+ step _ (ICALFirstResume s1 s2 i1 i2 x) = do
2489+ return $ Yield x (ICALFirstInner s1 s2 i1 i2)
2490+ -}
2491+
2492+data InterposeState s1 i1 a =
2493+ InterposeFirst s1
2494+ -- | InterposeFirstYield s1 i1
2495+ | InterposeFirstInner s1 i1
2496+ | InterposeFirstInject s1
2497+ -- | InterposeFirstBuf s1 i1
2498+ | InterposeSecondYield s1 i1
2499+ -- -- | InterposeSecondYield s1 i1 a
2500+ -- -- | InterposeFirstResume s1 i1 a
2501+
2502+-- Note that this only interposes the pure values, we may run many effects to
2503+-- generate those values as some effects may not generate anything (Skip).
2504+{-# INLINE_NORMAL interpose #-}
2505+interpose :: Monad m => m c -> Unfold m b c -> Stream m b -> Stream m c
2506+interpose
2507+ action
2508+ (Unfold istep1 inject1) (Stream step1 state1) =
2509+ Stream step (InterposeFirst state1)
2510+
2511+ where
2512+
2513+ {-# INLINE_LATE step #-}
2514+ step gst (InterposeFirst s1) = do
2515+ r <- step1 (adaptState gst) s1
2516+ case r of
2517+ Yield a s -> do
2518+ i <- inject1 a
2519+ i `seq` return (Skip (InterposeFirstInner s i))
2520+ -- i `seq` return (Skip (InterposeFirstYield s i))
2521+ Skip s -> return $ Skip (InterposeFirst s)
2522+ Stop -> return Stop
2523+
2524+ {-
2525+ step _ (InterposeFirstYield s1 i1) = do
2526+ r <- istep1 i1
2527+ return $ case r of
2528+ Yield x i' -> Yield x (InterposeFirstInner s1 i')
2529+ Skip i' -> Skip (InterposeFirstYield s1 i')
2530+ Stop -> Skip (InterposeFirst s1)
2531+ -}
2532+
2533+ step _ (InterposeFirstInner s1 i1) = do
2534+ r <- istep1 i1
2535+ return $ case r of
2536+ Yield x i' -> Yield x (InterposeFirstInner s1 i')
2537+ Skip i' -> Skip (InterposeFirstInner s1 i')
2538+ Stop -> Skip (InterposeFirstInject s1)
2539+
2540+ step gst (InterposeFirstInject s1) = do
2541+ r <- step1 (adaptState gst) s1
2542+ case r of
2543+ Yield a s -> do
2544+ i <- inject1 a
2545+ -- i `seq` return (Skip (InterposeFirstBuf s i))
2546+ i `seq` return (Skip (InterposeSecondYield s i))
2547+ Skip s -> return $ Skip (InterposeFirstInject s)
2548+ Stop -> return Stop
2549+
2550+ {-
2551+ step _ (InterposeFirstBuf s1 i1) = do
2552+ r <- istep1 i1
2553+ return $ case r of
2554+ Yield x i' -> Skip (InterposeSecondYield s1 i' x)
2555+ Skip i' -> Skip (InterposeFirstBuf s1 i')
2556+ Stop -> Stop
2557+ -}
2558+
2559+ {-
2560+ step _ (InterposeSecondYield s1 i1 v) = do
2561+ r <- action
2562+ return $ Yield r (InterposeFirstResume s1 i1 v)
2563+ -}
2564+ step _ (InterposeSecondYield s1 i1) = do
2565+ r <- action
2566+ return $ Yield r (InterposeFirstInner s1 i1)
2567+
2568+ {-
2569+ step _ (InterposeFirstResume s1 i1 v) = do
2570+ return $ Yield v (InterposeFirstInner s1 i1)
2571+ -}
2572+
2256------------------------------------------------------------------------------
2573------------------------------------------------------------------------------
2257-- Exceptions
2574-- Exceptions
2258------------------------------------------------------------------------------
2575------------------------------------------------------------------------------
@@ -2853,9 +3170,9 @@ data SuffixState s a
2853 | SuffixSuffix s
3170 | SuffixSuffix s
2854 | SuffixYield a (SuffixState s a)
3171 | SuffixYield a (SuffixState s a)
2855
3172
2856−{-# INLINE_NORMAL insertAfterEach #-}
3173+{-# INLINE_NORMAL intersperseSuffix #-}
2857−insertAfterEach :: forall m a. Monad m => m a -> Stream m a -> Stream m a
3174+intersperseSuffix :: forall m a. Monad m => m a -> Stream m a -> Stream m a
2858−insertAfterEach action (Stream step state) = Stream step' (SuffixElem state)
3175+intersperseSuffix action (Stream step state) = Stream step' (SuffixElem state)
2859 where
3176 where
2860 {-# INLINE_LATE step' #-}
3177 {-# INLINE_LATE step' #-}
2861 step' gst (SuffixElem st) = do
3178 step' gst (SuffixElem st) = do
src/Streamly/Streams/StreamK.hs+9−1
@@ -62,6 +62,7 @@ module Streamly.Streams.StreamK
62
62
63 -- ** Specialized Generation
63 -- ** Specialized Generation
64 , repeat
64 , repeat
65+ , repeatM
65 , replicate
66 , replicate
66 , replicateM
67 , replicateM
67 , fromIndices
68 , fromIndices
@@ -268,9 +269,16 @@ once = yieldM
268-- repeatM = cycle1 . yield
269-- repeatM = cycle1 . yield
269-- @
270-- @
270--
271--
272+-- Generate an infinite stream by repeating a monadic value.
273+--
274+-- /Internal/
275+repeatM :: (IsStream t, MonadAsync m) => m a -> t m a
276+repeatM = go
277+ where go m = m |: go m
278+
271-- Generate an infinite stream by repeating a pure value.
279-- Generate an infinite stream by repeating a pure value.
272--
280--
273−-- @since 0.4.0
281+-- /Internal/
274{-# INLINE repeat #-}
282{-# INLINE repeat #-}
275repeat :: IsStream t => a -> t m a
283repeat :: IsStream t => a -> t m a
276repeat a = let x = cons a x in x
284repeat a = let x = cons a x in x