on master help sign in
Use StreamD by default, expose StreamK as separate module
e249c4dHarendra Kumar
benchmark/Streamly/Benchmark/Data/Array/Common.hs+6−6
@@ -71,9 +71,9 @@ onArray
71 -> m (Stream Int)
71 -> m (Stream Int)
72onArray value f arr = S.fold (A.writeN value) $ f $ S.unfold A.reader arr
72onArray value f arr = S.fold (A.writeN value) $ f $ S.unfold A.reader arr
73
73
74−scanl' value n = composeN n $ onArray value $ S.scanl' (+) 0
74+scanl' value n = composeN n $ onArray value $ S.scan (Fold.foldl' (+) 0)
75−scanl1' value n = composeN n $ onArray value $ S.scanl1' (+)
75+scanl1' value n = composeN n $ onArray value $ Stream.scanl1' (+)
76−map value n = composeN n $ onArray value $ S.map (+1)
76+map value n = composeN n $ onArray value $ fmap (+1)
77-- map n = composeN n $ A.map (+1)
77-- map n = composeN n $ A.map (+1)
78
78
79{-# INLINE eqInstance #-}
79{-# INLINE eqInstance #-}
@@ -98,7 +98,7 @@ showInstance = P.show
98
98
99{-# INLINE pureFoldl' #-}
99{-# INLINE pureFoldl' #-}
100pureFoldl' :: MonadIO m => Stream Int -> m Int
100pureFoldl' :: MonadIO m => Stream Int -> m Int
101−pureFoldl' = S.foldl' (+) 0 . S.unfold A.reader
101+pureFoldl' = S.fold (Fold.foldl' (+) 0) . S.unfold A.reader
102
102
103-------------------------------------------------------------------------------
103-------------------------------------------------------------------------------
104-- Elimination
104-- Elimination
@@ -106,11 +106,11 @@ pureFoldl' = S.foldl' (+) 0 . S.unfold A.reader
106
106
107{-# INLINE unfoldReadDrain #-}
107{-# INLINE unfoldReadDrain #-}
108unfoldReadDrain :: MonadIO m => Stream Int -> m ()
108unfoldReadDrain :: MonadIO m => Stream Int -> m ()
109−unfoldReadDrain = S.drain . S.unfold A.reader
109+unfoldReadDrain = S.fold Fold.drain . S.unfold A.reader
110
110
111{-# INLINE toStreamRevDrain #-}
111{-# INLINE toStreamRevDrain #-}
112toStreamRevDrain :: MonadIO m => Stream Int -> m ()
112toStreamRevDrain :: MonadIO m => Stream Int -> m ()
113−toStreamRevDrain = S.drain . A.readRev
113+toStreamRevDrain = S.fold Fold.drain . A.readRev
114
114
115-------------------------------------------------------------------------------
115-------------------------------------------------------------------------------
116-- Bench groups
116-- Bench groups
benchmark/Streamly/Benchmark/Data/Array/CommonImports.hs+4−3
@@ -5,11 +5,12 @@ import Control.Monad.IO.Class (MonadIO)
5import Data.Functor ((<&>))
5import Data.Functor ((<&>))
6import System.Random (randomRIO)
6import System.Random (randomRIO)
7
7
8−import qualified Streamly.Prelude as S
8+import qualified Streamly.Data.Fold as Fold
9+import qualified Streamly.Data.Stream as S
9−import qualified Streamly.Internal.Data.Stream as Stream
10+import qualified Streamly.Internal.Data.Stream.StreamD as Stream
10
11
11import Gauge
12import Gauge
12import Streamly.Benchmark.Common hiding (benchPureSrc)
13import Streamly.Benchmark.Common hiding (benchPureSrc)
13−import qualified Streamly.Benchmark.Prelude as P
14+import qualified Stream.Common as P
14
15
15import Prelude as P hiding (map)
16import Prelude as P hiding (map)
benchmark/Streamly/Benchmark/Data/Array/Mut.hs+4−6
@@ -46,8 +46,7 @@ import Prelude
46import qualified Streamly.Internal.Data.Array as Array
46import qualified Streamly.Internal.Data.Array as Array
47import qualified Streamly.Internal.Data.Array.Mut as MArray
47import qualified Streamly.Internal.Data.Array.Mut as MArray
48import qualified Streamly.Internal.Data.Fold as Fold
48import qualified Streamly.Internal.Data.Fold as Fold
49−import qualified Streamly.Internal.Data.Stream as Stream
49+import qualified Streamly.Internal.Data.Stream.StreamD as Stream
50−import qualified Streamly.Prelude as IsStream (scanl1')
51
50
52import Gauge
51import Gauge
53import Streamly.Benchmark.Common hiding (benchPureSrc)
52import Streamly.Benchmark.Common hiding (benchPureSrc)
@@ -153,7 +152,7 @@ scanl' value n = composeN n $ onArray value $ Stream.scan (Fold.foldl' (+) 0)
153
152
154{-# INLINE scanl1' #-}
153{-# INLINE scanl1' #-}
155scanl1' :: MonadIO m => Int -> Int -> Stream Int -> m (Stream Int)
154scanl1' :: MonadIO m => Int -> Int -> Stream Int -> m (Stream Int)
156−scanl1' value n = composeN n $ onArray value $ IsStream.scanl1' (+)
155+scanl1' value n = composeN n $ onArray value $ Stream.scanl1' (+)
157
156
158{-# INLINE map #-}
157{-# INLINE map #-}
159map :: MonadIO m => Int -> Int -> Stream Int -> m (Stream Int)
158map :: MonadIO m => Int -> Int -> Stream Int -> m (Stream Int)
@@ -181,12 +180,11 @@ unfoldReadRevDrain = drain . Stream.unfold MArray.readerRev
181
180
182{-# INLINE toStreamDRevDrain #-}
181{-# INLINE toStreamDRevDrain #-}
183toStreamDRevDrain :: MonadIO m => Stream Int -> m ()
182toStreamDRevDrain :: MonadIO m => Stream Int -> m ()
184−toStreamDRevDrain =
183+toStreamDRevDrain = drain . MArray.toStreamDRev
185− drain . Stream.fromStreamD . MArray.toStreamDRev
186
184
187{-# INLINE toStreamDDrain #-}
185{-# INLINE toStreamDDrain #-}
188toStreamDDrain :: MonadIO m => Stream Int -> m ()
186toStreamDDrain :: MonadIO m => Stream Int -> m ()
189−toStreamDDrain = drain . Stream.fromStreamD . MArray.toStreamD
187+toStreamDDrain = drain . MArray.toStreamD
190
188
191{-# INLINE unfoldFold #-}
189{-# INLINE unfoldFold #-}
192unfoldFold :: MonadIO m => Stream Int -> m Int
190unfoldFold :: MonadIO m => Stream Int -> m Int
benchmark/Streamly/Benchmark/Data/Array/Stream.hs+28−22
@@ -27,21 +27,23 @@ module Main
27
27
28import Control.DeepSeq (NFData(..))
28import Control.DeepSeq (NFData(..))
29import Control.Monad (void, when)
29import Control.Monad (void, when)
30−import Control.Monad.Catch (MonadCatch, try, SomeException)
30+import Control.Monad.Catch (MonadCatch)
31import Data.Functor.Identity (runIdentity)
31import Data.Functor.Identity (runIdentity)
32import Data.Maybe (isJust)
32import Data.Maybe (isJust)
33import Data.Word (Word8)
33import Data.Word (Word8)
34−import Streamly.Internal.Data.Stream (Stream)
34+import Streamly.Internal.Data.Stream.StreamD (Stream)
35+import Streamly.Internal.Data.Stream.StreamK (StreamK)
35import System.IO (Handle)
36import System.IO (Handle)
36import System.Random (randomRIO)
37import System.Random (randomRIO)
37import Prelude hiding ()
38import Prelude hiding ()
38
39
40+import qualified Streamly.Data.Stream as Stream
39import qualified Streamly.Internal.Data.Array as Array
41import qualified Streamly.Internal.Data.Array as Array
40import qualified Streamly.Internal.Data.Stream.Chunked as ArrayStream
42import qualified Streamly.Internal.Data.Stream.Chunked as ArrayStream
41import qualified Streamly.Internal.Data.Fold as Fold
43import qualified Streamly.Internal.Data.Fold as Fold
42import qualified Streamly.Internal.Data.Parser as Parser
44import qualified Streamly.Internal.Data.Parser as Parser
43−import qualified Streamly.Internal.Data.Stream as S
45+import qualified Streamly.Internal.Data.Stream.StreamD as Stream
44−import qualified Streamly.Internal.Data.Stream.IsStream as Stream
46+import qualified Streamly.Internal.Data.Stream.StreamK as StreamK
45import qualified Streamly.Internal.FileSystem.Handle as Handle
47import qualified Streamly.Internal.FileSystem.Handle as Handle
46import qualified Streamly.Internal.Unicode.Stream as Unicode
48import qualified Streamly.Internal.Unicode.Stream as Unicode
47
49
@@ -63,8 +65,8 @@ import Test.Inspection
63-- XXX these can be moved to the common module
65-- XXX these can be moved to the common module
64
66
65{-# INLINE sourceUnfoldrM #-}
67{-# INLINE sourceUnfoldrM #-}
66−sourceUnfoldrM :: MonadIO m => Int -> Int -> Stream m Int
68+sourceUnfoldrM :: MonadIO m => Int -> Int -> Stream.Stream m Int
67−sourceUnfoldrM value n = S.unfoldrM step n
69+sourceUnfoldrM value n = Stream.unfoldrM step n
68 where
70 where
69 step cnt =
71 step cnt =
70 if cnt > n + value
72 if cnt > n + value
@@ -100,7 +102,7 @@ inspect $ 'toChunksLast `hasNoType` ''Step
100toChunksSumLengths :: Handle -> IO Int
102toChunksSumLengths :: Handle -> IO Int
101toChunksSumLengths inh =
103toChunksSumLengths inh =
102 let s = Handle.readChunks inh
104 let s = Handle.readChunks inh
103− in Stream.sum (Stream.map Array.length s)
105+ in Stream.fold Fold.sum (Stream.map Array.length s)
104
106
105#ifdef INSPECTION
107#ifdef INSPECTION
106inspect $ hasNoTypeClasses 'toChunksSumLengths
108inspect $ hasNoTypeClasses 'toChunksSumLengths
@@ -135,7 +137,9 @@ inspect $ hasNoTypeClasses 'toChunksDecodeUtf8Arrays
135-- | Count the number of lines in a file.
137-- | Count the number of lines in a file.
136toChunksSplitOnSuffix :: Handle -> IO Int
138toChunksSplitOnSuffix :: Handle -> IO Int
137toChunksSplitOnSuffix =
139toChunksSplitOnSuffix =
140+ Stream.fold Fold.length
138− Stream.length . ArrayStream.splitOnSuffix 10 . Handle.readChunks
141+ . ArrayStream.splitOnSuffix 10
142+ . Handle.readChunks
139
143
140#ifdef INSPECTION
144#ifdef INSPECTION
141inspect $ hasNoTypeClasses 'toChunksSplitOnSuffix
145inspect $ hasNoTypeClasses 'toChunksSplitOnSuffix
@@ -145,7 +149,10 @@ inspect $ 'toChunksSplitOnSuffix `hasNoType` ''Step
145-- XXX use a word splitting combinator instead of splitOn and test it.
149-- XXX use a word splitting combinator instead of splitOn and test it.
146-- | Count the number of words in a file.
150-- | Count the number of words in a file.
147toChunksSplitOn :: Handle -> IO Int
151toChunksSplitOn :: Handle -> IO Int
152+toChunksSplitOn =
153+ Stream.fold Fold.length
148−toChunksSplitOn = Stream.length . ArrayStream.splitOn 32 . Handle.readChunks
154+ . ArrayStream.splitOn 32
155+ . Handle.readChunks
149
156
150#ifdef INSPECTION
157#ifdef INSPECTION
151inspect $ hasNoTypeClasses 'toChunksSplitOn
158inspect $ hasNoTypeClasses 'toChunksSplitOn
@@ -183,8 +190,7 @@ o_1_space_read_chunked env =
183copyChunksSplitInterposeSuffix :: Handle -> Handle -> IO ()
190copyChunksSplitInterposeSuffix :: Handle -> Handle -> IO ()
184copyChunksSplitInterposeSuffix inh outh =
191copyChunksSplitInterposeSuffix inh outh =
185 Stream.fold (Handle.write outh)
192 Stream.fold (Handle.write outh)
186− $ ArrayStream.interposeSuffix 10
193+ $ ArrayStream.interposeSuffix 10 . ArrayStream.splitOnSuffix 10
187− $ ArrayStream.splitOnSuffix 10
188 $ Handle.readChunks inh
194 $ Handle.readChunks inh
189
195
190#ifdef INSPECTION
196#ifdef INSPECTION
@@ -197,9 +203,8 @@ inspect $ 'copyChunksSplitInterposeSuffix `hasNoType` ''Step
197copyChunksSplitInterpose :: Handle -> Handle -> IO ()
203copyChunksSplitInterpose :: Handle -> Handle -> IO ()
198copyChunksSplitInterpose inh outh =
204copyChunksSplitInterpose inh outh =
199 Stream.fold (Handle.write outh)
205 Stream.fold (Handle.write outh)
200− $ ArrayStream.interpose 32
201 -- XXX this is not correct word splitting combinator
206 -- XXX this is not correct word splitting combinator
202− $ ArrayStream.splitOn 32
207+ $ ArrayStream.interpose 32 . ArrayStream.splitOn 32
203 $ Handle.readChunks inh
208 $ Handle.readChunks inh
204
209
205#ifdef INSPECTION
210#ifdef INSPECTION
@@ -231,25 +236,26 @@ drainWhile p = Parser.takeWhile p Fold.drain
231
236
232{-# INLINE fold #-}
237{-# INLINE fold #-}
233fold :: Stream IO (Array.Array Int) -> IO ()
238fold :: Stream IO (Array.Array Int) -> IO ()
234−fold s = void $ ArrayStream.foldBreak Fold.drain s
239+fold s = void $ ArrayStream.foldBreak Fold.drain $ StreamK.fromStream s
235
240
236{-# INLINE parse #-}
241{-# INLINE parse #-}
237parse :: Int -> Stream IO (Array.Array Int) -> IO ()
242parse :: Int -> Stream IO (Array.Array Int) -> IO ()
243+parse value s =
238−parse value s = void $ ArrayStream.parseBreak (drainWhile (< value)) s
244+ void $ ArrayStream.parseBreak (drainWhile (< value)) $ StreamK.fromStream s
239
245
240{-# INLINE foldBreak #-}
246{-# INLINE foldBreak #-}
241−foldBreak :: Stream IO (Array.Array Int) -> IO ()
247+foldBreak :: StreamK IO (Array.Array Int) -> IO ()
242foldBreak s = do
248foldBreak s = do
243 (r, s1) <- ArrayStream.foldBreak Fold.one s
249 (r, s1) <- ArrayStream.foldBreak Fold.one s
244 when (isJust r) $ foldBreak s1
250 when (isJust r) $ foldBreak s1
245
251
246{-# INLINE parseBreak #-}
252{-# INLINE parseBreak #-}
247−parseBreak :: Stream IO (Array.Array Int) -> IO ()
253+parseBreak :: StreamK IO (Array.Array Int) -> IO ()
248parseBreak s = do
254parseBreak s = do
249− r <- try $ ArrayStream.parseBreak Parser.one s
255+ r <- ArrayStream.parseBreak Parser.one s
250 case r of
256 case r of
251− Left (_ :: SomeException) -> return ()
257+ (Left _, _) -> return ()
252− Right (_, s1) -> parseBreak s1
258+ (Right _, s1) -> parseBreak s1
253
259
254o_1_space_serial_array ::
260o_1_space_serial_array ::
255 Int -> [Array.Array Int] -> [Array.Array Int] -> [Benchmark]
261 Int -> [Array.Array Int] -> [Array.Array Int] -> [Benchmark]
@@ -259,7 +265,7 @@ o_1_space_serial_array bound arraysSmall arraysBig =
259 , benchIO
265 , benchIO
260 "foldBreak (recursive, small arrays)"
266 "foldBreak (recursive, small arrays)"
261 (\_ -> Stream.fromList arraysSmall)
267 (\_ -> Stream.fromList arraysSmall)
262− foldBreak
268+ (foldBreak . StreamK.fromStream)
263 , benchIO "parse (of 100)" (\_ -> Stream.fromList arraysSmall)
269 , benchIO "parse (of 100)" (\_ -> Stream.fromList arraysSmall)
264 $ parse bound
270 $ parse bound
265 , benchIO "parse (single)" (\_ -> Stream.fromList arraysBig)
271 , benchIO "parse (single)" (\_ -> Stream.fromList arraysBig)
@@ -267,7 +273,7 @@ o_1_space_serial_array bound arraysSmall arraysBig =
267 , benchIO
273 , benchIO
268 "parseBreak (recursive, small arrays)"
274 "parseBreak (recursive, small arrays)"
269 (\_ -> Stream.fromList arraysSmall)
275 (\_ -> Stream.fromList arraysSmall)
270− parseBreak
276+ (parseBreak . StreamK.fromStream)
271 ]
277 ]
272
278
273-------------------------------------------------------------------------------
279-------------------------------------------------------------------------------
benchmark/Streamly/Benchmark/Data/Fold.hs+2−2
@@ -25,7 +25,7 @@ import Data.IntMap.Strict (IntMap)
25import Data.Monoid (Last(..), Sum(..))
25import Data.Monoid (Last(..), Sum(..))
26import System.Random (randomRIO)
26import System.Random (randomRIO)
27
27
28−import Streamly.Internal.Data.Stream (Stream)
28+import Streamly.Internal.Data.Stream.StreamD (Stream)
29import Streamly.Internal.Data.Fold (Fold(..))
29import Streamly.Internal.Data.Fold (Fold(..))
30import Streamly.Internal.Data.IsMap.HashMap ()
30import Streamly.Internal.Data.IsMap.HashMap ()
31
31
@@ -34,7 +34,7 @@ import qualified Streamly.Internal.Data.Fold as FL
34import qualified Streamly.Internal.Data.Fold.Container as FL
34import qualified Streamly.Internal.Data.Fold.Container as FL
35import qualified Streamly.Internal.Data.Unfold as Unfold
35import qualified Streamly.Internal.Data.Unfold as Unfold
36import qualified Streamly.Internal.Data.Pipe as Pipe
36import qualified Streamly.Internal.Data.Pipe as Pipe
37−import qualified Streamly.Internal.Data.Stream as Stream
37+import qualified Streamly.Internal.Data.Stream.StreamD as Stream
38
38
39import Gauge
39import Gauge
40import Streamly.Benchmark.Common
40import Streamly.Benchmark.Common
benchmark/Streamly/Benchmark/Data/Fold/Window.hs+11−8
@@ -4,25 +4,25 @@ module Main (main) where
4
4
5import Control.DeepSeq (NFData)
5import Control.DeepSeq (NFData)
6import Streamly.Data.Fold (Fold)
6import Streamly.Data.Fold (Fold)
7−import Streamly.Internal.Data.Stream (Stream)
7+import Streamly.Internal.Data.Stream.StreamD (Stream)
8import System.Random (randomRIO)
8import System.Random (randomRIO)
9
9
10import qualified Streamly.Data.Fold as Fold
10import qualified Streamly.Data.Fold as Fold
11import qualified Streamly.Internal.Data.Ring.Unboxed as Ring
11import qualified Streamly.Internal.Data.Ring.Unboxed as Ring
12−import qualified Streamly.Prelude as Stream
13import qualified Streamly.Internal.Data.Fold.Window as Window
12import qualified Streamly.Internal.Data.Fold.Window as Window
13+import qualified Streamly.Internal.Data.Stream.StreamD as Stream
14
14
15import Gauge
15import Gauge
16
16
17{-# INLINE source #-}
17{-# INLINE source #-}
18−source :: (Monad m, Stream.IsStream t, Num a, Stream.Enumerable a) =>
18+source :: (Monad m, Num a, Stream.Enumerable a) =>
19− Int -> a -> t m a
19+ Int -> a -> Stream m a
20source len from =
20source len from =
21 Stream.enumerateFromThenTo from (from + 1) (from + fromIntegral len)
21 Stream.enumerateFromThenTo from (from + 1) (from + fromIntegral len)
22
22
23{-# INLINE sourceDescending #-}
23{-# INLINE sourceDescending #-}
24−sourceDescending :: (Monad m, Stream.IsStream t, Num a, Stream.Enumerable a) =>
24+sourceDescending :: (Monad m, Num a, Stream.Enumerable a) =>
25− Int -> a -> t m a
25+ Int -> a -> Stream m a
26sourceDescending len from =
26sourceDescending len from =
27 Stream.enumerateFromThenTo
27 Stream.enumerateFromThenTo
28 (from + fromIntegral len)
28 (from + fromIntegral len)
@@ -30,7 +30,7 @@ sourceDescending len from =
30 from
30 from
31
31
32{-# INLINE sourceDescendingInt #-}
32{-# INLINE sourceDescendingInt #-}
33−sourceDescendingInt :: (Monad m, Stream.IsStream t) => Int -> Int -> t m Int
33+sourceDescendingInt :: Monad m => Int -> Int -> Stream m Int
34sourceDescendingInt = sourceDescending
34sourceDescendingInt = sourceDescending
35
35
36{-# INLINE benchWith #-}
36{-# INLINE benchWith #-}
@@ -56,7 +56,10 @@ benchScanWith src len name f =
56 bench name
56 bench name
57 $ nfIO
57 $ nfIO
58 $ randomRIO (1, 1 :: Int)
58 $ randomRIO (1, 1 :: Int)
59+ >>= Stream.fold Fold.drain
59− >>= Stream.drain . Stream.postscan f . src len . fromIntegral
60+ . Stream.postscan f
61+ . src len
62+ . fromIntegral
60
63
61{-# INLINE benchWithPostscan #-}
64{-# INLINE benchWithPostscan #-}
62benchWithPostscan :: Int -> String -> Fold IO Double a -> Benchmark
65benchWithPostscan :: Int -> String -> Fold IO Double a -> Benchmark
benchmark/Streamly/Benchmark/Data/Parser.hs+4−15
@@ -20,13 +20,13 @@ module Main
20import Control.DeepSeq (NFData(..))
20import Control.DeepSeq (NFData(..))
21import Data.Foldable (asum)
21import Data.Foldable (asum)
22import Data.Functor (($>))
22import Data.Functor (($>))
23−import Data.Maybe (fromMaybe)
24import Data.Monoid (Sum(..))
23import Data.Monoid (Sum(..))
25import GHC.Magic (inline)
24import GHC.Magic (inline)
26import GHC.Magic (noinline)
25import GHC.Magic (noinline)
27import System.IO (Handle)
26import System.IO (Handle)
28import System.Random (randomRIO)
27import System.Random (randomRIO)
29import Streamly.Internal.Data.Parser (ParseError(..))
28import Streamly.Internal.Data.Parser (ParseError(..))
29+import Streamly.Internal.Data.Stream.StreamD (Stream)
30import Prelude hiding
30import Prelude hiding
31 (any, all, take, sequence, sequence_, sequenceA, takeWhile, dropWhile)
31 (any, all, take, sequence, sequence_, sequenceA, takeWhile, dropWhile)
32
32
@@ -37,13 +37,12 @@ import qualified Streamly.FileSystem.Handle as Handle
37import qualified Streamly.Internal.Data.Array as Array
37import qualified Streamly.Internal.Data.Array as Array
38import qualified Streamly.Internal.Data.Fold as Fold
38import qualified Streamly.Internal.Data.Fold as Fold
39import qualified Streamly.Internal.Data.Parser as PR
39import qualified Streamly.Internal.Data.Parser as PR
40−import qualified Streamly.Internal.Data.Stream as Stream
40+import qualified Streamly.Data.Stream as Stream
41−import qualified Streamly.Internal.Data.Stream.IsStream as IsStream (tail)
42import qualified Streamly.Internal.Data.Producer as Producer
41import qualified Streamly.Internal.Data.Producer as Producer
43import qualified Streamly.Internal.Data.Producer.Source as Source
42import qualified Streamly.Internal.Data.Producer.Source as Source
43+import qualified Streamly.Internal.Data.Stream.StreamD as Stream
44
44
45import Gauge hiding (env)
45import Gauge hiding (env)
46−import Streamly.Internal.Data.Stream (Stream)
47import Streamly.Benchmark.Common
46import Streamly.Benchmark.Common
48import Streamly.Benchmark.Common.Handle
47import Streamly.Benchmark.Common.Handle
49
48
@@ -141,8 +140,7 @@ dropWhile value = Stream.parse (PR.dropWhile (<= value))
141{-# INLINE takeStartBy #-}
140{-# INLINE takeStartBy #-}
142takeStartBy :: Monad m => Int -> Stream m Int -> m (Either ParseError ())
141takeStartBy :: Monad m => Int -> Stream m Int -> m (Either ParseError ())
143takeStartBy value stream = do
142takeStartBy value stream = do
144− stream1 <- return . fromMaybe (Stream.fromPure (value + 1)) =<< IsStream.tail stream
145− let stream2 = value `Stream.cons` stream1
143+ let stream2 = value `Stream.cons` stream
146 Stream.parse (PR.takeStartBy (== value) Fold.drain) stream2
144 Stream.parse (PR.takeStartBy (== value) Fold.drain) stream2
147
145
148takeFramedByEsc_ :: Monad m => Int -> Stream m Char -> m (Either ParseError ())
146takeFramedByEsc_ :: Monad m => Int -> Stream m Char -> m (Either ParseError ())
@@ -429,14 +427,6 @@ parseIterate n =
429 (Sum 0)
427 (Sum 0)
430 . fmap Sum
428 . fmap Sum
431
429
432−{-# INLINE parseBreak #-}
433−parseBreak :: Monad m => Stream m Int -> m ()
434−parseBreak s = do
435− r <- Stream.parseBreak PR.one s
436− case r of
437− (Left _, _) -> return ()
438− (Right _, s1) -> parseBreak s1
439−
440{-# INLINE concatSequence #-}
430{-# INLINE concatSequence #-}
441concatSequence :: Monad m => Stream m Int -> m (Either ParseError ())
431concatSequence :: Monad m => Stream m Int -> m (Either ParseError ())
442concatSequence = Stream.parse $ PR.concatSequence Fold.drain $ Stream.repeat PR.one
432concatSequence = Stream.parse $ PR.concatSequence Fold.drain $ Stream.repeat PR.one
@@ -490,7 +480,6 @@ o_1_space_serial value =
490 , benchIOSink value "shortest" $ shortestAllAny value
480 , benchIOSink value "shortest" $ shortestAllAny value
491 , benchIOSink value "longest" $ longestAllAny value
481 , benchIOSink value "longest" $ longestAllAny value
492 -}
482 -}
493− , benchIOSink value "parseBreak (recursive)" parseBreak
494 , benchIOSink value "parseMany (take 1)" (parseMany 1)
483 , benchIOSink value "parseMany (take 1)" (parseMany 1)
495 , benchIOSink value "parseMany (take all)" (parseMany value)
484 , benchIOSink value "parseMany (take all)" (parseMany value)
496 , benchIOSink value "parseIterate (take 1)" (parseIterate 1)
485 , benchIOSink value "parseIterate (take 1)" (parseIterate 1)
benchmark/Streamly/Benchmark/Data/Parser/ParserD.hs+8−9
@@ -21,9 +21,8 @@ import Control.DeepSeq (NFData(..))
21import Data.Foldable (asum)
21import Data.Foldable (asum)
22import Data.Function ((&))
22import Data.Function ((&))
23import Data.Functor (($>))
23import Data.Functor (($>))
24−import Data.Maybe (fromMaybe)
25−import Streamly.Internal.Data.Stream (Stream)
26import Streamly.Internal.Data.Parser (ParseError(..))
24import Streamly.Internal.Data.Parser (ParseError(..))
25+import Streamly.Internal.Data.Stream.StreamD (Stream)
27import System.Random (randomRIO)
26import System.Random (randomRIO)
28import Prelude hiding (any, all, take, sequence, sequenceA, sequence_, takeWhile, span)
27import Prelude hiding (any, all, take, sequence, sequenceA, sequence_, takeWhile, span)
29
28
@@ -35,9 +34,8 @@ import qualified Streamly.Internal.Data.Fold as Fold
35import qualified Streamly.Internal.Data.Parser.ParserD as PR
34import qualified Streamly.Internal.Data.Parser.ParserD as PR
36import qualified Streamly.Internal.Data.Producer as Producer
35import qualified Streamly.Internal.Data.Producer as Producer
37import qualified Streamly.Internal.Data.Producer.Source as Source
36import qualified Streamly.Internal.Data.Producer.Source as Source
38−import qualified Streamly.Internal.Data.Stream as Stream
37+import qualified Streamly.Data.Stream as Stream
39−import qualified Streamly.Internal.Data.Stream.IsStream as IsStream (tail)
40−import qualified Streamly.Internal.Data.Stream.StreamD as D
38+import qualified Streamly.Internal.Data.Stream.StreamD as Stream
41
39
42import Gauge
40import Gauge
43import Streamly.Benchmark.Common
41import Streamly.Benchmark.Common
@@ -75,7 +73,7 @@ listEqBy len = Stream.parseD (PR.listEqBy (==) [1 .. len])
75
73
76{-# INLINE streamEqBy #-}
74{-# INLINE streamEqBy #-}
77streamEqBy :: Int -> Stream IO Int -> IO (Either ParseError ())
75streamEqBy :: Int -> Stream IO Int -> IO (Either ParseError ())
78−streamEqBy len = Stream.parseD (PR.streamEqBy (==) (D.enumerateFromToIntegral 1 len))
76+streamEqBy len = Stream.parseD (PR.streamEqBy (==) (Stream.enumerateFromToIntegral 1 len))
79
77
80{-# INLINE drainWhile #-}
78{-# INLINE drainWhile #-}
81drainWhile :: Monad m => (a -> Bool) -> PR.Parser a m ()
79drainWhile :: Monad m => (a -> Bool) -> PR.Parser a m ()
@@ -84,8 +82,7 @@ drainWhile p = PR.takeWhile p Fold.drain
84{-# INLINE takeStartBy #-}
82{-# INLINE takeStartBy #-}
85takeStartBy :: Monad m => Int -> Stream m Int -> m (Either ParseError ())
83takeStartBy :: Monad m => Int -> Stream m Int -> m (Either ParseError ())
86takeStartBy value stream = do
84takeStartBy value stream = do
87− stream1 <- return . fromMaybe (Stream.fromPure (value + 1)) =<< IsStream.tail stream
88− let stream2 = value `Stream.cons` stream1
85+ let stream2 = value `Stream.cons` stream
89 Stream.parseD (PR.takeStartBy (== value) Fold.drain) stream2
86 Stream.parseD (PR.takeStartBy (== value) Fold.drain) stream2
90
87
91{-# INLINE takeWhile #-}
88{-# INLINE takeWhile #-}
@@ -202,7 +199,9 @@ longestAllAny value =
202
199
203{-# INLINE sequenceParser #-}
200{-# INLINE sequenceParser #-}
204sequenceParser :: Monad m => Stream m Int -> m (Either ParseError ())
201sequenceParser :: Monad m => Stream m Int -> m (Either ParseError ())
202+sequenceParser =
203+ Stream.parseD
205−sequenceParser = Stream.parseD (PR.sequence (D.repeat (PR.satisfy $ const True)) Fold.drain)
204+ (PR.sequence (Stream.repeat (PR.satisfy $ const True)) Fold.drain)
206
205
207-------------------------------------------------------------------------------
206-------------------------------------------------------------------------------
208-- Spanning
207-- Spanning
benchmark/Streamly/Benchmark/Data/Parser/ParserK.hs+3−3
@@ -17,7 +17,7 @@ module Main
17import Control.DeepSeq (NFData(..))
17import Control.DeepSeq (NFData(..))
18import Data.Foldable (asum)
18import Data.Foldable (asum)
19import Streamly.Internal.Data.Parser (ParseError(..))
19import Streamly.Internal.Data.Parser (ParseError(..))
20−import Streamly.Internal.Data.Stream (Stream)
20+import Streamly.Internal.Data.Stream.StreamD (Stream)
21import System.Random (randomRIO)
21import System.Random (randomRIO)
22import Prelude hiding (any, all, take, sequence, sequenceA, takeWhile)
22import Prelude hiding (any, all, take, sequence, sequenceA, takeWhile)
23
23
@@ -27,7 +27,7 @@ import qualified Data.Traversable as TR
27import qualified Streamly.Internal.Data.Fold as FL
27import qualified Streamly.Internal.Data.Fold as FL
28import qualified Streamly.Internal.Data.Parser.ParserK.Type as PR
28import qualified Streamly.Internal.Data.Parser.ParserK.Type as PR
29import qualified Streamly.Internal.Data.Parser.ParserD as PRD
29import qualified Streamly.Internal.Data.Parser.ParserD as PRD
30−import qualified Streamly.Internal.Data.Stream as Stream
30+import qualified Streamly.Internal.Data.Stream.StreamD as Stream
31
31
32import Gauge
32import Gauge
33import Streamly.Benchmark.Common
33import Streamly.Benchmark.Common
@@ -62,7 +62,7 @@ benchIOSink value name f =
62#ifdef FROM_PARSERK
62#ifdef FROM_PARSERK
63#define PARSE_OP (Stream.parseD . PRD.fromParserK)
63#define PARSE_OP (Stream.parseD . PRD.fromParserK)
64#else
64#else
65−#define PARSE_OP Stream.parseK
65+#define PARSE_OP Stream.parse
66#endif
66#endif
67
67
68{-# INLINE satisfy #-}
68{-# INLINE satisfy #-}
benchmark/Streamly/Benchmark/Data/Stream.hs+8
@@ -14,7 +14,9 @@ module Main (main) where
14import Streamly.Benchmark.Common.Handle (mkHandleBenchEnv)
14import Streamly.Benchmark.Common.Handle (mkHandleBenchEnv)
15
15
16import qualified Stream.Eliminate as Elimination
16import qualified Stream.Eliminate as Elimination
17+#ifndef USE_STREAMLY_CORE
17import qualified Stream.Exceptions as Exceptions
18import qualified Stream.Exceptions as Exceptions
19+#endif
18import qualified Stream.Expand as NestedStream
20import qualified Stream.Expand as NestedStream
19import qualified Stream.Generate as Generation
21import qualified Stream.Generate as Generation
20import qualified Stream.Lift as Lift
22import qualified Stream.Lift as Lift
@@ -27,7 +29,11 @@ import qualified Stream.Transform as Transformation
27import Streamly.Benchmark.Common
29import Streamly.Benchmark.Common
28
30
29moduleName :: String
31moduleName :: String
32+#ifdef USE_STREAMK
33+moduleName = "Data.Stream.StreamDK"
34+#else
30moduleName = "Data.Stream"
35moduleName = "Data.Stream"
36+#endif
31
37
32-------------------------------------------------------------------------------
38-------------------------------------------------------------------------------
33-- Main
39-- Main
@@ -46,7 +52,9 @@ main = do
46 allBenchmarks env size = Prelude.concat
52 allBenchmarks env size = Prelude.concat
47 [ Generation.benchmarks moduleName size
53 [ Generation.benchmarks moduleName size
48 , Elimination.benchmarks moduleName size
54 , Elimination.benchmarks moduleName size
55+#ifndef USE_STREAMLY_CORE
49 , Exceptions.benchmarks moduleName env size
56 , Exceptions.benchmarks moduleName env size
57+#endif
50#ifdef USE_PRELUDE
58#ifdef USE_PRELUDE
51 , Split.benchmarks moduleName env
59 , Split.benchmarks moduleName env
52#endif
60#endif
benchmark/Streamly/Benchmark/Data/Stream/Common.hs+122−62
@@ -16,6 +16,9 @@
16module Stream.Common
16module Stream.Common
17 ( MonadAsync
17 ( MonadAsync
18
18
19+ , fromStream
20+ , toStream
21+
19 -- Generation
22 -- Generation
20 , fromListM
23 , fromListM
21 , fromFoldableM
24 , fromFoldableM
@@ -41,8 +44,10 @@ module Stream.Common
41 , benchIO
44 , benchIO
42
45
43 -- Benchmarking functions
46 -- Benchmarking functions
47+#ifdef USE_STREAMK
44 , concatStreamsWith
48 , concatStreamsWith
45 , mergeMapWith
49 , mergeMapWith
50+#endif
46 , apDiscardFst
51 , apDiscardFst
47 , apDiscardSnd
52 , apDiscardSnd
48 , apLiftA2
53 , apLiftA2
@@ -70,8 +75,6 @@ import Control.Applicative (liftA2)
70import Control.DeepSeq (NFData)
75import Control.DeepSeq (NFData)
71import Control.Exception (try)
76import Control.Exception (try)
72import GHC.Exception (ErrorCall)
77import GHC.Exception (ErrorCall)
73−import Streamly.Internal.Data.Stream (Stream)
74−import Streamly.Internal.Data.Stream.Cross (CrossStream(..))
75import System.Random (randomRIO)
78import System.Random (randomRIO)
76
79
77import qualified Streamly.Internal.Data.Fold as Fold
80import qualified Streamly.Internal.Data.Fold as Fold
@@ -81,42 +84,97 @@ import qualified Streamly.Internal.Data.Pipe as Pipe
81import Streamly.Prelude (foldl', scanl')
84import Streamly.Prelude (foldl', scanl')
82import qualified Streamly.Internal.Data.Stream.IsStream as Stream
85import qualified Streamly.Internal.Data.Stream.IsStream as Stream
83import qualified Streamly.Prelude as Stream
86import qualified Streamly.Prelude as Stream
87+import qualified Streamly.Prelude as StreamK
84import Streamly.Benchmark.Prelude
88import Streamly.Benchmark.Prelude
85 ( composeN, sourceConcatMapId, benchIOSink
89 ( composeN, sourceConcatMapId, benchIOSink
86− , concatStreamsWith, mergeMapWith
90+ , concatStreamsWith
87 )
91 )
88#else
92#else
93+import Streamly.Internal.Data.Stream.StreamD (Stream)
89−import qualified Streamly.Internal.Data.Stream as Stream
94+import qualified Streamly.Internal.Data.Stream.StreamD as D
95+#ifdef USE_STREAMK
96+import Streamly.Internal.Data.Stream.StreamK (StreamK)
97+import qualified Streamly.Internal.Data.Stream.StreamD as Stream
98+import qualified Streamly.Internal.Data.Stream.StreamK as StreamK
99+#else
100+import qualified Streamly.Internal.Data.Stream.StreamD as Stream
101+import qualified Streamly.Internal.Data.Stream.StreamD as StreamK
102+#endif
90#endif
103#endif
91
104
92import Gauge
105import Gauge
93import Prelude hiding (mapM, replicate)
106import Prelude hiding (mapM, replicate)
94
107
108+#ifdef USE_STREAMK
109+toStream :: Applicative m => StreamK m a -> Stream m a
110+toStream = StreamK.toStream
111+
112+fromStream :: Monad m => Stream m a -> StreamK m a
113+fromStream = StreamK.fromStream
114+#else
115+fromStream :: a -> a
116+fromStream = id
117+
118+toStream :: a -> a
119+toStream = id
120+#endif
121+
95#ifdef USE_PRELUDE
122#ifdef USE_PRELUDE
123+type Stream = Stream.SerialT
96type MonadAsync m = Stream.MonadAsync m
124type MonadAsync m = Stream.MonadAsync m
125+mkCross = id
126+unCross = id
97#else
127#else
98type MonadAsync = Monad
128type MonadAsync = Monad
129+
130+#ifdef USE_STREAMK
131+mkCross :: StreamK.Stream m a -> StreamK.CrossStreamK m a
132+mkCross = StreamK.mkCross
133+
134+unCross :: StreamK.CrossStreamK m a -> StreamK.Stream m a
135+unCross = StreamK.unCross
136+#else
137+mkCross :: Stream m a -> Stream.CrossStream m a
138+mkCross = Stream.mkCross
139+
140+unCross :: Stream.CrossStream m a -> Stream m a
141+unCross = Stream.unCross
142+#endif
99#endif
143#endif
100
144
101−{-# INLINE append #-}
102−append :: Stream m a -> Stream m a -> Stream m a
103#ifdef USE_PRELUDE
145#ifdef USE_PRELUDE
146+{-# INLINE append #-}
147+append :: Monad m => Stream m a -> Stream m a -> Stream m a
104append = Stream.serial
148append = Stream.serial
105#else
149#else
150+#ifdef USE_STREAMK
151+append :: StreamK m a -> StreamK m a -> StreamK m a
152+append = StreamK.append
153+#else
154+append :: Monad m => Stream m a -> Stream m a -> Stream m a
106append = Stream.append
155append = Stream.append
107#endif
156#endif
157+#endif
108
158
109{-# INLINE append2 #-}
159{-# INLINE append2 #-}
110append2 :: Monad m => Stream m a -> Stream m a -> Stream m a
160append2 :: Monad m => Stream m a -> Stream m a -> Stream m a
111#ifdef USE_PRELUDE
161#ifdef USE_PRELUDE
112append2 = Stream.append
162append2 = Stream.append
113#else
163#else
114−append2 = Stream.append2
164+append2 = D.append
115#endif
165#endif
116
166
117{-# INLINE drain #-}
167{-# INLINE drain #-}
118drain :: Monad m => Stream m a -> m ()
168drain :: Monad m => Stream m a -> m ()
169+{-# INLINE toList #-}
170+toList :: Monad m => Stream m a -> m [a]
171+#ifdef USE_PRELUDE
172+drain = Stream.drain
173+toList = Stream.toList
174+#else
119drain = Stream.fold Fold.drain
175drain = Stream.fold Fold.drain
176+toList = Stream.fold Fold.toList
177+#endif
120
178
121{-# INLINE fromListM #-}
179{-# INLINE fromListM #-}
122fromListM :: MonadAsync m => [m a] -> Stream m a
180fromListM :: MonadAsync m => [m a] -> Stream m a
@@ -131,7 +189,7 @@ fromFoldableM :: MonadAsync m => [m a] -> Stream m a
131#ifdef USE_PRELUDE
189#ifdef USE_PRELUDE
132fromFoldableM = Stream.fromFoldableM
190fromFoldableM = Stream.fromFoldableM
133#else
191#else
134−fromFoldableM = Stream.sequence . Stream.fromFoldable
192+fromFoldableM = Stream.sequence . toStream . StreamK.fromFoldable
135#endif
193#endif
136
194
137{-# INLINE sourceUnfoldrM #-}
195{-# INLINE sourceUnfoldrM #-}
@@ -168,8 +226,8 @@ sourceUnfoldrAction value n = Stream.unfoldr step n
168 else Just (return cnt, cnt + 1)
226 else Just (return cnt, cnt + 1)
169
227
170{-# INLINE sourceFromFoldable #-}
228{-# INLINE sourceFromFoldable #-}
171−sourceFromFoldable :: Int -> Int -> Stream m Int
229+sourceFromFoldable :: Monad m => Int -> Int -> Stream m Int
172−sourceFromFoldable value n = Stream.fromFoldable [n..n+value]
230+sourceFromFoldable value n = toStream $ StreamK.fromFoldable [n..n+value]
173
231
174#ifndef USE_PRELUDE
232#ifndef USE_PRELUDE
175{-# INLINE benchIOSink #-}
233{-# INLINE benchIOSink #-}
@@ -194,43 +252,45 @@ benchIO :: (NFData b) => String -> (Int -> IO b) -> Benchmark
194benchIO name f = bench name $ nfIO $ randomRIO (1,1) >>= f
252benchIO name f = bench name $ nfIO $ randomRIO (1,1) >>= f
195
253
196#ifndef USE_PRELUDE
254#ifndef USE_PRELUDE
255+#ifdef USE_STREAMK
197{-# INLINE concatStreamsWith #-}
256{-# INLINE concatStreamsWith #-}
198concatStreamsWith
257concatStreamsWith
199− :: (Stream IO Int -> Stream IO Int -> Stream IO Int)
258+ :: (StreamK IO Int -> StreamK IO Int -> StreamK IO Int)
200 -> Int
259 -> Int
201 -> Int
260 -> Int
202 -> Int
261 -> Int
203 -> IO ()
262 -> IO ()
204concatStreamsWith op outer inner n =
263concatStreamsWith op outer inner n =
205− drain $ Stream.concatMapWith op
264+ drain $ toStream $ StreamK.concatMapWith op
206− (sourceUnfoldrM inner)
265+ (fromStream . sourceUnfoldrM inner)
207− (sourceUnfoldrM outer n)
266+ (fromStream $ sourceUnfoldrM outer n)
208
267
209{-# INLINE mergeMapWith #-}
268{-# INLINE mergeMapWith #-}
210mergeMapWith
269mergeMapWith
211− :: (Stream IO Int -> Stream IO Int -> Stream IO Int)
270+ :: (StreamK IO Int -> StreamK IO Int -> StreamK IO Int)
212 -> Int
271 -> Int
213 -> Int
272 -> Int
214 -> Int
273 -> Int
215 -> IO ()
274 -> IO ()
216mergeMapWith op outer inner n =
275mergeMapWith op outer inner n =
217− drain $ Stream.mergeMapWith op
276+ drain $ toStream $ StreamK.mergeMapWith op
218− (sourceUnfoldrM inner)
277+ (fromStream . sourceUnfoldrM inner)
219− (sourceUnfoldrM outer n)
278+ (fromStream $ sourceUnfoldrM outer n)
279+#endif
220
280
221{-# INLINE sourceConcatMapId #-}
281{-# INLINE sourceConcatMapId #-}
222sourceConcatMapId :: (Monad m)
282sourceConcatMapId :: (Monad m)
223 => Int -> Int -> Stream m (Stream m Int)
283 => Int -> Int -> Stream m (Stream m Int)
224sourceConcatMapId value n =
284sourceConcatMapId value n =
225− Stream.fromFoldable $ fmap (Stream.fromEffect . return) [n..n+value]
285+ Stream.fromList $ fmap (D.fromEffect . return) [n..n+value]
226#endif
286#endif
227
287
228{-# INLINE apDiscardFst #-}
288{-# INLINE apDiscardFst #-}
229apDiscardFst :: MonadAsync m =>
289apDiscardFst :: MonadAsync m =>
230 Int -> Int -> m ()
290 Int -> Int -> m ()
231−apDiscardFst linearCount start = drain $ unCrossStream $
291+apDiscardFst linearCount start = drain $ toStream $ unCross $
232− CrossStream (sourceUnfoldrM nestedCount2 start)
292+ mkCross (fromStream $ sourceUnfoldrM nestedCount2 start)
233− *> CrossStream (sourceUnfoldrM nestedCount2 start)
293+ *> mkCross (fromStream $ sourceUnfoldrM nestedCount2 start)
234
294
235 where
295 where
236
296
@@ -238,9 +298,9 @@ apDiscardFst linearCount start = drain $ unCrossStream $
238
298
239{-# INLINE apDiscardSnd #-}
299{-# INLINE apDiscardSnd #-}
240apDiscardSnd :: MonadAsync m => Int -> Int -> m ()
300apDiscardSnd :: MonadAsync m => Int -> Int -> m ()
241−apDiscardSnd linearCount start = drain $ unCrossStream $
301+apDiscardSnd linearCount start = drain $ toStream $ unCross $
242− CrossStream (sourceUnfoldrM nestedCount2 start)
302+ mkCross (fromStream $ sourceUnfoldrM nestedCount2 start)
243− <* CrossStream (sourceUnfoldrM nestedCount2 start)
303+ <* mkCross (fromStream $ sourceUnfoldrM nestedCount2 start)
244
304
245 where
305 where
246
306
@@ -248,9 +308,9 @@ apDiscardSnd linearCount start = drain $ unCrossStream $
248
308
249{-# INLINE apLiftA2 #-}
309{-# INLINE apLiftA2 #-}
250apLiftA2 :: MonadAsync m => Int -> Int -> m ()
310apLiftA2 :: MonadAsync m => Int -> Int -> m ()
251−apLiftA2 linearCount start = drain $ unCrossStream $
311+apLiftA2 linearCount start = drain $ toStream $ unCross $
252− liftA2 (+) (CrossStream (sourceUnfoldrM nestedCount2 start))
312+ liftA2 (+) (mkCross (fromStream $ sourceUnfoldrM nestedCount2 start))
253− (CrossStream (sourceUnfoldrM nestedCount2 start))
313+ (mkCross (fromStream $ sourceUnfoldrM nestedCount2 start))
254
314
255 where
315 where
256
316
@@ -258,9 +318,9 @@ apLiftA2 linearCount start = drain $ unCrossStream $
258
318
259{-# INLINE toNullAp #-}
319{-# INLINE toNullAp #-}
260toNullAp :: MonadAsync m => Int -> Int -> m ()
320toNullAp :: MonadAsync m => Int -> Int -> m ()
261−toNullAp linearCount start = drain $ unCrossStream $
321+toNullAp linearCount start = drain $ toStream $ unCross $
262− (+) <$> CrossStream (sourceUnfoldrM nestedCount2 start)
322+ (+) <$> mkCross (fromStream $ sourceUnfoldrM nestedCount2 start)
263− <*> CrossStream (sourceUnfoldrM nestedCount2 start)
323+ <*> mkCross (fromStream $ sourceUnfoldrM nestedCount2 start)
264
324
265 where
325 where
266
326
@@ -268,9 +328,9 @@ toNullAp linearCount start = drain $ unCrossStream $
268
328
269{-# INLINE monadThen #-}
329{-# INLINE monadThen #-}
270monadThen :: MonadAsync m => Int -> Int -> m ()
330monadThen :: MonadAsync m => Int -> Int -> m ()
271−monadThen linearCount start = drain $ unCrossStream $ do
331+monadThen linearCount start = drain $ toStream $ unCross $ do
272− CrossStream (sourceUnfoldrM nestedCount2 start) >>
332+ mkCross (fromStream $ sourceUnfoldrM nestedCount2 start) >>
273− CrossStream (sourceUnfoldrM nestedCount2 start)
333+ mkCross (fromStream $ sourceUnfoldrM nestedCount2 start)
274
334
275 where
335 where
276
336
@@ -278,9 +338,9 @@ monadThen linearCount start = drain $ unCrossStream $ do
278
338
279{-# INLINE toNullM #-}
339{-# INLINE toNullM #-}
280toNullM :: MonadAsync m => Int -> Int -> m ()
340toNullM :: MonadAsync m => Int -> Int -> m ()
281−toNullM linearCount start = drain $ unCrossStream $ do
341+toNullM linearCount start = drain $ toStream $ unCross $ do
282− x <- CrossStream (sourceUnfoldrM nestedCount2 start)
342+ x <- mkCross (fromStream $ sourceUnfoldrM nestedCount2 start)
283− y <- CrossStream (sourceUnfoldrM nestedCount2 start)
343+ y <- mkCross (fromStream $ sourceUnfoldrM nestedCount2 start)
284 return $ x + y
344 return $ x + y
285
345
286 where
346 where
@@ -289,56 +349,56 @@ toNullM linearCount start = drain $ unCrossStream $ do
289
349
290{-# INLINE toNullM3 #-}
350{-# INLINE toNullM3 #-}
291toNullM3 :: MonadAsync m => Int -> Int -> m ()
351toNullM3 :: MonadAsync m => Int -> Int -> m ()
292−toNullM3 linearCount start = drain $ unCrossStream $ do
352+toNullM3 linearCount start = drain $ toStream $ unCross $ do
293− x <- CrossStream (sourceUnfoldrM nestedCount3 start)
353+ x <- mkCross (fromStream $ sourceUnfoldrM nestedCount3 start)
294− y <- CrossStream (sourceUnfoldrM nestedCount3 start)
354+ y <- mkCross (fromStream $ sourceUnfoldrM nestedCount3 start)
295− z <- CrossStream (sourceUnfoldrM nestedCount3 start)
355+ z <- mkCross (fromStream $ sourceUnfoldrM nestedCount3 start)
296 return $ x + y + z
356 return $ x + y + z
297 where
357 where
298 nestedCount3 = round (fromIntegral linearCount**(1/3::Double))
358 nestedCount3 = round (fromIntegral linearCount**(1/3::Double))
299
359
300{-# INLINE filterAllOutM #-}
360{-# INLINE filterAllOutM #-}
301filterAllOutM :: MonadAsync m => Int -> Int -> m ()
361filterAllOutM :: MonadAsync m => Int -> Int -> m ()
302−filterAllOutM linearCount start = drain $ unCrossStream $ do
362+filterAllOutM linearCount start = drain $ toStream $ unCross $ do
303− x <- CrossStream (sourceUnfoldrM nestedCount2 start)
363+ x <- mkCross (fromStream $ sourceUnfoldrM nestedCount2 start)
304− y <- CrossStream (sourceUnfoldrM nestedCount2 start)
364+ y <- mkCross (fromStream $ sourceUnfoldrM nestedCount2 start)
305 let s = x + y
365 let s = x + y
306 if s < 0
366 if s < 0
307 then return s
367 then return s
308− else CrossStream Stream.nil
368+ else mkCross StreamK.nil
309 where
369 where
310 nestedCount2 = round (fromIntegral linearCount**(1/2::Double))
370 nestedCount2 = round (fromIntegral linearCount**(1/2::Double))
311
371
312{-# INLINE filterAllInM #-}
372{-# INLINE filterAllInM #-}
313filterAllInM :: MonadAsync m => Int -> Int -> m ()
373filterAllInM :: MonadAsync m => Int -> Int -> m ()
314−filterAllInM linearCount start = drain $ unCrossStream $ do
374+filterAllInM linearCount start = drain $ toStream $ unCross $ do
315− x <- CrossStream (sourceUnfoldrM nestedCount2 start)
375+ x <- mkCross (fromStream $ sourceUnfoldrM nestedCount2 start)
316− y <- CrossStream (sourceUnfoldrM nestedCount2 start)
376+ y <- mkCross (fromStream $ sourceUnfoldrM nestedCount2 start)
317 let s = x + y
377 let s = x + y
318 if s > 0
378 if s > 0
319 then return s
379 then return s
320− else CrossStream Stream.nil
380+ else mkCross StreamK.nil
321 where
381 where
322 nestedCount2 = round (fromIntegral linearCount**(1/2::Double))
382 nestedCount2 = round (fromIntegral linearCount**(1/2::Double))
323
383
324{-# INLINE filterSome #-}
384{-# INLINE filterSome #-}
325filterSome :: MonadAsync m => Int -> Int -> m ()
385filterSome :: MonadAsync m => Int -> Int -> m ()
326−filterSome linearCount start = drain $ unCrossStream $ do
386+filterSome linearCount start = drain $ toStream $ unCross $ do
327− x <- CrossStream (sourceUnfoldrM nestedCount2 start)
387+ x <- mkCross (fromStream $ sourceUnfoldrM nestedCount2 start)
328− y <- CrossStream (sourceUnfoldrM nestedCount2 start)
388+ y <- mkCross (fromStream $ sourceUnfoldrM nestedCount2 start)
329 let s = x + y
389 let s = x + y
330 if s > 1100000
390 if s > 1100000
331 then return s
391 then return s
332− else CrossStream Stream.nil
392+ else mkCross StreamK.nil
333 where
393 where
334 nestedCount2 = round (fromIntegral linearCount**(1/2::Double))
394 nestedCount2 = round (fromIntegral linearCount**(1/2::Double))
335
395
336{-# INLINE breakAfterSome #-}
396{-# INLINE breakAfterSome #-}
337breakAfterSome :: Int -> Int -> IO ()
397breakAfterSome :: Int -> Int -> IO ()
338breakAfterSome linearCount start = do
398breakAfterSome linearCount start = do
339− (_ :: Either ErrorCall ()) <- try $ drain $ unCrossStream $ do
399+ (_ :: Either ErrorCall ()) <- try $ drain $ toStream $ unCross $ do
340− x <- CrossStream (sourceUnfoldrM nestedCount2 start)
400+ x <- mkCross (fromStream $ sourceUnfoldrM nestedCount2 start)
341− y <- CrossStream (sourceUnfoldrM nestedCount2 start)
401+ y <- mkCross (fromStream $ sourceUnfoldrM nestedCount2 start)
342 let s = x + y
402 let s = x + y
343 if s > 1100000
403 if s > 1100000
344 then error "break"
404 then error "break"
@@ -349,9 +409,9 @@ breakAfterSome linearCount start = do
349
409
350{-# INLINE toListM #-}
410{-# INLINE toListM #-}
351toListM :: MonadAsync m => Int -> Int -> m [Int]
411toListM :: MonadAsync m => Int -> Int -> m [Int]
352−toListM linearCount start = Stream.fold Fold.toList $ unCrossStream $ do
412+toListM linearCount start = toList $ toStream $ unCross $ do
353− x <- CrossStream (sourceUnfoldrM nestedCount2 start)
413+ x <- mkCross (fromStream $ sourceUnfoldrM nestedCount2 start)
354− y <- CrossStream (sourceUnfoldrM nestedCount2 start)
414+ y <- mkCross (fromStream $ sourceUnfoldrM nestedCount2 start)
355 return $ x + y
415 return $ x + y
356 where
416 where
357 nestedCount2 = round (fromIntegral linearCount**(1/2::Double))
417 nestedCount2 = round (fromIntegral linearCount**(1/2::Double))
@@ -361,9 +421,9 @@ toListM linearCount start = Stream.fold Fold.toList $ unCrossStream $ do
361{-# INLINE toListSome #-}
421{-# INLINE toListSome #-}
362toListSome :: MonadAsync m => Int -> Int -> m [Int]
422toListSome :: MonadAsync m => Int -> Int -> m [Int]
363toListSome linearCount start =
423toListSome linearCount start =
364− Stream.fold Fold.toList $ Stream.take 10000 $ unCrossStream $ do
424+ toList $ Stream.take 10000 $ toStream $ unCross $ do
365− x <- CrossStream (sourceUnfoldrM nestedCount2 start)
425+ x <- mkCross (fromStream $ sourceUnfoldrM nestedCount2 start)
366− y <- CrossStream (sourceUnfoldrM nestedCount2 start)
426+ y <- mkCross (fromStream $ sourceUnfoldrM nestedCount2 start)
367 return $ x + y
427 return $ x + y
368 where
428 where
369 nestedCount2 = round (fromIntegral linearCount**(1/2::Double))
429 nestedCount2 = round (fromIntegral linearCount**(1/2::Double))
benchmark/Streamly/Benchmark/Data/Stream/Eliminate.hs+56−38
@@ -32,39 +32,41 @@ import System.Random (randomRIO)
32
32
33import qualified Data.Foldable as F
33import qualified Data.Foldable as F
34import qualified GHC.Exts as GHC
34import qualified GHC.Exts as GHC
35+import qualified Streamly.Internal.Data.Fold as Fold
35
36
36#ifdef INSPECTION
37#ifdef INSPECTION
37import GHC.Types (SPEC(..))
38import GHC.Types (SPEC(..))
38import Test.Inspection
39import Test.Inspection
39−
40import qualified Streamly.Internal.Data.Stream.StreamD as D
40import qualified Streamly.Internal.Data.Stream.StreamD as D
41#endif
41#endif
42−import qualified Streamly.Internal.Data.Fold as Fold
43−#ifdef USE_PRELUDE
44−import qualified Streamly.Internal.Data.Stream.IsStream as S
45−#else
46−import qualified Streamly.Internal.Data.Stream as S
47−#endif
48
42
49−import Gauge
50−import Streamly.Internal.Data.Stream (Stream)
51#ifdef USE_PRELUDE
43#ifdef USE_PRELUDE
52import Streamly.Prelude (fromSerial)
44import Streamly.Prelude (fromSerial)
53import Streamly.Benchmark.Prelude
45import Streamly.Benchmark.Prelude
46+import qualified Streamly.Internal.Data.Stream.IsStream as S
47+import qualified Streamly.Internal.Data.Stream.IsStream as StreamK
54#else
48#else
55import Stream.Common
49import Stream.Common
56− ( sourceUnfoldr
50+import Streamly.Internal.Data.Stream.StreamD (Stream)
57− , sourceUnfoldrM
51+import qualified Streamly.Internal.Data.Stream.StreamD as S
58− , sourceUnfoldrAction
52+#ifdef USE_STREAMK
59− , benchIOSink
53+import Streamly.Internal.Data.Stream.StreamK (StreamK)
60− )
54+import qualified Streamly.Data.Stream.StreamK as StreamK
55+#else
56+import qualified Streamly.Internal.Data.Stream.StreamD as StreamK
61#endif
57#endif
58+#endif
59+
60+import Gauge
62import Streamly.Benchmark.Common
61import Streamly.Benchmark.Common
63import Prelude hiding (length, sum, or, and, any, all, notElem, elem, (!!),
62import Prelude hiding (length, sum, or, and, any, all, notElem, elem, (!!),
64 lookup, repeat, minimum, maximum, product, last, mapM_, init)
63 lookup, repeat, minimum, maximum, product, last, mapM_, init)
65import qualified Prelude
64import qualified Prelude
66
65
67#ifdef USE_PRELUDE
66#ifdef USE_PRELUDE
67+type Stream = S.SerialT
68+fromStream = id
69+
68{-# INLINE repeat #-}
70{-# INLINE repeat #-}
69repeat :: (Monad m, S.IsStream t) => Int -> Int -> t m Int
71repeat :: (Monad m, S.IsStream t) => Int -> Int -> t m Int
70repeat count = S.take count . S.repeat
72repeat count = S.take count . S.repeat
@@ -213,6 +215,9 @@ o_1_space_elimination_foldable value =
213 , bench "minimum" $ nf (foldableMin value) 1
215 , bench "minimum" $ nf (foldableMin value) 1
214 , benchPureSink value "min (ord)" ordInstanceMin
216 , benchPureSink value "min (ord)" ordInstanceMin
215 , bench "maximum" $ nf (foldableMax value) 1
217 , bench "maximum" $ nf (foldableMax value) 1
218+ , bench "minimumBy" $ nf (`foldableMinBy` 1) value
219+ , bench "maximumBy" $ nf (`foldableMaxBy` 1) value
220+ , bench "minimumByList" $ nf (`foldableListMinBy` 1) value
216 , bench "length . toList"
221 , bench "length . toList"
217 $ nf (Prelude.length . foldableToList value) 1
222 $ nf (Prelude.length . foldableToList value) 1
218 , bench "notElem" $ nf (foldableNotElem value) 1
223 , bench "notElem" $ nf (foldableNotElem value) 1
@@ -235,28 +240,15 @@ o_1_space_elimination_foldable value =
235 ]
240 ]
236 ]
241 ]
237
242
238−o_n_space_elimination_foldable :: Int -> [Benchmark]
239−o_n_space_elimination_foldable value =
240− -- Head recursive strict right folds.
241− [ bgroup "foldl"
242− -- XXX the definitions of minimumBy and maximumBy in Data.Foldable use
243− -- foldl1 which does not work in constant memory for our
244− -- implementation. It works in constant memory for lists but even for
245− -- lists it takes 15x more time compared to our foldl' based
246− -- implementation.
247− [ bench "minimumBy" $ nf (`foldableMinBy` 1) value
248− , bench "maximumBy" $ nf (`foldableMaxBy` 1) value
249− , bench "minimumByList" $ nf (`foldableListMinBy` 1) value
250− ]
251− ]
252−
253-------------------------------------------------------------------------------
243-------------------------------------------------------------------------------
254-- Stream folds
244-- Stream folds
255-------------------------------------------------------------------------------
245-------------------------------------------------------------------------------
256
246
247+#ifndef USE_PRELUDE
257instance NFData a => NFData (Stream Identity a) where
248instance NFData a => NFData (Stream Identity a) where
258 {-# INLINE rnf #-}
249 {-# INLINE rnf #-}
259 rnf xs = runIdentity $ S.fold (Fold.foldl' (\_ x -> rnf x) ()) xs
250 rnf xs = runIdentity $ S.fold (Fold.foldl' (\_ x -> rnf x) ()) xs
251+#endif
260
252
261{-# INLINE benchPureSink #-}
253{-# INLINE benchPureSink #-}
262benchPureSink :: NFData b
254benchPureSink :: NFData b
@@ -283,9 +275,13 @@ benchIdentitySink value name f = bench name $ nf (f . sourceUnfoldr value) 1
283-------------------------------------------------------------------------------
275-------------------------------------------------------------------------------
284
276
285{-# INLINE uncons #-}
277{-# INLINE uncons #-}
278+#ifdef USE_STREAMK
279+uncons :: Monad m => StreamK m Int -> m ()
280+#else
286uncons :: Monad m => Stream m Int -> m ()
281uncons :: Monad m => Stream m Int -> m ()
282+#endif
287uncons s = do
283uncons s = do
288− r <- S.uncons s
284+ r <- StreamK.uncons s
289 case r of
285 case r of
290 Nothing -> return ()
286 Nothing -> return ()
291 Just (_, t) -> uncons t
287 Just (_, t) -> uncons t
@@ -310,9 +306,15 @@ foldrMElem e =
310 else xs)
306 else xs)
311 (return False)
307 (return False)
312
308
309+#ifdef USE_STREAMK
313{-# INLINE foldrToStream #-}
310{-# INLINE foldrToStream #-}
314−foldrToStream :: Monad m => Stream m Int -> m (Stream Identity Int)
311+foldrToStream :: Monad m => Stream m Int -> m (StreamK Identity Int)
312+foldrToStream = S.foldr StreamK.cons StreamK.nil
313+#else
314+-- {-# INLINE foldrToStream #-}
315+-- foldrToStream :: Monad m => Stream m Int -> m (Stream Identity Int)
315−foldrToStream = S.foldr S.cons S.nil
316+-- foldrToStream = S.foldr S.cons S.nil
317+#endif
316
318
317{-# INLINE foldrMBuild #-}
319{-# INLINE foldrMBuild #-}
318foldrMBuild :: Monad m => Stream m Int -> m [Int]
320foldrMBuild :: Monad m => Stream m Int -> m [Int]
@@ -456,17 +458,34 @@ o_1_space_elimination_folds value =
456 ]
458 ]
457 , bgroup "Identity"
459 , bgroup "Identity"
458 [ benchIdentitySink value "foldrMElem" (foldrMElem value)
460 [ benchIdentitySink value "foldrMElem" (foldrMElem value)
461+#ifdef USE_STREAMK
459 , benchIdentitySink value "foldrToStreamLength"
462 , benchIdentitySink value "foldrToStreamLength"
463+ (S.fold Fold.length . toStream . runIdentity . foldrToStream)
464+ {-
465+ , benchIdentitySink 16 "foldrToStreamLength (16)"
466+ (S.fold Fold.length . toStream . runIdentity . foldrToStream)
467+ -}
468+#else
469+ {-
470+ , benchIdentitySink 16 "foldrToStreamLength (16)"
460 (S.fold Fold.length . runIdentity . foldrToStream)
471 (S.fold Fold.length . runIdentity . foldrToStream)
472+ -}
473+#endif
474+ {-
475+ , benchPureSink 16 "foldrMToListLength (16)"
476+ (Prelude.length . runIdentity . foldrMBuild)
477+ -}
461 , benchPureSink value "foldrMToListLength"
478 , benchPureSink value "foldrMToListLength"
462 (Prelude.length . runIdentity . foldrMBuild)
479 (Prelude.length . runIdentity . foldrMBuild)
463 ]
480 ]
464 ]
481 ]
465
482
466 -- deconstruction
483 -- deconstruction
467− , benchIOSink value "uncons" uncons
484+ , benchIOSink value "uncons" (uncons . fromStream)
485+#ifndef USE_PRELUDE
468 , benchHoistSink value "length . generalizeInner"
486 , benchHoistSink value "length . generalizeInner"
469 (S.fold Fold.length . S.generalizeInner)
487 (S.fold Fold.length . S.generalizeInner)
488+#endif
470#ifdef USE_PRELUDE
489#ifdef USE_PRELUDE
471 , benchIOSink value "init" init
490 , benchIOSink value "init" init
472
491
@@ -587,8 +606,10 @@ o_n_space_elimination_toList value =
587 [ bgroup "toList"
606 [ bgroup "toList"
588 -- Converting the stream to a list or pure stream in a strict monad
607 -- Converting the stream to a list or pure stream in a strict monad
589 [ benchIOSink value "toList" S.toList
608 [ benchIOSink value "toList" S.toList
609+#ifndef USE_PRELUDE
590 , benchIOSink value "toStream"
610 , benchIOSink value "toStream"
591 (S.toStream :: (Stream IO Int -> IO (Stream Identity Int)))
611 (S.toStream :: (Stream IO Int -> IO (Stream Identity Int)))
612+#endif
592 ]
613 ]
593 ]
614 ]
594#endif
615#endif
@@ -718,11 +739,8 @@ benchmarks moduleName size =
718#ifdef USE_PRELUDE
739#ifdef USE_PRELUDE
719 ++ o_n_heap_elimination_foldl size
740 ++ o_n_heap_elimination_foldl size
720 ++ o_n_heap_elimination_toList size
741 ++ o_n_heap_elimination_toList size
721−#endif
722− , bgroup (o_n_space_prefix moduleName) $
723− o_n_space_elimination_foldable size
724−#ifdef USE_PRELUDE
725 ++ o_n_space_elimination_toList size
742 ++ o_n_space_elimination_toList size
726#endif
743#endif
744+ , bgroup (o_n_space_prefix moduleName) $
727− ++ o_n_space_elimination_foldr size
745+ o_n_space_elimination_foldr size
728 ]
746 ]
benchmark/Streamly/Benchmark/Data/Stream/Exceptions.hs+36−28
@@ -27,25 +27,21 @@ module Stream.Exceptions (benchmarks) where
27
27
28import Control.Exception (Exception, throwIO)
28import Control.Exception (Exception, throwIO)
29import Stream.Common (drain)
29import Stream.Common (drain)
30−import Streamly.Internal.Data.Stream (Stream)
31
30
32import qualified Data.IORef as Ref
31import qualified Data.IORef as Ref
33import qualified Data.Map.Strict as Map
32import qualified Data.Map.Strict as Map
34−import qualified Stream.Common as Common
35
33
36−#ifndef USE_STREAMLY_CORE
37import Control.Exception (SomeException)
34import Control.Exception (SomeException)
38import System.IO (Handle, hClose, hPutChar)
35import System.IO (Handle, hClose, hPutChar)
39import qualified Streamly.FileSystem.Handle as FH
36import qualified Streamly.FileSystem.Handle as FH
40import qualified Streamly.Internal.FileSystem.Handle as IFH
37import qualified Streamly.Internal.FileSystem.Handle as IFH
41import qualified Streamly.Internal.Data.Unfold as IUF
38import qualified Streamly.Internal.Data.Unfold as IUF
42import qualified Streamly.Internal.Data.Unfold.Exception as IUF
39import qualified Streamly.Internal.Data.Unfold.Exception as IUF
43−#endif
44
40
45#ifdef USE_PRELUDE
41#ifdef USE_PRELUDE
46import qualified Streamly.Internal.Data.Stream.IsStream as Stream
42import qualified Streamly.Internal.Data.Stream.IsStream as Stream
47#else
43#else
48−import qualified Streamly.Internal.Data.Stream as Stream
44+import qualified Streamly.Internal.Data.Stream.StreamD as Stream
49import qualified Streamly.Internal.Data.Stream.Exception.Lifted as Stream
45import qualified Streamly.Internal.Data.Stream.Exception.Lifted as Stream
50#endif
46#endif
51
47
@@ -60,18 +56,35 @@ import Test.Inspection
60import qualified Streamly.Internal.Data.Stream.StreamD as D
56import qualified Streamly.Internal.Data.Stream.StreamD as D
61#endif
57#endif
62
58
63−-------------------------------------------------------------------------------
59+#ifdef USE_PRELUDE
64−-- stream exceptions
60+type Stream = Stream.SerialT
65−-------------------------------------------------------------------------------
61+toStreamD = Stream.toStream
62+fromStreamD = Stream.fromStream
63+#else
64+type Stream = Stream.Stream
65+toStreamD :: a -> a
66+toStreamD = id
67+fromStreamD :: a -> a
68+fromStreamD = id
69+#endif
66
70
67−{-# INLINE replicateM #-}
71+afterUnsafe :: IO b -> Stream IO a -> Stream IO a
68−replicateM :: Common.MonadAsync m => Int -> m a -> Stream m a
72+finallyUnsafe :: IO b -> Stream IO a -> Stream IO a
73+bracketUnsafe :: IO b -> (b -> IO c) -> (b -> Stream IO a) -> Stream IO a
69#ifdef USE_PRELUDE
74#ifdef USE_PRELUDE
70−replicateM = Stream.replicateM
75+afterUnsafe = Stream.after_
76+finallyUnsafe = Stream.finally_
77+bracketUnsafe = Stream.bracket_
71#else
78#else
72−replicateM n = Stream.sequence . Stream.replicate n
79+afterUnsafe = Stream.afterUnsafe
80+finallyUnsafe = Stream.finallyUnsafe
81+bracketUnsafe = Stream.bracketUnsafe
73#endif
82#endif
74
83
84+-------------------------------------------------------------------------------
85+-- stream exceptions
86+-------------------------------------------------------------------------------
87+
75data BenchException
88data BenchException
76 = BenchException1
89 = BenchException1
77 | BenchException2
90 | BenchException2
@@ -101,7 +114,7 @@ retryNone length from = do
101 where
114 where
102
115
103 source ref =
116 source ref =
104− replicateM (from + length)
117+ Stream.replicateM (from + length)
105 $ Ref.modifyIORef' ref (+ 1) >> Ref.readIORef ref
118 $ Ref.modifyIORef' ref (+ 1) >> Ref.readIORef ref
106
119
107retryAll :: Int -> Int -> IO ()
120retryAll :: Int -> Int -> IO ()
@@ -146,7 +159,6 @@ o_1_space_serial_exceptions length =
146 ]
159 ]
147
160
148-- XXX Move these to FileSystem.Handle benchmarks
161-- XXX Move these to FileSystem.Handle benchmarks
149−#ifndef USE_STREAMLY_CORE
150
162
151-------------------------------------------------------------------------------
163-------------------------------------------------------------------------------
152-- copy stream exceptions
164-- copy stream exceptions
@@ -177,7 +189,7 @@ inspect $ hasNoTypeClasses 'readWriteHandleExceptionStream
177readWriteFinally_Stream :: Handle -> Handle -> IO ()
189readWriteFinally_Stream :: Handle -> Handle -> IO ()
178readWriteFinally_Stream inh devNull =
190readWriteFinally_Stream inh devNull =
179 let readEx =
191 let readEx =
180− Stream.finallyUnsafe (hClose inh) (Stream.unfold FH.reader inh)
192+ finallyUnsafe (hClose inh) (Stream.unfold FH.reader inh)
181 in Stream.fold (FH.write devNull) readEx
193 in Stream.fold (FH.write devNull) readEx
182
194
183#ifdef INSPECTION
195#ifdef INSPECTION
@@ -192,9 +204,9 @@ readWriteFinallyStream inh devNull =
192-- | Send the file contents to /dev/null with exception handling
204-- | Send the file contents to /dev/null with exception handling
193fromToBytesBracket_Stream :: Handle -> Handle -> IO ()
205fromToBytesBracket_Stream :: Handle -> Handle -> IO ()
194fromToBytesBracket_Stream inh devNull =
206fromToBytesBracket_Stream inh devNull =
195− let readEx = Stream.bracketUnsafe (return ()) (\_ -> hClose inh)
207+ let readEx = bracketUnsafe (return ()) (\_ -> hClose inh)
196− (\_ -> IFH.read inh)
208+ (\_ -> fromStreamD $ IFH.read inh)
197− in IFH.putBytes devNull readEx
209+ in IFH.putBytes devNull (toStreamD readEx)
198
210
199#ifdef INSPECTION
211#ifdef INSPECTION
200inspect $ hasNoTypeClasses 'fromToBytesBracket_Stream
212inspect $ hasNoTypeClasses 'fromToBytesBracket_Stream
@@ -203,8 +215,8 @@ inspect $ hasNoTypeClasses 'fromToBytesBracket_Stream
203fromToBytesBracketStream :: Handle -> Handle -> IO ()
215fromToBytesBracketStream :: Handle -> Handle -> IO ()
204fromToBytesBracketStream inh devNull =
216fromToBytesBracketStream inh devNull =
205 let readEx = Stream.bracket (return ()) (\_ -> hClose inh)
217 let readEx = Stream.bracket (return ()) (\_ -> hClose inh)
206− (\_ -> IFH.read inh)
218+ (\_ -> fromStreamD $ IFH.read inh)
207− in IFH.putBytes devNull readEx
219+ in IFH.putBytes devNull (toStreamD readEx)
208
220
209readWriteBeforeAfterStream :: Handle -> Handle -> IO ()
221readWriteBeforeAfterStream :: Handle -> Handle -> IO ()
210readWriteBeforeAfterStream inh devNull =
222readWriteBeforeAfterStream inh devNull =
@@ -228,7 +240,7 @@ inspect $ 'readWriteAfterStream `hasNoType` ''D.Step
228
240
229readWriteAfter_Stream :: Handle -> Handle -> IO ()
241readWriteAfter_Stream :: Handle -> Handle -> IO ()
230readWriteAfter_Stream inh devNull =
242readWriteAfter_Stream inh devNull =
231− let readEx = Stream.afterUnsafe (hClose inh) (Stream.unfold FH.reader inh)
243+ let readEx = afterUnsafe (hClose inh) (Stream.unfold FH.reader inh)
232 in Stream.fold (FH.write devNull) readEx
244 in Stream.fold (FH.write devNull) readEx
233
245
234#ifdef INSPECTION
246#ifdef INSPECTION
@@ -310,10 +322,10 @@ o_1_space_copy_exceptions_readChunks env =
310-- | Send the file contents to /dev/null with exception handling
322-- | Send the file contents to /dev/null with exception handling
311toChunksBracket_ :: Handle -> Handle -> IO ()
323toChunksBracket_ :: Handle -> Handle -> IO ()
312toChunksBracket_ inh devNull =
324toChunksBracket_ inh devNull =
313− let readEx = Stream.bracketUnsafe
325+ let readEx = bracketUnsafe
314 (return ())
326 (return ())
315 (\_ -> hClose inh)
327 (\_ -> hClose inh)
316− (\_ -> IFH.readChunks inh)
328+ (\_ -> fromStreamD $ IFH.readChunks inh)
317 in Stream.fold (IFH.writeChunks devNull) readEx
329 in Stream.fold (IFH.writeChunks devNull) readEx
318
330
319#ifdef INSPECTION
331#ifdef INSPECTION
@@ -325,7 +337,7 @@ toChunksBracket inh devNull =
325 let readEx = Stream.bracket
337 let readEx = Stream.bracket
326 (return ())
338 (return ())
327 (\_ -> hClose inh)
339 (\_ -> hClose inh)
328− (\_ -> IFH.readChunks inh)
340+ (\_ -> fromStreamD $ IFH.readChunks inh)
329 in Stream.fold (IFH.writeChunks devNull) readEx
341 in Stream.fold (IFH.writeChunks devNull) readEx
330
342
331o_1_space_copy_exceptions_toChunks :: BenchEnv -> [Benchmark]
343o_1_space_copy_exceptions_toChunks :: BenchEnv -> [Benchmark]
@@ -338,16 +350,12 @@ o_1_space_copy_exceptions_toChunks env =
338 ]
350 ]
339 ]
351 ]
340
352
341−#endif
342−
343benchmarks :: String -> BenchEnv -> Int -> [Benchmark]
353benchmarks :: String -> BenchEnv -> Int -> [Benchmark]
344benchmarks moduleName _env size =
354benchmarks moduleName _env size =
345 [ bgroup (o_1_space_prefix moduleName) $ concat
355 [ bgroup (o_1_space_prefix moduleName) $ concat
346 [ o_1_space_serial_exceptions size
356 [ o_1_space_serial_exceptions size
347−#ifndef USE_STREAMLY_CORE
348 , o_1_space_copy_exceptions_readChunks _env
357 , o_1_space_copy_exceptions_readChunks _env
349 , o_1_space_copy_exceptions_toChunks _env
358 , o_1_space_copy_exceptions_toChunks _env
350 , o_1_space_copy_stream_exceptions _env
359 , o_1_space_copy_stream_exceptions _env
351−#endif
352 ]
360 ]
353 ]
361 ]
benchmark/Streamly/Benchmark/Data/Stream/Expand.hs+108−76
@@ -25,11 +25,6 @@
25
25
26module Stream.Expand (benchmarks) where
26module Stream.Expand (benchmarks) where
27
27
28−import Streamly.Internal.Data.Stream (Stream)
29−import Streamly.Internal.Data.Stream.Cross (CrossStream(..))
30−
31−import qualified Control.Applicative as AP
32−
33#ifdef INSPECTION
28#ifdef INSPECTION
34import GHC.Types (SPEC(..))
29import GHC.Types (SPEC(..))
35import Test.Inspection
30import Test.Inspection
@@ -38,19 +33,29 @@ import qualified Streamly.Internal.Data.Stream.StreamD as D
38#endif
33#endif
39
34
40import qualified Stream.Common as Common
35import qualified Stream.Common as Common
36+import qualified Streamly.Internal.Data.Unfold as UF
37+
41#ifdef USE_PRELUDE
38#ifdef USE_PRELUDE
42import qualified Streamly.Internal.Data.Stream.IsStream as S
39import qualified Streamly.Internal.Data.Stream.IsStream as S
40+import qualified Streamly.Internal.Data.Stream.IsStream as StreamK
43import Streamly.Benchmark.Prelude
41import Streamly.Benchmark.Prelude
44 ( sourceFoldMapM, sourceFoldMapWith, sourceFoldMapWithM
42 ( sourceFoldMapM, sourceFoldMapWith, sourceFoldMapWithM
45 , sourceFoldMapWithStream, concatFoldableWith, concatForFoldableWith)
43 , sourceFoldMapWithStream, concatFoldableWith, concatForFoldableWith)
46#else
44#else
47−import qualified Streamly.Internal.Data.Stream as S
45+import qualified Streamly.Internal.Data.Stream.StreamD as S
48−#endif
46+#ifdef USE_STREAMK
49−import qualified Streamly.Internal.Data.Unfold as UF
47+import Streamly.Internal.Data.Stream.StreamD (Stream)
48+import Streamly.Internal.Data.Stream.StreamK (StreamK, CrossStreamK)
49+import qualified Control.Applicative as AP
50import qualified Streamly.Internal.Data.Fold as Fold
50import qualified Streamly.Internal.Data.Fold as Fold
51+import qualified Streamly.Internal.Data.Stream.StreamK as StreamK
52+#else
53+import qualified Streamly.Internal.Data.Stream.StreamD as StreamK
54+#endif
55+#endif
51
56
52import Gauge
57import Gauge
53−import Stream.Common hiding (append2)
58+import Stream.Common
54import Streamly.Benchmark.Common
59import Streamly.Benchmark.Common
55import Prelude hiding (concatMap)
60import Prelude hiding (concatMap)
56
61
@@ -58,6 +63,7 @@ import Prelude hiding (concatMap)
58-- Iteration/looping utilities
63-- Iteration/looping utilities
59-------------------------------------------------------------------------------
64-------------------------------------------------------------------------------
60
65
66+#ifdef USE_STREAMK
61{-# INLINE iterateN #-}
67{-# INLINE iterateN #-}
62iterateN :: (Int -> a -> a) -> a -> Int -> a
68iterateN :: (Int -> a -> a) -> a -> Int -> a
63iterateN g initial count = f count initial
69iterateN g initial count = f count initial
@@ -69,13 +75,16 @@ iterateN g initial count = f count initial
69
75
70-- Iterate a transformation over a singleton stream
76-- Iterate a transformation over a singleton stream
71{-# INLINE iterateSingleton #-}
77{-# INLINE iterateSingleton #-}
72−iterateSingleton ::
78+iterateSingleton :: Applicative m =>
73− (Int -> CrossStream m Int -> CrossStream m Int)
79+ (Int -> CrossStreamK m Int -> CrossStreamK m Int)
74 -> Int
80 -> Int
75 -> Int
81 -> Int
76 -> Stream m Int
82 -> Stream m Int
77iterateSingleton g count n =
83iterateSingleton g count n =
84+ toStream
85+ $ StreamK.unCross
78− unCrossStream $ iterateN g (CrossStream (S.fromPure n)) count
86+ $ iterateN g (StreamK.mkCross (StreamK.fromPure n)) count
87+#endif
79
88
80{-
89{-
81-- XXX need to check why this is slower than the explicit recursion above, even
90-- XXX need to check why this is slower than the explicit recursion above, even
@@ -104,50 +113,28 @@ _iterateSingleton g value n = S.foldrM g (return n) $ sourceIntFromTo value n
104{-# INLINE serial2 #-}
113{-# INLINE serial2 #-}
105serial2 :: Int -> Int -> IO ()
114serial2 :: Int -> Int -> IO ()
106serial2 count n =
115serial2 count n =
107− drain $
116+ drain $ toStream $
117+ Common.append
118+ (fromStream $ sourceUnfoldrM count n)
108− Common.append (sourceUnfoldrM count n) (sourceUnfoldrM count (n + 1))
119+ (fromStream $ sourceUnfoldrM count (n + 1))
109
120
110{-# INLINE serial4 #-}
121{-# INLINE serial4 #-}
111serial4 :: Int -> Int -> IO ()
122serial4 :: Int -> Int -> IO ()
112serial4 count n =
123serial4 count n =
113− drain $
124+ drain $ toStream $
114 Common.append
125 Common.append
115− (Common.append (sourceUnfoldrM count n) (sourceUnfoldrM count (n + 1)))
116 (Common.append
126 (Common.append
117− (sourceUnfoldrM count (n + 2))
118− (sourceUnfoldrM count (n + 3)))
127+ (fromStream $ sourceUnfoldrM count n)
119−
120−{-# INLINE append2 #-}
121−append2 :: Int -> Int -> IO ()
122−append2 count n =
123− drain $
124− Common.append2 (sourceUnfoldrM count n) (sourceUnfoldrM count (n + 1))
128+ (fromStream $ sourceUnfoldrM count (n + 1)))
125−
126−{-# INLINE append4 #-}
127−append4 :: Int -> Int -> IO ()
128−append4 count n =
129− drain $
130− Common.append2
131− (Common.append2
129+ (Common.append
132− (sourceUnfoldrM count n)
133− (sourceUnfoldrM count (n + 1)))
130+ (fromStream $ sourceUnfoldrM count (n + 2))
134− (Common.append2
135− (sourceUnfoldrM count (n + 2))
136− (sourceUnfoldrM count (n + 3)))
131+ (fromStream $ sourceUnfoldrM count (n + 3)))
137−
138−#ifdef INSPECTION
139−inspect $ hasNoTypeClasses 'append2
140−inspect $ 'append2 `hasNoType` ''SPEC
141−inspect $ 'append2 `hasNoType` ''D.AppendState
142−#endif
143
132
144o_1_space_joining :: Int -> [Benchmark]
133o_1_space_joining :: Int -> [Benchmark]
145o_1_space_joining value =
134o_1_space_joining value =
146 [ bgroup "joining"
135 [ bgroup "joining"
147 [ benchIOSrc1 "serial (2,x/2)" (serial2 (value `div` 2))
136 [ benchIOSrc1 "serial (2,x/2)" (serial2 (value `div` 2))
148− , benchIOSrc1 "append (2,x/2)" (append2 (value `div` 2))
149 , benchIOSrc1 "serial (2,2,x/4)" (serial4 (value `div` 4))
137 , benchIOSrc1 "serial (2,2,x/4)" (serial4 (value `div` 4))
150− , benchIOSrc1 "append (2,2,x/4)" (append4 (value `div` 4))
151 ]
138 ]
152 ]
139 ]
153
140
@@ -183,10 +170,11 @@ o_1_space_concatFoldable value =
183{-# INLINE concatMap #-}
170{-# INLINE concatMap #-}
184concatMap :: Int -> Int -> Int -> IO ()
171concatMap :: Int -> Int -> Int -> IO ()
185concatMap outer inner n =
172concatMap outer inner n =
186− drain $ S.concatMap
173+ drain $ toStream $ StreamK.concatMap
187− (\_ -> sourceUnfoldrM inner n)
174+ (\_ -> fromStream $ sourceUnfoldrM inner n)
188− (sourceUnfoldrM outer n)
175+ (fromStream $ sourceUnfoldrM outer n)
189
176
177+#ifndef USE_STREAMK
190{-# INLINE concatMapM #-}
178{-# INLINE concatMapM #-}
191concatMapM :: Int -> Int -> Int -> IO ()
179concatMapM :: Int -> Int -> Int -> IO ()
192concatMapM outer inner n =
180concatMapM outer inner n =
@@ -198,15 +186,16 @@ concatMapM outer inner n =
198inspect $ hasNoTypeClasses 'concatMap
186inspect $ hasNoTypeClasses 'concatMap
199inspect $ 'concatMap `hasNoType` ''SPEC
187inspect $ 'concatMap `hasNoType` ''SPEC
200#endif
188#endif
189+#endif
201
190
202-- concatMap unfoldr/unfoldr
191-- concatMap unfoldr/unfoldr
203
192
204{-# INLINE concatMapPure #-}
193{-# INLINE concatMapPure #-}
205concatMapPure :: Int -> Int -> Int -> IO ()
194concatMapPure :: Int -> Int -> Int -> IO ()
206concatMapPure outer inner n =
195concatMapPure outer inner n =
207− drain $ S.concatMap
196+ drain $ toStream $ StreamK.concatMap
208− (\_ -> sourceUnfoldr inner n)
197+ (\_ -> fromStream $ sourceUnfoldr inner n)
209− (sourceUnfoldr outer n)
198+ (fromStream $ sourceUnfoldr outer n)
210
199
211#ifdef INSPECTION
200#ifdef INSPECTION
212inspect $ hasNoTypeClasses 'concatMapPure
201inspect $ hasNoTypeClasses 'concatMapPure
@@ -218,7 +207,8 @@ inspect $ 'concatMapPure `hasNoType` ''SPEC
218{-# INLINE concatMapRepl #-}
207{-# INLINE concatMapRepl #-}
219concatMapRepl :: Int -> Int -> Int -> IO ()
208concatMapRepl :: Int -> Int -> Int -> IO ()
220concatMapRepl outer inner n =
209concatMapRepl outer inner n =
210+ drain $ toStream $ StreamK.concatMap
221− drain $ S.concatMap (S.replicate inner) (sourceUnfoldrM outer n)
211+ (fromStream . S.replicate inner) (fromStream $ sourceUnfoldrM outer n)
222
212
223#ifdef INSPECTION
213#ifdef INSPECTION
224inspect $ hasNoTypeClasses 'concatMapRepl
214inspect $ hasNoTypeClasses 'concatMapRepl
@@ -227,6 +217,7 @@ inspect $ 'concatMapRepl `hasNoType` ''SPEC
227
217
228-- concatMapWith
218-- concatMapWith
229
219
220+#ifdef USE_STREAMK
230{-# INLINE concatMapWithSerial #-}
221{-# INLINE concatMapWithSerial #-}
231concatMapWithSerial :: Int -> Int -> Int -> IO ()
222concatMapWithSerial :: Int -> Int -> Int -> IO ()
232concatMapWithSerial = concatStreamsWith Common.append
223concatMapWithSerial = concatStreamsWith Common.append
@@ -236,6 +227,7 @@ inspect $ hasNoTypeClasses 'concatMapWithSerial
236inspect $ 'concatMapWithSerial `hasNoType` ''SPEC
227inspect $ 'concatMapWithSerial `hasNoType` ''SPEC
237#endif
228#endif
238
229
230+{-
239{-# INLINE concatMapWithAppend #-}
231{-# INLINE concatMapWithAppend #-}
240concatMapWithAppend :: Int -> Int -> Int -> IO ()
232concatMapWithAppend :: Int -> Int -> Int -> IO ()
241concatMapWithAppend = concatStreamsWith Common.append2
233concatMapWithAppend = concatStreamsWith Common.append2
@@ -244,6 +236,7 @@ concatMapWithAppend = concatStreamsWith Common.append2
244inspect $ hasNoTypeClasses 'concatMapWithAppend
236inspect $ hasNoTypeClasses 'concatMapWithAppend
245inspect $ 'concatMapWithAppend `hasNoType` ''SPEC
237inspect $ 'concatMapWithAppend `hasNoType` ''SPEC
246#endif
238#endif
239+-}
247
240
248-- mergeMapWith
241-- mergeMapWith
249
242
@@ -251,9 +244,12 @@ inspect $ 'concatMapWithAppend `hasNoType` ''SPEC
251mergeMapWithSerial :: Int -> Int -> Int -> IO ()
244mergeMapWithSerial :: Int -> Int -> Int -> IO ()
252mergeMapWithSerial = mergeMapWith Common.append
245mergeMapWithSerial = mergeMapWith Common.append
253
246
247+{-
254{-# INLINE mergeMapWithAppend #-}
248{-# INLINE mergeMapWithAppend #-}
255mergeMapWithAppend :: Int -> Int -> Int -> IO ()
249mergeMapWithAppend :: Int -> Int -> Int -> IO ()
256mergeMapWithAppend = mergeMapWith Common.append2
250mergeMapWithAppend = mergeMapWith Common.append2
251+-}
252+#endif
257
253
258-- unfoldMany
254-- unfoldMany
259
255
@@ -284,10 +280,6 @@ o_1_space_concat value = sqrtVal `seq`
284 , benchIOSrc1 "concatMapPure (1 of n)"
280 , benchIOSrc1 "concatMapPure (1 of n)"
285 (concatMapPure 1 value)
281 (concatMapPure 1 value)
286
282
287− -- This is for comparison with foldMapWith
288− , benchIOSrc "concatMapId (n of 1) (fromFoldable)"
289− (S.concatMap id . sourceConcatMapId value)
290−
291 , benchIOSrc1 "concatMap (n of 1)"
283 , benchIOSrc1 "concatMap (n of 1)"
292 (concatMap value 1)
284 (concatMap value 1)
293 , benchIOSrc1 "concatMap (sqrt n of sqrt n)"
285 , benchIOSrc1 "concatMap (sqrt n of sqrt n)"
@@ -295,16 +287,25 @@ o_1_space_concat value = sqrtVal `seq`
295 , benchIOSrc1 "concatMap (1 of n)"
287 , benchIOSrc1 "concatMap (1 of n)"
296 (concatMap 1 value)
288 (concatMap 1 value)
297
289
290+#ifndef USE_STREAMK
291+ -- This is for comparison with foldMapWith
292+ , benchIOSrc "concatMapId (n of 1) (fromFoldable)"
293+ (S.concatMap id . sourceConcatMapId value)
294+
298 , benchIOSrc1 "concatMapM (n of 1)"
295 , benchIOSrc1 "concatMapM (n of 1)"
299 (concatMapM value 1)
296 (concatMapM value 1)
300 , benchIOSrc1 "concatMapM (sqrt n of sqrt n)"
297 , benchIOSrc1 "concatMapM (sqrt n of sqrt n)"
301 (concatMapM sqrtVal sqrtVal)
298 (concatMapM sqrtVal sqrtVal)
302 , benchIOSrc1 "concatMapM (1 of n)"
299 , benchIOSrc1 "concatMapM (1 of n)"
303 (concatMapM 1 value)
300 (concatMapM 1 value)
301+#endif
304
302
303+#ifdef USE_STREAMK
304+ {-
305 -- This is for comparison with foldMapWith
305 -- This is for comparison with foldMapWith
306 , benchIOSrc "concatMapWithId (n of 1) (fromFoldable)"
306 , benchIOSrc "concatMapWithId (n of 1) (fromFoldable)"
307− (S.concatMapWith Common.append id . sourceConcatMapId value)
307+ (toStream . S.concatMapWith Common.append id . sourceConcatMapId value)
308+ -}
308
309
309 , benchIOSrc1 "concatMapWith (n of 1)"
310 , benchIOSrc1 "concatMapWith (n of 1)"
310 (concatMapWithSerial value 1)
311 (concatMapWithSerial value 1)
@@ -313,9 +314,12 @@ o_1_space_concat value = sqrtVal `seq`
313 , benchIOSrc1 "concatMapWith (1 of n)"
314 , benchIOSrc1 "concatMapWith (1 of n)"
314 (concatMapWithSerial 1 value)
315 (concatMapWithSerial 1 value)
315
316
317+ {-
316 -- quadratic with number of outer streams
318 -- quadratic with number of outer streams
317 , benchIOSrc1 "concatMapWithAppend (2 of n/2)"
319 , benchIOSrc1 "concatMapWithAppend (2 of n/2)"
318 (concatMapWithAppend 2 (value `div` 2))
320 (concatMapWithAppend 2 (value `div` 2))
321+ -}
322+#endif
319
323
320 -- concatMap vs unfoldMany
324 -- concatMap vs unfoldMany
321 , benchIOSrc1 "concatMapRepl (sqrt n of sqrt n)"
325 , benchIOSrc1 "concatMapRepl (sqrt n of sqrt n)"
@@ -329,8 +333,9 @@ o_1_space_concat value = sqrtVal `seq`
329
333
330 sqrtVal = round $ sqrt (fromIntegral value :: Double)
334 sqrtVal = round $ sqrt (fromIntegral value :: Double)
331
335
336+#ifdef USE_STREAMK
332−o_n_space_concat :: Int -> [Benchmark]
337+o_n_space_merge :: Int -> [Benchmark]
333−o_n_space_concat value = sqrtVal `seq`
338+o_n_space_merge value = sqrtVal `seq`
334 [ bgroup "concat"
339 [ bgroup "concat"
335 [
340 [
336 -------------------mergeMapWith-----------------
341 -------------------mergeMapWith-----------------
@@ -344,16 +349,19 @@ o_n_space_concat value = sqrtVal `seq`
344 , benchIOSrc1 "mergeMapWithSerial (2 of n/2)"
349 , benchIOSrc1 "mergeMapWithSerial (2 of n/2)"
345 (mergeMapWithSerial 2 (value `div` 2))
350 (mergeMapWithSerial 2 (value `div` 2))
346
351
352+ {-
347 , benchIOSrc1 "mergeMapWithAppend (n of 1)"
353 , benchIOSrc1 "mergeMapWithAppend (n of 1)"
348 (mergeMapWithAppend value 1)
354 (mergeMapWithAppend value 1)
349 , benchIOSrc1 "mergeMapWithAppend (sqrtVal of sqrtVal)"
355 , benchIOSrc1 "mergeMapWithAppend (sqrtVal of sqrtVal)"
350 (mergeMapWithAppend sqrtVal sqrtVal)
356 (mergeMapWithAppend sqrtVal sqrtVal)
357+ -}
351 ]
358 ]
352 ]
359 ]
353
360
354 where
361 where
355
362
356 sqrtVal = round $ sqrt (fromIntegral value :: Double)
363 sqrtVal = round $ sqrt (fromIntegral value :: Double)
364+#endif
357
365
358-------------------------------------------------------------------------------
366-------------------------------------------------------------------------------
359-- Applicative
367-- Applicative
@@ -369,9 +377,10 @@ o_1_space_applicative value =
369 ]
377 ]
370 ]
378 ]
371
379
380+#ifdef USE_STREAMK
372o_n_space_applicative :: Int -> [Benchmark]
381o_n_space_applicative :: Int -> [Benchmark]
373o_n_space_applicative value =
382o_n_space_applicative value =
374− [ bgroup "Applicative"
383+ [ bgroup "iterated"
375 [ benchIOSrc "(*>) (n times)" $
384 [ benchIOSrc "(*>) (n times)" $
376 iterateSingleton ((*>) . pure) value
385 iterateSingleton ((*>) . pure) value
377 , benchIOSrc "(<*) (n times)" $
386 , benchIOSrc "(<*) (n times)" $
@@ -382,6 +391,7 @@ o_n_space_applicative value =
382 iterateSingleton (AP.liftA2 (+) . pure) value
391 iterateSingleton (AP.liftA2 (+) . pure) value
383 ]
392 ]
384 ]
393 ]
394+#endif
385
395
386-------------------------------------------------------------------------------
396-------------------------------------------------------------------------------
387-- Monad
397-- Monad
@@ -405,30 +415,46 @@ o_1_space_monad value =
405 ]
415 ]
406 ]
416 ]
407
417
418+#ifdef USE_STREAMK
408-- This is a good benchmark but inefficient way to compute primes. As we see a
419-- This is a good benchmark but inefficient way to compute primes. As we see a
409-- new prime we keep appending a division filter for all the future numbers.
420-- new prime we keep appending a division filter for all the future numbers.
410{-# INLINE sieve #-}
421{-# INLINE sieve #-}
411−sieve :: Monad m => Stream m Int -> Stream m Int
422+sieve :: Monad m => StreamK m Int -> StreamK m Int
412−sieve s = S.concatEffect $ do
423+sieve s = StreamK.concatEffect $ do
413− r <- S.uncons s
424+ r <- StreamK.uncons s
414 case r of
425 case r of
415 Just (prime, rest) ->
426 Just (prime, rest) ->
427+ -- XXX Use K.filter or rewrite to K.filter
416− pure $ prime `S.cons` sieve (S.filter (\n -> n `mod` prime /= 0) rest)
428+ let f = S.filter (\n -> n `mod` prime /= 0)
429+ in pure $ prime `StreamK.cons` sieve (fromStream $ f $ toStream rest)
417− Nothing -> pure S.nil
430+ Nothing -> pure StreamK.nil
431+
432+o_n_space_iterated :: Int -> [Benchmark]
433+o_n_space_iterated value =
434+ [ bgroup "iterated"
435+ [
436+ benchIO "concatEffect prime sieve (n/4)"
437+ (\n ->
438+ S.fold Fold.sum
439+ $ toStream
440+ $ sieve
441+ $ fromStream
442+ $ S.enumerateFromTo 2 (value `div` 4 + n))
443+ , benchIOSrc "(>>) (n times)" $
444+ iterateSingleton ((>>) . pure) value
445+ , benchIOSrc "(>>=) (n times)" $
446+ iterateSingleton (\x xs -> xs >>= \y -> return (x + y)) value
447+ ]
448+ ]
449+#endif
418
450
419o_n_space_monad :: Int -> [Benchmark]
451o_n_space_monad :: Int -> [Benchmark]
420o_n_space_monad value =
452o_n_space_monad value =
421 [ bgroup "Monad"
453 [ bgroup "Monad"
422− [ benchIOSrc "(>>) (n times)" $
423− iterateSingleton ((>>) . pure) value
424− , benchIOSrc "(>>=) (n times)" $
425− iterateSingleton (\x xs -> xs >>= \y -> return (x + y)) value
426− , benchIO "(>>=) (sqrt n x sqrt n) (toList)" $
454+ [ benchIO "(>>=) (sqrt n x sqrt n) (toList)" $
427 toListM value
455 toListM value
428 , benchIO "(>>=) (sqrt n x sqrt n) (toListSome)" $
456 , benchIO "(>>=) (sqrt n x sqrt n) (toListSome)" $
429 toListSome value
457 toListSome value
430− , benchIO "naive prime sieve (n/4)"
431− (\n -> S.fold Fold.sum $ sieve $ S.enumerateFromTo 2 (value `div` 4 + n))
432 ]
458 ]
433 ]
459 ]
434
460
@@ -436,6 +462,7 @@ o_n_space_monad value =
436-- Joining
462-- Joining
437-------------------------------------------------------------------------------
463-------------------------------------------------------------------------------
438
464
465+{-
439toKv :: Int -> (Int, Int)
466toKv :: Int -> (Int, Int)
440toKv p = (p, p)
467toKv p = (p, p)
441
468
@@ -487,6 +514,7 @@ o_n_heap_buffering value =
487
514
488 halfVal = value `div` 2
515 halfVal = value `div` 2
489 sqrtVal = round $ sqrt (fromIntegral value :: Double)
516 sqrtVal = round $ sqrt (fromIntegral value :: Double)
517+-}
490
518
491-------------------------------------------------------------------------------
519-------------------------------------------------------------------------------
492-- Main
520-- Main
@@ -495,6 +523,7 @@ o_n_heap_buffering value =
495-- In addition to gauge options, the number of elements in the stream can be
523-- In addition to gauge options, the number of elements in the stream can be
496-- passed using the --stream-size option.
524-- passed using the --stream-size option.
497--
525--
526+{-# ANN benchmarks "HLint: ignore" #-}
498benchmarks :: String -> Int -> [Benchmark]
527benchmarks :: String -> Int -> [Benchmark]
499benchmarks moduleName size =
528benchmarks moduleName size =
500 [ bgroup (o_1_space_prefix moduleName) $ Prelude.concat
529 [ bgroup (o_1_space_prefix moduleName) $ Prelude.concat
@@ -505,19 +534,22 @@ benchmarks moduleName size =
505 , o_1_space_concatFoldable size
534 , o_1_space_concatFoldable size
506#endif
535#endif
507 , o_1_space_concat size
536 , o_1_space_concat size
508−
509 , o_1_space_applicative size
537 , o_1_space_applicative size
510 , o_1_space_monad size
538 , o_1_space_monad size
511−
512 ]
539 ]
513 , bgroup (o_n_space_prefix moduleName) $ Prelude.concat
540 , bgroup (o_n_space_prefix moduleName) $ Prelude.concat
514 [
541 [
515 -- multi-stream
542 -- multi-stream
543+ o_n_space_monad size
544+#ifdef USE_STREAMK
545+ , o_n_space_merge size
546+ , o_n_space_iterated size
516− o_n_space_applicative size
547+ , o_n_space_applicative size
517− , o_n_space_monad size
548+#endif
518− , o_n_space_concat size
519 ]
549 ]
550+ {-
520 , bgroup (o_n_heap_prefix moduleName) $
551 , bgroup (o_n_heap_prefix moduleName) $
521 -- multi-stream
552 -- multi-stream
522 o_n_heap_buffering size
553 o_n_heap_buffering size
554+ -}
523 ]
555 ]
benchmark/Streamly/Benchmark/Data/Stream/Generate.hs+43−25
@@ -21,29 +21,28 @@ import Control.DeepSeq (NFData(..))
21import Data.Functor.Identity (Identity(..))
21import Data.Functor.Identity (Identity(..))
22
22
23import qualified GHC.Exts as GHC
23import qualified GHC.Exts as GHC
24−import qualified Stream.Common as Common
25import qualified Streamly.Internal.Data.Fold as Fold
24import qualified Streamly.Internal.Data.Fold as Fold
25+
26#ifdef USE_PRELUDE
26#ifdef USE_PRELUDE
27+import Streamly.Prelude (MonadAsync)
28+import Stream.Common hiding (MonadAsync)
27import Streamly.Benchmark.Prelude (sourceFromFoldableM, absTimes)
29import Streamly.Benchmark.Prelude (sourceFromFoldableM, absTimes)
28import qualified Streamly.Prelude as S
30import qualified Streamly.Prelude as S
29import qualified Streamly.Internal.Data.Stream.IsStream as Stream
31import qualified Streamly.Internal.Data.Stream.IsStream as Stream
30#else
32#else
33+import Stream.Common
34+import Streamly.Internal.Data.Stream.StreamD (Stream)
35+import qualified Streamly.Internal.Data.Stream.StreamD as Stream
36+#ifdef USE_STREAMK
37+import System.IO.Unsafe (unsafeInterleaveIO)
31−import qualified Streamly.Internal.Data.Stream as Stream
38+import qualified Streamly.Internal.Data.Stream.StreamK as StreamK
39+import qualified Stream.Common as Common
40+#endif
32#endif
41#endif
33−import qualified Prelude
34
42
35import Gauge
43import Gauge
36import Streamly.Benchmark.Common
44import Streamly.Benchmark.Common
37−import Streamly.Internal.Data.Stream (Stream)
45+import qualified Prelude
38−import Streamly.Internal.Data.Stream.Cross (CrossStream(..))
39−#ifdef USE_PRELUDE
40−import Streamly.Prelude (MonadAsync)
41−import Stream.Common hiding (MonadAsync)
42−#else
43−import Stream.Common
44−#endif
45−
46−import System.IO.Unsafe (unsafeInterleaveIO)
47
46
48import Prelude hiding (repeat, replicate, iterate)
47import Prelude hiding (repeat, replicate, iterate)
49
48
@@ -51,6 +50,14 @@ import Prelude hiding (repeat, replicate, iterate)
51-- Generation
50-- Generation
52-------------------------------------------------------------------------------
51-------------------------------------------------------------------------------
53
52
53+#ifdef USE_PRELUDE
54+type Stream = Stream.SerialT
55+toStreamD = Stream.toStream
56+#else
57+toStreamD :: a -> a
58+toStreamD = id
59+#endif
60+
54-------------------------------------------------------------------------------
61-------------------------------------------------------------------------------
55-- fromList
62-- fromList
56-------------------------------------------------------------------------------
63-------------------------------------------------------------------------------
@@ -157,15 +164,15 @@ iterate count = Stream.take count . Stream.iterate (+1)
157iterateM :: MonadAsync m => Int -> Int -> Stream m Int
164iterateM :: MonadAsync m => Int -> Int -> Stream m Int
158iterateM count = Stream.take count . Stream.iterateM (return . (+1)) . return
165iterateM count = Stream.take count . Stream.iterateM (return . (+1)) . return
159
166
160−#ifdef USE_PRELUDE
161{-# INLINE repeatM #-}
167{-# INLINE repeatM #-}
162−repeatM :: (MonadAsync m, S.IsStream t) => Int -> Int -> t m Int
168+repeatM :: MonadAsync m => Int -> Int -> Stream m Int
163−repeatM count = S.take count . S.repeatM . return
169+repeatM count = Stream.take count . Stream.repeatM . return
164
170
165{-# INLINE replicateM #-}
171{-# INLINE replicateM #-}
166−replicateM :: (MonadAsync m, S.IsStream t) => Int -> Int -> t m Int
172+replicateM :: MonadAsync m => Int -> Int -> Stream m Int
167−replicateM count = S.replicateM count . return
173+replicateM count = Stream.replicateM count . return
168
174
175+#ifdef USE_PRELUDE
169{-# INLINE fromIndices #-}
176{-# INLINE fromIndices #-}
170fromIndices :: (Monad m, S.IsStream t) => Int -> Int -> t m Int
177fromIndices :: (Monad m, S.IsStream t) => Int -> Int -> t m Int
171fromIndices value n = S.take value $ S.fromIndices (+ n)
178fromIndices value n = S.take value $ S.fromIndices (+ n)
@@ -175,15 +182,17 @@ fromIndicesM :: (MonadAsync m, S.IsStream t) => Int -> Int -> t m Int
175fromIndicesM value n = S.take value $ S.fromIndicesM (return <$> (+ n))
182fromIndicesM value n = S.take value $ S.fromIndicesM (return <$> (+ n))
176#endif
183#endif
177
184
185+#ifdef USE_STREAMK
178{-# INLINE mfixUnfold #-}
186{-# INLINE mfixUnfold #-}
179mfixUnfold :: Int -> Int -> Stream IO (Int, Int)
187mfixUnfold :: Int -> Int -> Stream IO (Int, Int)
180−mfixUnfold count start = Stream.mfix f
188+mfixUnfold count start = toStream $ StreamK.mfix f
181 where
189 where
182− f action = unCrossStream $ do
190+ f action = StreamK.unCross $ do
183 let incr n act = fmap ((+n) . snd) $ unsafeInterleaveIO act
191 let incr n act = fmap ((+n) . snd) $ unsafeInterleaveIO act
184− x <- CrossStream (Common.fromListM [incr 1 action, incr 2 action])
192+ x <- StreamK.mkCross (fromStream $ Common.fromListM [incr 1 action, incr 2 action])
185− y <- CrossStream (Common.sourceUnfoldr count start)
193+ y <- StreamK.mkCross (fromStream $ Common.sourceUnfoldr count start)
186 return (x, y)
194 return (x, y)
195+#endif
187
196
188o_1_space_generation :: Int -> [Benchmark]
197o_1_space_generation :: Int -> [Benchmark]
189o_1_space_generation value =
198o_1_space_generation value =
@@ -201,37 +210,46 @@ o_1_space_generation value =
201 , benchIOSrc "fracFromTo" (sourceFracFromTo value)
210 , benchIOSrc "fracFromTo" (sourceFracFromTo value)
202 , benchIOSrc "fromList" (sourceFromList value)
211 , benchIOSrc "fromList" (sourceFromList value)
203 , benchIOSrc "fromListM" (sourceFromListM value)
212 , benchIOSrc "fromListM" (sourceFromListM value)
204− , benchPureSrc "IsList.fromList" (sourceIsList value)
213+ , benchPureSrc "IsList.fromList" (toStreamD . sourceIsList value)
205− , benchPureSrc "IsString.fromString" (sourceIsString value)
214+ , benchPureSrc "IsString.fromString" (toStreamD . sourceIsString value)
206 , benchIOSrc "enumerateFrom" (enumerateFrom value)
215 , benchIOSrc "enumerateFrom" (enumerateFrom value)
207 , benchIOSrc "enumerateFromTo" (enumerateFromTo value)
216 , benchIOSrc "enumerateFromTo" (enumerateFromTo value)
208 , benchIOSrc "enumerateFromThen" (enumerateFromThen value)
217 , benchIOSrc "enumerateFromThen" (enumerateFromThen value)
209 , benchIOSrc "enumerateFromThenTo" (enumerateFromThenTo value)
218 , benchIOSrc "enumerateFromThenTo" (enumerateFromThenTo value)
210 , benchIOSrc "enumerate" (enumerate value)
219 , benchIOSrc "enumerate" (enumerate value)
211 , benchIOSrc "enumerateTo" (enumerateTo value)
220 , benchIOSrc "enumerateTo" (enumerateTo value)
212−#ifdef USE_PRELUDE
213 , benchIOSrc "repeatM" (repeatM value)
221 , benchIOSrc "repeatM" (repeatM value)
214 , benchIOSrc "replicateM" (replicateM value)
222 , benchIOSrc "replicateM" (replicateM value)
223+#ifdef USE_PRELUDE
215 , benchIOSrc "fromIndices" (fromIndices value)
224 , benchIOSrc "fromIndices" (fromIndices value)
216 , benchIOSrc "fromIndicesM" (fromIndicesM value)
225 , benchIOSrc "fromIndicesM" (fromIndicesM value)
217#endif
226#endif
218
227
219 -- These essentially test cons and consM
228 -- These essentially test cons and consM
229+#ifdef USE_STREAMK
220 , benchIOSrc "fromFoldable" (sourceFromFoldable value)
230 , benchIOSrc "fromFoldable" (sourceFromFoldable value)
231+ -- , benchIOSrc "fromFoldable 16" (sourceFromFoldable 16)
232+#else
233+ -- , benchIOSrc "fromFoldable 16" (sourceFromFoldable 16)
234+#endif
221
235
222#ifdef USE_PRELUDE
236#ifdef USE_PRELUDE
223 , benchIOSrc "fromFoldableM" (sourceFromFoldableM value)
237 , benchIOSrc "fromFoldableM" (sourceFromFoldableM value)
224 , benchIOSrc "absTimes" $ absTimes value
238 , benchIOSrc "absTimes" $ absTimes value
225#endif
239#endif
240+#ifdef USE_STREAMK
226 , Common.benchIOSrc "mfix_10" (mfixUnfold 10)
241 , Common.benchIOSrc "mfix_10" (mfixUnfold 10)
227 , Common.benchIOSrc "mfix_100" (mfixUnfold 100)
242 , Common.benchIOSrc "mfix_100" (mfixUnfold 100)
228 , Common.benchIOSrc "mfix_1000" (mfixUnfold 1000)
243 , Common.benchIOSrc "mfix_1000" (mfixUnfold 1000)
244+#endif
229 ]
245 ]
230 ]
246 ]
231
247
248+#ifndef USE_PRELUDE
232instance NFData a => NFData (Stream Identity a) where
249instance NFData a => NFData (Stream Identity a) where
233 {-# INLINE rnf #-}
250 {-# INLINE rnf #-}
234 rnf xs = runIdentity $ Stream.fold (Fold.foldl' (\_ x -> rnf x) ()) xs
251 rnf xs = runIdentity $ Stream.fold (Fold.foldl' (\_ x -> rnf x) ()) xs
252+#endif
235
253
236o_n_heap_generation :: Int -> [Benchmark]
254o_n_heap_generation :: Int -> [Benchmark]
237o_n_heap_generation value =
255o_n_heap_generation value =
benchmark/Streamly/Benchmark/Data/Stream/Lift.hs+29−27
@@ -18,24 +18,33 @@ module Stream.Lift (benchmarks) where
18import Control.DeepSeq (NFData(..))
18import Control.DeepSeq (NFData(..))
19import Control.Monad.State.Strict (StateT, get, put)
19import Control.Monad.State.Strict (StateT, get, put)
20import Data.Functor.Identity (Identity)
20import Data.Functor.Identity (Identity)
21−import Stream.Common
22− (benchIO, sourceUnfoldr, sourceUnfoldrM, benchIOSrc, drain)
21+import Stream.Common (sourceUnfoldr, sourceUnfoldrM, benchIOSrc)
23import System.Random (randomRIO)
22import System.Random (randomRIO)
23+
24+import qualified Stream.Common as Common
25+import qualified Streamly.Internal.Data.Fold as Fold
26+
24#ifdef USE_PRELUDE
27#ifdef USE_PRELUDE
25import qualified Streamly.Internal.Data.Stream.IsStream as Stream
28import qualified Streamly.Internal.Data.Stream.IsStream as Stream
26#else
29#else
30+import Streamly.Internal.Data.Stream.StreamD (Stream)
27−import qualified Streamly.Internal.Data.Stream as Stream
31+import qualified Streamly.Internal.Data.Stream.StreamD as Stream
28−#endif
32+#ifdef USE_STREAMK
33+import Stream.Common (benchIO, drain)
29−import qualified Streamly.Internal.Data.Fold as Fold
34+import Streamly.Internal.Data.Stream.StreamK (StreamK)
30−import qualified Stream.Common as Common
35+import qualified Streamly.Internal.Data.Stream.StreamK as StreamK
31import qualified Control.Monad.State.Strict as State
36import qualified Control.Monad.State.Strict as State
37+#endif
38+#endif
32
39
33import Gauge
40import Gauge
34−import Streamly.Internal.Data.Stream (Stream)
35import Streamly.Benchmark.Common
41import Streamly.Benchmark.Common
36−
37import Prelude hiding (reverse, tail)
42import Prelude hiding (reverse, tail)
38
43
44+#ifdef USE_PRELUDE
45+type Stream = Stream.SerialT
46+#endif
47+
39-------------------------------------------------------------------------------
48-------------------------------------------------------------------------------
40-- Monad transformation (hoisting etc.)
49-- Monad transformation (hoisting etc.)
41-------------------------------------------------------------------------------
50-------------------------------------------------------------------------------
@@ -76,12 +85,15 @@ o_1_space_hoisting value =
76 [ bgroup "hoisting"
85 [ bgroup "hoisting"
77 [ benchIOSrc "evalState" (evalStateT value)
86 [ benchIOSrc "evalState" (evalStateT value)
78 , benchIOSrc "withState" (withState value)
87 , benchIOSrc "withState" (withState value)
88+#ifndef USE_PRELUDE
79 , benchHoistSink value "generalizeInner"
89 , benchHoistSink value "generalizeInner"
80 ((\xs -> Stream.fold Fold.length xs :: IO Int)
90 ((\xs -> Stream.fold Fold.length xs :: IO Int)
81 . Stream.generalizeInner)
91 . Stream.generalizeInner)
92+#endif
82 ]
93 ]
83 ]
94 ]
84
95
96+#ifdef USE_STREAMK
85{-# INLINE iterateStateIO #-}
97{-# INLINE iterateStateIO #-}
86iterateStateIO ::
98iterateStateIO ::
87 Monad m
99 Monad m
@@ -95,28 +107,17 @@ iterateStateIO n = do
95 iterateStateIO n
107 iterateStateIO n
96 else return x
108 else return x
97
109
110+-- XXX This is basically testing the perf of concatEffect, change it to just
111+-- use concatEffect and move it along with other concatMap benchmarks.
98{-# INLINE iterateStateT #-}
112{-# INLINE iterateStateT #-}
99−iterateStateT :: Int -> Stream (StateT Int IO) Int
113+iterateStateT :: Int -> StreamK (StateT Int IO) Int
100−iterateStateT n = Stream.concatEffect $ do
114+iterateStateT n = StreamK.concatEffect $ do
101 x <- get
115 x <- get
102 if x > n
116 if x > n
103 then do
117 then do
104 put (x - 1)
118 put (x - 1)
105 return $ iterateStateT n
119 return $ iterateStateT n
106− else return $ Stream.fromPure x
120+ else return $ StreamK.fromPure x
107−
108−{-# INLINE iterateState #-}
109−{-# SPECIALIZE iterateState :: Int -> Stream (StateT Int IO) Int #-}
110−iterateState :: Monad m =>
111− Int
112− -> Stream (StateT Int m) Int
113−iterateState n = Stream.concatEffect $ do
114− x <- get
115− if x > n
116− then do
117− put (x - 1)
118− return $ iterateState n
119− else return $ Stream.fromPure x
120
121
121o_n_heap_transformer :: Int -> [Benchmark]
122o_n_heap_transformer :: Int -> [Benchmark]
122o_n_heap_transformer value =
123o_n_heap_transformer value =
@@ -124,11 +125,10 @@ o_n_heap_transformer value =
124 [ benchIO "StateT Int IO (n times) (baseline)" $ \n ->
125 [ benchIO "StateT Int IO (n times) (baseline)" $ \n ->
125 State.evalStateT (iterateStateIO n) value
126 State.evalStateT (iterateStateIO n) value
126 , benchIO "Stream (StateT Int IO) (n times)" $ \n ->
127 , benchIO "Stream (StateT Int IO) (n times)" $ \n ->
127− State.evalStateT (drain (iterateStateT n)) value
128+ State.evalStateT (drain $ Common.toStream (iterateStateT n)) value
128− , benchIO "MonadState Int m => Stream m Int" $ \n ->
129− State.evalStateT (drain (iterateState n)) value
130 ]
129 ]
131 ]
130 ]
131+#endif
132
132
133-------------------------------------------------------------------------------
133-------------------------------------------------------------------------------
134-- Main
134-- Main
@@ -140,5 +140,7 @@ o_n_heap_transformer value =
140benchmarks :: String -> Int -> [Benchmark]
140benchmarks :: String -> Int -> [Benchmark]
141benchmarks moduleName size =
141benchmarks moduleName size =
142 [ bgroup (o_1_space_prefix moduleName) (o_1_space_hoisting size)
142 [ bgroup (o_1_space_prefix moduleName) (o_1_space_hoisting size)
143+#ifdef USE_STREAMK
143 , bgroup (o_n_heap_prefix moduleName) (o_n_heap_transformer size)
144 , bgroup (o_n_heap_prefix moduleName) (o_n_heap_transformer size)
145+#endif
144 ]
146 ]
benchmark/Streamly/Benchmark/Data/Stream/Reduce.hs+131−104
@@ -21,17 +21,21 @@ import Control.DeepSeq (NFData(..))
21import Control.Monad.IO.Class (MonadIO(..))
21import Control.Monad.IO.Class (MonadIO(..))
22import Data.Monoid (Sum(..))
22import Data.Monoid (Sum(..))
23import GHC.Generics (Generic)
23import GHC.Generics (Generic)
24−import Streamly.Internal.Data.Stream (Stream)
25
24
26import qualified Streamly.Internal.Data.Refold.Type as Refold
25import qualified Streamly.Internal.Data.Refold.Type as Refold
27import qualified Streamly.Internal.Data.Fold as FL
26import qualified Streamly.Internal.Data.Fold as FL
28import qualified Stream.Common as Common
27import qualified Stream.Common as Common
29−#ifdef USE_PRELUDE
28+
30−import Control.Monad (when)
29+#ifndef USE_STREAMLY_CORE
31−import Data.Proxy (Proxy(..))
32import Data.HashMap.Strict (HashMap)
30import Data.HashMap.Strict (HashMap)
31+import Data.Proxy (Proxy(..))
33import Streamly.Internal.Data.IsMap.HashMap ()
32import Streamly.Internal.Data.IsMap.HashMap ()
33+#endif
34+
35+#ifdef USE_PRELUDE
36+import Control.Monad (when)
34import qualified Streamly.Internal.Data.Stream.IsStream as S
37import qualified Streamly.Internal.Data.Stream.IsStream as S
38+import qualified Streamly.Prelude as S
35import Streamly.Prelude (fromSerial)
39import Streamly.Prelude (fromSerial)
36import Streamly.Benchmark.Prelude hiding
40import Streamly.Benchmark.Prelude hiding
37 ( benchIO, benchIOSrc, sourceUnfoldrM, apDiscardFst, apDiscardSnd, apLiftA2
41 ( benchIO, benchIOSrc, sourceUnfoldrM, apDiscardFst, apDiscardSnd, apLiftA2
@@ -39,7 +43,22 @@ import Streamly.Benchmark.Prelude hiding
39 , filterSome, breakAfterSome, toListM, toListSome, transformMapM
43 , filterSome, breakAfterSome, toListM, toListSome, transformMapM
40 , transformComposeMapM, transformTeeMapM, transformZipMapM)
44 , transformComposeMapM, transformTeeMapM, transformZipMapM)
41#else
45#else
46+
47+import Streamly.Internal.Data.Stream.StreamD (Stream)
42−import qualified Streamly.Internal.Data.Stream as S
48+import qualified Streamly.Internal.Data.Stream.StreamD as S
49+#ifndef USE_STREAMLY_CORE
50+import qualified Streamly.Data.Stream.Prelude as S
51+import qualified Streamly.Internal.Data.Stream.Time as S
52+#endif
53+
54+#ifdef USE_STREAMK
55+import Streamly.Internal.Data.Stream.StreamK (StreamK)
56+import qualified Streamly.Internal.Data.Parser as PR
57+import qualified Streamly.Internal.Data.Stream.StreamK as K
58+#else
59+import qualified Streamly.Internal.Data.Stream.StreamD as K
60+#endif
61+
43#endif
62#endif
44
63
45import Gauge
64import Gauge
@@ -47,45 +66,27 @@ import Streamly.Benchmark.Common
47import Stream.Common
66import Stream.Common
48import Prelude hiding (reverse, tail)
67import Prelude hiding (reverse, tail)
49
68
50−-------------------------------------------------------------------------------
69+#ifdef USE_PRELUDE
51−-- Iteration/looping utilities
70+type Stream = S.SerialT
52−-------------------------------------------------------------------------------
71+#endif
53−
54−{-# INLINE iterateN #-}
55−iterateN :: (Int -> a -> a) -> a -> Int -> a
56−iterateN g initial count = f count initial
57−
58− where
59−
60− f (0 :: Int) x = x
61− f i x = f (i - 1) (g i x)
62
72
63−-- Iterate a transformation over a singleton stream
73+-- Apply transformation g count times on a stream of length len
64−{-# INLINE iterateSingleton #-}
74+#ifdef USE_STREAMK
65−iterateSingleton ::
75+{-# INLINE iterateSource #-}
66− (Int -> Stream m Int -> Stream m Int)
76+iterateSource ::
67− -> Int
77+ MonadAsync m
78+ => (StreamK m Int -> StreamK m Int)
68 -> Int
79 -> Int
69− -> Stream m Int
70−iterateSingleton g count n = iterateN g (S.fromPure n) count
71−
72−{-
73−-- XXX need to check why this is slower than the explicit recursion above, even
74−-- if the above code is written in a foldr like head recursive way. We also
75−-- need to try this with foldlM' once #150 is fixed.
76−-- However, it is perhaps best to keep the iteration benchmarks independent of
77−-- foldrM and any related fusion issues.
78−{-# INLINE _iterateSingleton #-}
79−_iterateSingleton ::
80− Monad m
81− => (Int -> Stream m Int -> Stream m Int)
82 -> Int
80 -> Int
83 -> Int
81 -> Int
84− -> Stream m Int
82+ -> StreamK m Int
85−_iterateSingleton g value n = S.foldrM g (return n) $ sourceIntFromTo value n
83+iterateSource g count len n = f count (fromStream $ sourceUnfoldrM len n)
86−-}
87
84
88−-- Apply transformation g count times on a stream of length len
85+ where
86+
87+ f (0 :: Int) stream = stream
88+ f i stream = f (i - 1) (g stream)
89+#else
89{-# INLINE iterateSource #-}
90{-# INLINE iterateSource #-}
90iterateSource ::
91iterateSource ::
91 MonadAsync m
92 MonadAsync m
@@ -100,28 +101,7 @@ iterateSource g count len n = f count (sourceUnfoldrM len n)
100
101
101 f (0 :: Int) stream = stream
102 f (0 :: Int) stream = stream
102 f i stream = f (i - 1) (g stream)
103 f i stream = f (i - 1) (g stream)
103−
104+#endif
104−-------------------------------------------------------------------------------
105−-- Functor
106−-------------------------------------------------------------------------------
107−
108−o_n_space_functor :: Int -> [Benchmark]
109−o_n_space_functor value =
110− [ bgroup "Functor"
111− [ benchIO "(+) (n times) (baseline)" $ \i0 ->
112− iterateN (\i acc -> acc >>= \n -> return $ i + n) (return i0) value
113− , benchIOSrc "(<$) (n times)" $
114− iterateSingleton (<$) value
115− , benchIOSrc "fmap (n times)" $
116− iterateSingleton (fmap . (+)) value
117− {-
118− , benchIOSrc fromSerial "_(<$) (n times)" $
119− _iterateSingleton (<$) value
120− , benchIOSrc fromSerial "_fmap (n times)" $
121− _iterateSingleton (fmap . (+)) value
122− -}
123− ]
124− ]
125
105
126-------------------------------------------------------------------------------
106-------------------------------------------------------------------------------
127-- Grouping transformations
107-- Grouping transformations
@@ -195,6 +175,16 @@ refoldIterateM =
195 (Refold.take 2 Refold.sconcat) (return (Sum 0))
175 (Refold.take 2 Refold.sconcat) (return (Sum 0))
196 . fmap Sum
176 . fmap Sum
197
177
178+#ifdef USE_STREAMK
179+{-# INLINE parseBreak #-}
180+parseBreak :: Monad m => StreamK m Int -> m ()
181+parseBreak s = do
182+ r <- K.parseBreak PR.one s
183+ case r of
184+ (Left _, _) -> return ()
185+ (Right _, s1) -> parseBreak s1
186+#endif
187+
198o_1_space_grouping :: Int -> [Benchmark]
188o_1_space_grouping :: Int -> [Benchmark]
199o_1_space_grouping value =
189o_1_space_grouping value =
200 -- Buffering operations using heap proportional to group/window sizes.
190 -- Buffering operations using heap proportional to group/window sizes.
@@ -216,31 +206,54 @@ o_1_space_grouping value =
216 , benchIOSink value "refoldMany" refoldMany
206 , benchIOSink value "refoldMany" refoldMany
217 , benchIOSink value "foldIterateM" foldIterateM
207 , benchIOSink value "foldIterateM" foldIterateM
218 , benchIOSink value "refoldIterateM" refoldIterateM
208 , benchIOSink value "refoldIterateM" refoldIterateM
209+#ifdef USE_STREAMK
210+ , benchIOSink value "parseBreak (recursive)" (parseBreak . fromStream)
211+#endif
212+
213+#ifndef USE_STREAMLY_CORE
214+ , benchIOSink value "classifySessionsOf (10000 buckets)"
215+ (classifySessionsOf (getKey 10000))
216+ , benchIOSink value "classifySessionsOf (64 buckets)"
217+ (classifySessionsOf (getKey 64))
218+ , benchIOSink value "classifySessionsOfHash (10000 buckets)"
219+ (classifySessionsOfHash (getKey 10000))
220+ , benchIOSink value "classifySessionsOfHash (64 buckets)"
221+ (classifySessionsOfHash (getKey 64))
222+#endif
219 ]
223 ]
220 ]
224 ]
221
225
226+#ifndef USE_STREAMLY_CORE
227+ where
228+
229+ getKey :: Int -> Int -> Int
230+ getKey n = (`mod` n)
231+#endif
232+
222-------------------------------------------------------------------------------
233-------------------------------------------------------------------------------
223-- Size conserving transformations (reordering, buffering, etc.)
234-- Size conserving transformations (reordering, buffering, etc.)
224-------------------------------------------------------------------------------
235-------------------------------------------------------------------------------
225
236
237+#ifndef USE_PRELUDE
226{-# INLINE reverse #-}
238{-# INLINE reverse #-}
227reverse :: MonadIO m => Int -> Stream m Int -> m ()
239reverse :: MonadIO m => Int -> Stream m Int -> m ()
228−reverse n = composeN n S.reverse
240+reverse n = composeN n (toStream . K.reverse . fromStream)
229
241
230{-# INLINE reverse' #-}
242{-# INLINE reverse' #-}
231reverse' :: MonadIO m => Int -> Stream m Int -> m ()
243reverse' :: MonadIO m => Int -> Stream m Int -> m ()
232−reverse' n = composeN n S.reverse'
244+reverse' n = composeN n S.reverseUnbox
245+#endif
233
246
234o_n_heap_buffering :: Int -> [Benchmark]
247o_n_heap_buffering :: Int -> [Benchmark]
235o_n_heap_buffering value =
248o_n_heap_buffering value =
236 [ bgroup "buffered"
249 [ bgroup "buffered"
237 [
250 [
251+#ifndef USE_PRELUDE
238 -- Reversing a stream
252 -- Reversing a stream
239 benchIOSink value "reverse" (reverse 1)
253 benchIOSink value "reverse" (reverse 1)
240 , benchIOSink value "reverse'" (reverse' 1)
254 , benchIOSink value "reverse'" (reverse' 1)
241−
255+#else
242−#ifdef USE_PRELUDE
243− , benchIOSink value "mkAsync" (mkAsync fromSerial)
256+ benchIOSink value "mkAsync" (mkAsync fromSerial)
244#endif
257#endif
245 ]
258 ]
246 ]
259 ]
@@ -249,9 +262,9 @@ o_n_heap_buffering value =
249-- Grouping/Splitting
262-- Grouping/Splitting
250-------------------------------------------------------------------------------
263-------------------------------------------------------------------------------
251
264
252−#ifdef USE_PRELUDE
265+#ifndef USE_STREAMLY_CORE
253{-# INLINE classifySessionsOf #-}
266{-# INLINE classifySessionsOf #-}
254−classifySessionsOf :: MonadAsync m => (Int -> Int) -> Stream m Int -> m ()
267+classifySessionsOf :: S.MonadAsync m => (Int -> Int) -> Stream m Int -> m ()
255classifySessionsOf getKey =
268classifySessionsOf getKey =
256 Common.drain
269 Common.drain
257 . S.classifySessionsOf
270 . S.classifySessionsOf
@@ -260,7 +273,7 @@ classifySessionsOf getKey =
260 . fmap (\x -> (getKey x, x))
273 . fmap (\x -> (getKey x, x))
261
274
262{-# INLINE classifySessionsOfHash #-}
275{-# INLINE classifySessionsOfHash #-}
263−classifySessionsOfHash :: MonadAsync m =>
276+classifySessionsOfHash :: S.MonadAsync m =>
264 (Int -> Int) -> Stream m Int -> m ()
277 (Int -> Int) -> Stream m Int -> m ()
265classifySessionsOfHash getKey =
278classifySessionsOfHash getKey =
266 Common.drain
279 Common.drain
@@ -269,25 +282,6 @@ classifySessionsOfHash getKey =
269 1 False (const (return False)) 3 (FL.take 10 FL.sum)
282 1 False (const (return False)) 3 (FL.take 10 FL.sum)
270 . S.timestamped
283 . S.timestamped
271 . fmap (\x -> (getKey x, x))
284 . fmap (\x -> (getKey x, x))
272−
273−o_n_space_grouping :: Int -> [Benchmark]
274−o_n_space_grouping value =
275− -- Buffering operations using heap proportional to group/window sizes.
276− [ bgroup "grouping"
277− [ benchIOSink value "classifySessionsOf (10000 buckets)"
278− (classifySessionsOf (getKey 10000))
279− , benchIOSink value "classifySessionsOf (64 buckets)"
280− (classifySessionsOf (getKey 64))
281− , benchIOSink value "classifySessionsOfHash (10000 buckets)"
282− (classifySessionsOfHash (getKey 10000))
283− , benchIOSink value "classifySessionsOfHash (64 buckets)"
284− (classifySessionsOfHash (getKey 64))
285− ]
286− ]
287−
288− where
289−
290− getKey n = (`mod` n)
291#endif
285#endif
292
286
293-------------------------------------------------------------------------------
287-------------------------------------------------------------------------------
@@ -349,8 +343,9 @@ data Pair a b =
349 deriving (Generic, NFData)
343 deriving (Generic, NFData)
350
344
351{-# INLINE sumProductFold #-}
345{-# INLINE sumProductFold #-}
352−sumProductFold :: Monad m => Stream m Int -> m (Int, Int)
346+sumProductFold :: Monad m => Stream m Int -> m (Pair Int Int)
347+sumProductFold =
353−sumProductFold = Common.foldl' (\(s, p) x -> (s + x, p * x)) (0, 1)
348+ Common.foldl' (\(Pair s p) x -> Pair (s + x) (p * x)) (Pair 0 1)
354
349
355{-# INLINE sumProductScan #-}
350{-# INLINE sumProductScan #-}
356sumProductScan :: Monad m => Stream m Int -> m (Pair Int Int)
351sumProductScan :: Monad m => Stream m Int -> m (Pair Int Int)
@@ -398,6 +393,46 @@ o_1_space_transformations_mixedX4 value =
398-- Iterating a transformation over and over again
393-- Iterating a transformation over and over again
399-------------------------------------------------------------------------------
394-------------------------------------------------------------------------------
400
395
396+#ifdef USE_STREAMK
397+{-
398+-- this is quadratic
399+{-# INLINE iterateScan #-}
400+iterateScan :: MonadAsync m => Int -> Int -> Int -> Stream m Int
401+iterateScan count len = toStream . iterateSource (K.scanl' (+) 0) count len
402+-}
403+
404+{-# INLINE iterateMapM #-}
405+iterateMapM :: MonadAsync m => Int -> Int -> Int -> Stream m Int
406+iterateMapM count len = toStream . iterateSource (K.mapM return) count len
407+
408+{-# INLINE iterateFilterEven #-}
409+iterateFilterEven :: MonadAsync m => Int -> Int -> Int -> Stream m Int
410+iterateFilterEven count len =
411+ toStream . iterateSource (K.filter even) count len
412+
413+{-# INLINE iterateTakeAll #-}
414+iterateTakeAll :: MonadAsync m => Int -> Int -> Int -> Int -> Stream m Int
415+iterateTakeAll value count len =
416+ toStream . iterateSource (K.take (value + 1)) count len
417+
418+{-# INLINE iterateDropOne #-}
419+iterateDropOne :: MonadAsync m => Int -> Int -> Int -> Stream m Int
420+iterateDropOne count len = toStream . iterateSource (K.drop 1) count len
421+
422+{-# INLINE iterateDropWhileTrue #-}
423+iterateDropWhileTrue :: MonadAsync m
424+ => Int -> Int -> Int -> Int -> Stream m Int
425+iterateDropWhileTrue value count len =
426+ toStream . iterateSource (K.dropWhile (<= (value + 1))) count len
427+
428+{-# INLINE iterateDropWhileFalse #-}
429+iterateDropWhileFalse :: MonadAsync m
430+ => Int -> Int -> Int -> Int -> Stream m Int
431+iterateDropWhileFalse value count len =
432+ toStream . iterateSource (K.dropWhile (> (value + 1))) count len
433+
434+#else
435+
401-- this is quadratic
436-- this is quadratic
402{-# INLINE iterateScan #-}
437{-# INLINE iterateScan #-}
403iterateScan :: MonadAsync m => Int -> Int -> Int -> Stream m Int
438iterateScan :: MonadAsync m => Int -> Int -> Int -> Stream m Int
@@ -426,15 +461,11 @@ iterateTakeAll value = iterateSource (S.take (value + 1))
426iterateDropOne :: MonadAsync m => Int -> Int -> Int -> Stream m Int
461iterateDropOne :: MonadAsync m => Int -> Int -> Int -> Stream m Int
427iterateDropOne = iterateSource (S.drop 1)
462iterateDropOne = iterateSource (S.drop 1)
428
463
429−{-# INLINE iterateDropWhileFalse #-}
430−iterateDropWhileFalse :: MonadAsync m
431− => Int -> Int -> Int -> Int -> Stream m Int
432−iterateDropWhileFalse value = iterateSource (S.dropWhile (> (value + 1)))
433−
434{-# INLINE iterateDropWhileTrue #-}
464{-# INLINE iterateDropWhileTrue #-}
435iterateDropWhileTrue :: MonadAsync m
465iterateDropWhileTrue :: MonadAsync m
436 => Int -> Int -> Int -> Int -> Stream m Int
466 => Int -> Int -> Int -> Int -> Stream m Int
437iterateDropWhileTrue value = iterateSource (S.dropWhile (<= (value + 1)))
467iterateDropWhileTrue value = iterateSource (S.dropWhile (<= (value + 1)))
468+#endif
438
469
439#ifdef USE_PRELUDE
470#ifdef USE_PRELUDE
440{-# INLINE tail #-}
471{-# INLINE tail #-}
@@ -455,8 +486,10 @@ o_n_stack_iterated :: Int -> [Benchmark]
455o_n_stack_iterated value = by10 `seq` by100 `seq`
486o_n_stack_iterated value = by10 `seq` by100 `seq`
456 [ bgroup "iterated"
487 [ bgroup "iterated"
457 [ benchIOSrc "mapM (n/10 x 10)" $ iterateMapM by10 10
488 [ benchIOSrc "mapM (n/10 x 10)" $ iterateMapM by10 10
489+#ifndef USE_STREAMK
458 , benchIOSrc "scanl' (quadratic) (n/100 x 100)" $
490 , benchIOSrc "scanl' (quadratic) (n/100 x 100)" $
459 iterateScan by100 100
491 iterateScan by100 100
492+#endif
460#ifdef USE_PRELUDE
493#ifdef USE_PRELUDE
461 , benchIOSrc "scanl1' (n/10 x 10)" $ iterateScanl1 by10 10
494 , benchIOSrc "scanl1' (n/10 x 10)" $ iterateScanl1 by10 10
462#endif
495#endif
@@ -465,8 +498,10 @@ o_n_stack_iterated value = by10 `seq` by100 `seq`
465 , benchIOSrc "takeAll (n/10 x 10)" $
498 , benchIOSrc "takeAll (n/10 x 10)" $
466 iterateTakeAll value by10 10
499 iterateTakeAll value by10 10
467 , benchIOSrc "dropOne (n/10 x 10)" $ iterateDropOne by10 10
500 , benchIOSrc "dropOne (n/10 x 10)" $ iterateDropOne by10 10
501+#ifdef USE_STREAMK
468 , benchIOSrc "dropWhileFalse (n/10 x 10)" $
502 , benchIOSrc "dropWhileFalse (n/10 x 10)" $
469 iterateDropWhileFalse value by10 10
503 iterateDropWhileFalse value by10 10
504+#endif
470 , benchIOSrc "dropWhileTrue (n/10 x 10)" $
505 , benchIOSrc "dropWhileTrue (n/10 x 10)" $
471 iterateDropWhileTrue value by10 10
506 iterateDropWhileTrue value by10 10
472#ifdef USE_PRELUDE
507#ifdef USE_PRELUDE
@@ -530,13 +565,5 @@ benchmarks moduleName size =
530 , o_1_space_pipesX4 size
565 , o_1_space_pipesX4 size
531 ]
566 ]
532 , bgroup (o_n_stack_prefix moduleName) (o_n_stack_iterated size)
567 , bgroup (o_n_stack_prefix moduleName) (o_n_stack_iterated size)
533− , bgroup (o_n_heap_prefix moduleName) $ Prelude.concat
568+ , bgroup (o_n_heap_prefix moduleName) (o_n_heap_buffering size)
534− [
535−#ifdef USE_PRELUDE
536− o_n_space_grouping size
537− ,
538−#endif
539− o_n_space_functor size
540− , o_n_heap_buffering size
541− ]
542 ]
569 ]
benchmark/Streamly/Benchmark/Data/Stream/Split.hs+3−2
@@ -143,7 +143,7 @@ splitOnSeq str inh =
143-- | Split on a word8 sequence.
143-- | Split on a word8 sequence.
144splitOnSeq100k :: Handle -> IO Int
144splitOnSeq100k :: Handle -> IO Int
145splitOnSeq100k inh = do
145splitOnSeq100k inh = do
146− arr <- A.fromStream $ S.replicate 100000 123
146+ arr <- A.fromStream $ IP.toStream $ S.fromSerial $ S.replicate 100000 123
147 (S.length $ IP.splitOnSeq arr FL.drain
147 (S.length $ IP.splitOnSeq arr FL.drain
148 $ S.unfold FH.read inh) -- >>= print
148 $ S.unfold FH.read inh) -- >>= print
149
149
@@ -220,8 +220,9 @@ o_1_space_reduce_read_split env =
220splitOnSeqUtf8 :: String -> Handle -> IO Int
220splitOnSeqUtf8 :: String -> Handle -> IO Int
221splitOnSeqUtf8 str inh =
221splitOnSeqUtf8 str inh =
222 (S.length $ IP.splitOnSeq (A.fromList str) FL.drain
222 (S.length $ IP.splitOnSeq (A.fromList str) FL.drain
223+ $ IP.fromStream
223 $ IUS.decodeUtf8Arrays
224 $ IUS.decodeUtf8Arrays
224− $ IFH.getChunks inh) -- >>= print
225+ $ IFH.readChunks inh) -- >>= print
225
226
226o_1_space_reduce_toChunks_split :: BenchEnv -> [Benchmark]
227o_1_space_reduce_toChunks_split :: BenchEnv -> [Benchmark]
227o_1_space_reduce_toChunks_split env =
228o_1_space_reduce_toChunks_split env =
benchmark/Streamly/Benchmark/Data/Stream/StreamK.hs+23−24
@@ -33,7 +33,6 @@ import Prelude hiding
33import qualified Prelude as P
33import qualified Prelude as P
34import qualified Data.List as List
34import qualified Data.List as List
35
35
36−import qualified Streamly.Internal.Control.Concurrent as S
37import qualified Streamly.Internal.Data.Stream.StreamK.Type as S
36import qualified Streamly.Internal.Data.Stream.StreamK.Type as S
38import qualified Streamly.Internal.Data.Stream.StreamK as S
37import qualified Streamly.Internal.Data.Stream.StreamK as S
39
38
@@ -129,7 +128,7 @@ unfoldr streamLen n = S.unfoldr step n
129 else Just (cnt, cnt + 1)
128 else Just (cnt, cnt + 1)
130
129
131{-# INLINE unfoldrM #-}
130{-# INLINE unfoldrM #-}
132−unfoldrM :: S.MonadAsync m => Int -> Int -> Stream m Int
131+unfoldrM :: Monad m => Int -> Int -> Stream m Int
133unfoldrM streamLen n = S.unfoldrMWith S.consM step n
132unfoldrM streamLen n = S.unfoldrMWith S.consM step n
134 where
133 where
135 step cnt =
134 step cnt =
@@ -142,7 +141,7 @@ repeat :: Int -> Int -> Stream m Int
142repeat streamLen = S.take streamLen . S.repeat
141repeat streamLen = S.take streamLen . S.repeat
143
142
144{-# INLINE repeatM #-}
143{-# INLINE repeatM #-}
145−repeatM :: S.MonadAsync m => Int -> Int -> Stream m Int
144+repeatM :: Monad m => Int -> Int -> Stream m Int
146repeatM streamLen = S.take streamLen . S.repeatM . return
145repeatM streamLen = S.take streamLen . S.repeatM . return
147
146
148{-# INLINE replicate #-}
147{-# INLINE replicate #-}
@@ -150,7 +149,7 @@ replicate :: Int -> Int -> Stream m Int
150replicate = S.replicate
149replicate = S.replicate
151
150
152{-# INLINE replicateM #-}
151{-# INLINE replicateM #-}
153−replicateM :: S.MonadAsync m => Int -> Int -> Stream m Int
152+replicateM :: Monad m => Int -> Int -> Stream m Int
154replicateM streamLen = S.replicateMWith S.consM streamLen . return
153replicateM streamLen = S.replicateMWith S.consM streamLen . return
155
154
156{-# INLINE iterate #-}
155{-# INLINE iterate #-}
@@ -158,7 +157,7 @@ iterate :: Int -> Int -> Stream m Int
158iterate streamLen = S.take streamLen . S.iterate (+1)
157iterate streamLen = S.take streamLen . S.iterate (+1)
159
158
160{-# INLINE iterateM #-}
159{-# INLINE iterateM #-}
161−iterateM :: S.MonadAsync m => Int -> Int -> Stream m Int
160+iterateM :: Monad m => Int -> Int -> Stream m Int
162iterateM streamLen = S.take streamLen . S.iterateM (return . (+1)) . return
161iterateM streamLen = S.take streamLen . S.iterateM (return . (+1)) . return
163
162
164{-# INLINE fromFoldable #-}
163{-# INLINE fromFoldable #-}
@@ -166,7 +165,7 @@ fromFoldable :: Int -> Int -> Stream m Int
166fromFoldable streamLen n = S.fromFoldable [n..n+streamLen]
165fromFoldable streamLen n = S.fromFoldable [n..n+streamLen]
167
166
168{-# INLINE fromFoldableM #-}
167{-# INLINE fromFoldableM #-}
169−fromFoldableM :: S.MonadAsync m => Int -> Int -> Stream m Int
168+fromFoldableM :: Monad m => Int -> Int -> Stream m Int
170fromFoldableM streamLen n =
169fromFoldableM streamLen n =
171 Prelude.foldr S.consM S.nil (Prelude.fmap return [n..n+streamLen])
170 Prelude.foldr S.consM S.nil (Prelude.fmap return [n..n+streamLen])
172
171
@@ -180,12 +179,13 @@ concatMapFoldableWith f g = Prelude.foldr (f . g) S.nil
180
179
181{-# INLINE concatMapFoldableSerial #-}
180{-# INLINE concatMapFoldableSerial #-}
182concatMapFoldableSerial :: Int -> Int -> Stream m Int
181concatMapFoldableSerial :: Int -> Int -> Stream m Int
182+concatMapFoldableSerial streamLen n =
183−concatMapFoldableSerial streamLen n = concatMapFoldableWith S.serial S.fromPure [n..n+streamLen]
183+ concatMapFoldableWith S.append S.fromPure [n..n+streamLen]
184
184
185{-# INLINE concatMapFoldableSerialM #-}
185{-# INLINE concatMapFoldableSerialM #-}
186concatMapFoldableSerialM :: Monad m => Int -> Int -> Stream m Int
186concatMapFoldableSerialM :: Monad m => Int -> Int -> Stream m Int
187concatMapFoldableSerialM streamLen n =
187concatMapFoldableSerialM streamLen n =
188− concatMapFoldableWith S.serial (S.fromEffect . return) [n..n+streamLen]
188+ concatMapFoldableWith S.append (S.fromEffect . return) [n..n+streamLen]
189
189
190-------------------------------------------------------------------------------
190-------------------------------------------------------------------------------
191-- Elimination
191-- Elimination
@@ -270,11 +270,11 @@ fmapK :: Monad m => Int -> Stream m Int -> m ()
270fmapK n = composeN n $ P.fmap (+ 1)
270fmapK n = composeN n $ P.fmap (+ 1)
271
271
272{-# INLINE mapM #-}
272{-# INLINE mapM #-}
273−mapM :: S.MonadAsync m => Int -> Stream m Int -> m ()
273+mapM :: Monad m => Int -> Stream m Int -> m ()
274mapM n = composeN n $ S.mapMWith S.consM return
274mapM n = composeN n $ S.mapMWith S.consM return
275
275
276{-# INLINE mapMSerial #-}
276{-# INLINE mapMSerial #-}
277−mapMSerial :: S.MonadAsync m => Int -> Stream m Int -> m ()
277+mapMSerial :: Monad m => Int -> Stream m Int -> m ()
278mapMSerial n = composeN n $ S.mapMSerial return
278mapMSerial n = composeN n $ S.mapMSerial return
279
279
280{-# INLINE filterEven #-}
280{-# INLINE filterEven #-}
@@ -326,7 +326,7 @@ foldlS :: Monad m => Int -> Stream m Int -> m ()
326foldlS n = composeN n $ S.foldlS (flip S.cons) S.nil
326foldlS n = composeN n $ S.foldlS (flip S.cons) S.nil
327
327
328{-# INLINE intersperse #-}
328{-# INLINE intersperse #-}
329−intersperse :: S.MonadAsync m => Int -> Int -> Stream m Int -> m ()
329+intersperse :: Monad m => Int -> Int -> Stream m Int -> m ()
330intersperse streamLen n = composeN n $ S.intersperse streamLen
330intersperse streamLen n = composeN n $ S.intersperse streamLen
331
331
332-------------------------------------------------------------------------------
332-------------------------------------------------------------------------------
@@ -335,8 +335,7 @@ intersperse streamLen n = composeN n $ S.intersperse streamLen
335
335
336{-# INLINE iterateSource #-}
336{-# INLINE iterateSource #-}
337iterateSource
337iterateSource
338− :: S.MonadAsync m
339− => Int -> (Stream m Int -> Stream m Int) -> Int -> Int -> Stream m Int
338+ :: Monad m => Int -> (Stream m Int -> Stream m Int) -> Int -> Int -> Stream m Int
340iterateSource iterStreamLen g i n = f i (unfoldrM iterStreamLen n)
339iterateSource iterStreamLen g i n = f i (unfoldrM iterStreamLen n)
341 where
340 where
342 f (0 :: Int) m = g m
341 f (0 :: Int) m = g m
@@ -344,37 +343,37 @@ iterateSource iterStreamLen g i n = f i (unfoldrM iterStreamLen n)
344
343
345-- this is quadratic
344-- this is quadratic
346{-# INLINE iterateScan #-}
345{-# INLINE iterateScan #-}
347−iterateScan :: S.MonadAsync m => Int -> Int -> Int -> Stream m Int
346+iterateScan :: Monad m => Int -> Int -> Int -> Stream m Int
348iterateScan iterStreamLen maxIters =
347iterateScan iterStreamLen maxIters =
349 iterateSource iterStreamLen (S.scanl' (+) 0) (maxIters `div` 10)
348 iterateSource iterStreamLen (S.scanl' (+) 0) (maxIters `div` 10)
350
349
351-- this is quadratic
350-- this is quadratic
352{-# INLINE iterateDropWhileFalse #-}
351{-# INLINE iterateDropWhileFalse #-}
353−iterateDropWhileFalse :: S.MonadAsync m => Int -> Int -> Int -> Int -> Stream m Int
352+iterateDropWhileFalse :: Monad m => Int -> Int -> Int -> Int -> Stream m Int
354iterateDropWhileFalse streamLen iterStreamLen maxIters =
353iterateDropWhileFalse streamLen iterStreamLen maxIters =
355 iterateSource iterStreamLen (S.dropWhile (> streamLen)) (maxIters `div` 10)
354 iterateSource iterStreamLen (S.dropWhile (> streamLen)) (maxIters `div` 10)
356
355
357{-# INLINE iterateMapM #-}
356{-# INLINE iterateMapM #-}
358−iterateMapM :: S.MonadAsync m => Int -> Int -> Int -> Stream m Int
357+iterateMapM :: Monad m => Int -> Int -> Int -> Stream m Int
359iterateMapM iterStreamLen =
358iterateMapM iterStreamLen =
360 iterateSource iterStreamLen (S.mapMWith S.consM return)
359 iterateSource iterStreamLen (S.mapMWith S.consM return)
361
360
362{-# INLINE iterateFilterEven #-}
361{-# INLINE iterateFilterEven #-}
363−iterateFilterEven :: S.MonadAsync m => Int -> Int -> Int -> Stream m Int
362+iterateFilterEven :: Monad m => Int -> Int -> Int -> Stream m Int
364iterateFilterEven iterStreamLen = iterateSource iterStreamLen (S.filter even)
363iterateFilterEven iterStreamLen = iterateSource iterStreamLen (S.filter even)
365
364
366{-# INLINE iterateTakeAll #-}
365{-# INLINE iterateTakeAll #-}
367−iterateTakeAll :: S.MonadAsync m => Int -> Int -> Int -> Int -> Stream m Int
366+iterateTakeAll :: Monad m => Int -> Int -> Int -> Int -> Stream m Int
368iterateTakeAll streamLen iterStreamLen =
367iterateTakeAll streamLen iterStreamLen =
369 iterateSource iterStreamLen (S.take streamLen)
368 iterateSource iterStreamLen (S.take streamLen)
370
369
371{-# INLINE iterateDropOne #-}
370{-# INLINE iterateDropOne #-}
372−iterateDropOne :: S.MonadAsync m => Int -> Int -> Int -> Stream m Int
371+iterateDropOne :: Monad m => Int -> Int -> Int -> Stream m Int
373iterateDropOne iterStreamLen = iterateSource iterStreamLen (S.drop 1)
372iterateDropOne iterStreamLen = iterateSource iterStreamLen (S.drop 1)
374
373
375{-# INLINE iterateDropWhileTrue #-}
374{-# INLINE iterateDropWhileTrue #-}
376−iterateDropWhileTrue :: S.MonadAsync m =>
375+iterateDropWhileTrue ::
377− Int -> Int -> Int -> Int -> Stream m Int
376+ Monad m => Int -> Int -> Int -> Int -> Stream m Int
378iterateDropWhileTrue streamLen iterStreamLen =
377iterateDropWhileTrue streamLen iterStreamLen =
379 iterateSource iterStreamLen (S.dropWhile (<= streamLen))
378 iterateSource iterStreamLen (S.dropWhile (<= streamLen))
380
379
@@ -392,7 +391,7 @@ zipWithM src = drain $ S.zipWithM (curry return) src src
392
391
393{-# INLINE sortByK #-}
392{-# INLINE sortByK #-}
394sortByK :: (a -> a -> Ordering) -> Stream m a -> Stream m a
393sortByK :: (a -> a -> Ordering) -> Stream m a -> Stream m a
395−sortByK f = S.concatPairsWith (S.mergeBy f) S.fromPure
394+sortByK f = S.mergeMapWith (S.mergeBy f) S.fromPure
396
395
397{-# INLINE sortBy #-}
396{-# INLINE sortBy #-}
398sortBy :: Monad m => Stream m Int -> m ()
397sortBy :: Monad m => Stream m Int -> m ()
@@ -494,7 +493,7 @@ sourceConcatMapId val n =
494{-# INLINE concatMapBySerial #-}
493{-# INLINE concatMapBySerial #-}
495concatMapBySerial :: Int -> Int -> Int -> IO ()
494concatMapBySerial :: Int -> Int -> Int -> IO ()
496concatMapBySerial outer inner n =
495concatMapBySerial outer inner n =
497− S.drain $ S.concatMapWith S.serial
496+ S.drain $ S.concatMapWith S.append
498 (unfoldrM inner)
497 (unfoldrM inner)
499 (unfoldrM outer n)
498 (unfoldrM outer n)
500
499
@@ -731,7 +730,7 @@ o_1_space_concat streamLen =
731 -- This is for comparison with concatMapFoldableWith
730 -- This is for comparison with concatMapFoldableWith
732 , benchIOSrc1 "concatMapWithId (n of 1) (fromFoldable)"
731 , benchIOSrc1 "concatMapWithId (n of 1) (fromFoldable)"
733 (S.drain
732 (S.drain
734− . S.concatMapWith S.serial id
733+ . S.concatMapWith S.append id
735 . sourceConcatMapId streamLen)
734 . sourceConcatMapId streamLen)
736
735
737 , benchIOSrc1 "concatMapBy serial (n of 1)"
736 , benchIOSrc1 "concatMapBy serial (n of 1)"
benchmark/Streamly/Benchmark/Data/Stream/ToStreamK.hs+14−10
@@ -33,11 +33,9 @@ import Prelude hiding
33import qualified Prelude as P
33import qualified Prelude as P
34-- import qualified Data.List as List
34-- import qualified Data.List as List
35
35
36−import qualified Streamly.Internal.Control.Concurrent as S
37import qualified Streamly.Internal.Data.Stream.StreamK.Type as S
36import qualified Streamly.Internal.Data.Stream.StreamK.Type as S
38import qualified Streamly.Internal.Data.Stream.StreamK as S
37import qualified Streamly.Internal.Data.Stream.StreamK as S
39import qualified Streamly.Internal.Data.Stream.StreamD as D
38import qualified Streamly.Internal.Data.Stream.StreamD as D
40−-- import qualified Streamly.Internal.Data.Stream as Stream
41import qualified Streamly.Internal.Data.Fold as Fold
39import qualified Streamly.Internal.Data.Fold as Fold
42
40
43import Gauge (bgroup, Benchmark, defaultMain)
41import Gauge (bgroup, Benchmark, defaultMain)
@@ -64,7 +62,7 @@ unfoldrD streamLen n = D.toStreamK (D.unfoldr step n)
64 else Just (cnt, cnt + 1)
62 else Just (cnt, cnt + 1)
65
63
66{-# INLINE unfoldrMD #-}
64{-# INLINE unfoldrMD #-}
67−unfoldrMD :: S.MonadAsync m => Int -> Int -> Stream m Int
65+unfoldrMD :: Monad m => Int -> Int -> Stream m Int
68unfoldrMD streamLen n = D.toStreamK (D.unfoldrM step n)
66unfoldrMD streamLen n = D.toStreamK (D.unfoldrM step n)
69 where
67 where
70 step cnt =
68 step cnt =
@@ -84,7 +82,7 @@ unfoldrK streamLen n = S.unfoldr step n
84-}
82-}
85
83
86{-# INLINE unfoldrMK #-}
84{-# INLINE unfoldrMK #-}
87−unfoldrMK :: S.MonadAsync m => Int -> Int -> Stream m Int
85+unfoldrMK :: Monad m => Int -> Int -> Stream m Int
88unfoldrMK streamLen n = S.unfoldrMWith S.consM step n
86unfoldrMK streamLen n = S.unfoldrMWith S.consM step n
89 where
87 where
90 step cnt =
88 step cnt =
@@ -97,7 +95,7 @@ repeat :: Monad m => Int -> Int -> Stream m Int
97repeat streamLen = S.take streamLen . D.toStreamK . D.repeat
95repeat streamLen = S.take streamLen . D.toStreamK . D.repeat
98
96
99{-# INLINE repeatM #-}
97{-# INLINE repeatM #-}
100−repeatM :: S.MonadAsync m => Int -> Int -> Stream m Int
98+repeatM :: Monad m => Int -> Int -> Stream m Int
101repeatM streamLen = S.take streamLen . D.toStreamK . D.repeatM . return
99repeatM streamLen = S.take streamLen . D.toStreamK . D.repeatM . return
102
100
103{-# INLINE replicate #-}
101{-# INLINE replicate #-}
@@ -105,7 +103,7 @@ replicate :: Monad m => Int -> Int -> Stream m Int
105replicate x y = D.toStreamK $ D.replicate x y
103replicate x y = D.toStreamK $ D.replicate x y
106
104
107{-# INLINE replicateM #-}
105{-# INLINE replicateM #-}
108−replicateM :: S.MonadAsync m => Int -> Int -> Stream m Int
106+replicateM :: Monad m => Int -> Int -> Stream m Int
109replicateM streamLen = D.toStreamK . D.replicateM streamLen . return
107replicateM streamLen = D.toStreamK . D.replicateM streamLen . return
110
108
111{-# INLINE iterate #-}
109{-# INLINE iterate #-}
@@ -113,7 +111,7 @@ iterate :: Monad m => Int -> Int -> Stream m Int
113iterate streamLen = S.take streamLen . D.toStreamK . D.iterate (+1)
111iterate streamLen = S.take streamLen . D.toStreamK . D.iterate (+1)
114
112
115{-# INLINE iterateM #-}
113{-# INLINE iterateM #-}
116−iterateM :: S.MonadAsync m => Int -> Int -> Stream m Int
114+iterateM :: Monad m => Int -> Int -> Stream m Int
117iterateM streamLen = S.take streamLen . D.toStreamK . D.iterateM (return . (+1)) . return
115iterateM streamLen = S.take streamLen . D.toStreamK . D.iterateM (return . (+1)) . return
118
116
119{-# INLINE fromFoldable #-}
117{-# INLINE fromFoldable #-}
@@ -121,7 +119,7 @@ fromFoldable :: Int -> Int -> Stream m Int
121fromFoldable streamLen n = S.fromFoldable [n..n+streamLen]
119fromFoldable streamLen n = S.fromFoldable [n..n+streamLen]
122
120
123{-# INLINE fromFoldableM #-}
121{-# INLINE fromFoldableM #-}
124−fromFoldableM :: S.MonadAsync m => Int -> Int -> Stream m Int
122+fromFoldableM :: Monad m => Int -> Int -> Stream m Int
125fromFoldableM streamLen n =
123fromFoldableM streamLen n =
126 Prelude.foldr S.consM S.nil (Prelude.fmap return [n..n+streamLen])
124 Prelude.foldr S.consM S.nil (Prelude.fmap return [n..n+streamLen])
127
125
@@ -225,7 +223,7 @@ composeN n f =
225{-# INLINE scanl' #-}
223{-# INLINE scanl' #-}
226scanl' :: Monad m => Int -> Stream m Int -> m ()
224scanl' :: Monad m => Int -> Stream m Int -> m ()
227scanl' n =
225scanl' n =
228− composeN n (D.toStreamK . D.scanOnce (Fold.foldl' (+) 0) . D.fromStreamK)
226+ composeN n (D.toStreamK . D.scan (Fold.foldl' (+) 0) . D.fromStreamK)
229
227
230{-# INLINE map #-}
228{-# INLINE map #-}
231map :: Monad m => Int -> Stream m Int -> m ()
229map :: Monad m => Int -> Stream m Int -> m ()
@@ -238,7 +236,7 @@ fmapK n = composeN n $ P.fmap (+ 1)
238-}
236-}
239
237
240{-# INLINE mapM #-}
238{-# INLINE mapM #-}
241−mapM :: S.MonadAsync m => Int -> Stream m Int -> m ()
239+mapM :: Monad m => Int -> Stream m Int -> m ()
242mapM n = composeN n (D.toStreamK . D.mapM return . D.fromStreamK)
240mapM n = composeN n (D.toStreamK . D.mapM return . D.fromStreamK)
243
241
244{-
242{-
@@ -620,6 +618,8 @@ filterAllInNestedList str = do
620moduleName :: String
618moduleName :: String
621moduleName = "Data.Stream.ToStreamK"
619moduleName = "Data.Stream.ToStreamK"
622
620
621+-- Generation of StreamK using StreamD generation functions and eleminating
622+-- using StreamK drain.
623o_1_space_generation :: Int -> Benchmark
623o_1_space_generation :: Int -> Benchmark
624o_1_space_generation streamLen =
624o_1_space_generation streamLen =
625 bgroup "generation"
625 bgroup "generation"
@@ -640,6 +640,7 @@ o_1_space_generation streamLen =
640 , benchFold "concatMapFoldableWithM" drain (concatMapFoldableSerialM streamLen)
640 , benchFold "concatMapFoldableWithM" drain (concatMapFoldableSerialM streamLen)
641 ]
641 ]
642
642
643+-- Generating using StreamK and eliminating using StreamD folds.
643o_1_space_elimination :: Int -> Benchmark
644o_1_space_elimination :: Int -> Benchmark
644o_1_space_elimination streamLen =
645o_1_space_elimination streamLen =
645 bgroup "elimination"
646 bgroup "elimination"
@@ -671,6 +672,8 @@ o_1_space_nested streamLen =
671 streamLen3 = round (P.fromIntegral streamLen**(1/3::P.Double)) -- triple nested loop
672 streamLen3 = round (P.fromIntegral streamLen**(1/3::P.Double)) -- triple nested loop
672-}
673-}
673
674
675+-- Generate using StreamK and transform using StreamD transformation functions
676+-- and then drain using StreamK.
674o_1_space_transformation :: Int -> Benchmark
677o_1_space_transformation :: Int -> Benchmark
675o_1_space_transformation streamLen =
678o_1_space_transformation streamLen =
676 bgroup "transformation"
679 bgroup "transformation"
@@ -694,6 +697,7 @@ o_1_space_transformationX4 streamLen =
694 -- , benchFold "concatMap" (concatMap 4) (unfoldrM streamLen16)
697 -- , benchFold "concatMap" (concatMap 4) (unfoldrM streamLen16)
695 ]
698 ]
696
699
700+-- Generate using K, fold using K, concat using D.concatMap
697o_1_space_concat :: Int -> Benchmark
701o_1_space_concat :: Int -> Benchmark
698o_1_space_concat streamLen =
702o_1_space_concat streamLen =
699 bgroup "concat"
703 bgroup "concat"
benchmark/Streamly/Benchmark/Data/Stream/Transform.hs+137−30
@@ -26,32 +26,47 @@
26
26
27module Stream.Transform (benchmarks) where
27module Stream.Transform (benchmarks) where
28
28
29−import Control.DeepSeq (NFData(..))
30import Control.Monad.IO.Class (MonadIO(..))
29import Control.Monad.IO.Class (MonadIO(..))
31−import Data.Functor.Identity (Identity(..))
32
30
33import System.Random (randomRIO)
31import System.Random (randomRIO)
34
32
35import qualified Streamly.Internal.Data.Fold as FL
33import qualified Streamly.Internal.Data.Fold as FL
36
34
37−import qualified Prelude
38import qualified Stream.Common as Common
35import qualified Stream.Common as Common
39−import qualified Streamly.Internal.Data.Fold as Fold
40import qualified Streamly.Internal.Data.Unfold as Unfold
36import qualified Streamly.Internal.Data.Unfold as Unfold
37+
41#ifdef USE_PRELUDE
38#ifdef USE_PRELUDE
39+import Control.DeepSeq (NFData(..))
40+import Data.Functor.Identity (Identity(..))
41+import qualified Prelude
42+import qualified Streamly.Internal.Data.Fold as Fold
42import qualified Streamly.Internal.Data.Stream.IsStream as Stream
43import qualified Streamly.Internal.Data.Stream.IsStream as Stream
43import Streamly.Internal.Data.Time.Units
44import Streamly.Internal.Data.Time.Units
44#else
45#else
46+import Streamly.Internal.Data.Stream.StreamD (Stream)
47+import qualified Streamly.Internal.Data.Stream.StreamD as Stream
48+#ifndef USE_STREAMLY_CORE
45import qualified Streamly.Internal.Data.Stream.Time as Stream
49import qualified Streamly.Internal.Data.Stream.Time as Stream
50+#endif
51+#ifdef USE_STREAMK
52+import Control.DeepSeq (NFData(..))
53+import Data.Functor.Identity (Identity(..))
54+import qualified Prelude
46−import qualified Streamly.Internal.Data.Stream as Stream
55+import qualified Streamly.Internal.Data.Fold as Fold
56+import Streamly.Internal.Data.Stream.StreamK (StreamK)
57+import qualified Streamly.Internal.Data.Stream.StreamK as StreamK
58+#endif
47#endif
59#endif
48
60
49import Gauge
61import Gauge
50−import Streamly.Internal.Data.Stream (Stream)
51import Stream.Common hiding (scanl')
62import Stream.Common hiding (scanl')
52import Streamly.Benchmark.Common
63import Streamly.Benchmark.Common
53import Prelude hiding (sequence, mapM)
64import Prelude hiding (sequence, mapM)
54
65
66+#ifdef USE_PRELUDE
67+type Stream = Stream.SerialT
68+#endif
69+
55-------------------------------------------------------------------------------
70-------------------------------------------------------------------------------
56-- Pipelines (stream-to-stream transformations)
71-- Pipelines (stream-to-stream transformations)
57-------------------------------------------------------------------------------
72-------------------------------------------------------------------------------
@@ -64,32 +79,36 @@ import Prelude hiding (sequence, mapM)
64-- Traversable Instance
79-- Traversable Instance
65-------------------------------------------------------------------------------
80-------------------------------------------------------------------------------
66
81
82+#ifdef USE_STREAMK
67{-# INLINE traversableTraverse #-}
83{-# INLINE traversableTraverse #-}
68−traversableTraverse :: Stream Identity Int -> IO (Stream Identity Int)
84+traversableTraverse :: StreamK Identity Int -> IO (StreamK Identity Int)
69traversableTraverse = traverse return
85traversableTraverse = traverse return
70
86
71{-# INLINE traversableSequenceA #-}
87{-# INLINE traversableSequenceA #-}
72−traversableSequenceA :: Stream Identity Int -> IO (Stream Identity Int)
88+traversableSequenceA :: StreamK Identity Int -> IO (StreamK Identity Int)
73traversableSequenceA = sequenceA . Prelude.fmap return
89traversableSequenceA = sequenceA . Prelude.fmap return
74
90
75{-# INLINE traversableMapM #-}
91{-# INLINE traversableMapM #-}
76−traversableMapM :: Stream Identity Int -> IO (Stream Identity Int)
92+traversableMapM :: StreamK Identity Int -> IO (StreamK Identity Int)
77traversableMapM = Prelude.mapM return
93traversableMapM = Prelude.mapM return
78
94
79{-# INLINE traversableSequence #-}
95{-# INLINE traversableSequence #-}
80−traversableSequence :: Stream Identity Int -> IO (Stream Identity Int)
96+traversableSequence :: StreamK Identity Int -> IO (StreamK Identity Int)
81traversableSequence = Prelude.sequence . Prelude.fmap return
97traversableSequence = Prelude.sequence . Prelude.fmap return
82
98
83{-# INLINE benchPureSinkIO #-}
99{-# INLINE benchPureSinkIO #-}
84benchPureSinkIO
100benchPureSinkIO
85 :: NFData b
101 :: NFData b
86− => Int -> String -> (Stream Identity Int -> IO b) -> Benchmark
102+ => Int -> String -> (StreamK Identity Int -> IO b) -> Benchmark
87benchPureSinkIO value name f =
103benchPureSinkIO value name f =
104+ bench name
88− bench name $ nfIO $ randomRIO (1, 1) >>= f . sourceUnfoldr value
105+ $ nfIO $ randomRIO (1, 1) >>= f . fromStream . sourceUnfoldr value
89
106
90−instance NFData a => NFData (Stream Identity a) where
107+instance NFData a => NFData (StreamK Identity a) where
91 {-# INLINE rnf #-}
108 {-# INLINE rnf #-}
109+ rnf xs =
110+ runIdentity
92− rnf xs = runIdentity $ Stream.fold (Fold.foldl' (\_ x -> rnf x) ()) xs
111+ $ Stream.fold (Fold.foldl' (\_ x -> rnf x) ()) (toStream xs)
93
112
94o_n_space_traversable :: Int -> [Benchmark]
113o_n_space_traversable :: Int -> [Benchmark]
95o_n_space_traversable value =
114o_n_space_traversable value =
@@ -102,6 +121,7 @@ o_n_space_traversable value =
102 , benchPureSinkIO value "sequence" traversableSequence
121 , benchPureSinkIO value "sequence" traversableSequence
103 ]
122 ]
104 ]
123 ]
124+#endif
105
125
106-------------------------------------------------------------------------------
126-------------------------------------------------------------------------------
107-- maps and scans
127-- maps and scans
@@ -166,13 +186,21 @@ timestamped :: (MonadAsync m) => Stream m Int -> m ()
166timestamped = Stream.drain . Stream.timestamped
186timestamped = Stream.drain . Stream.timestamped
167#endif
187#endif
168
188
189+#ifdef USE_STREAMK
169{-# INLINE foldrS #-}
190{-# INLINE foldrS #-}
170foldrS :: MonadIO m => Int -> Stream m Int -> m ()
191foldrS :: MonadIO m => Int -> Stream m Int -> m ()
192+foldrS n =
171−foldrS n = composeN n $ Stream.foldrS Stream.cons Stream.nil
193+ composeN n (toStream . StreamK.foldrS StreamK.cons StreamK.nil . fromStream)
172
194
173{-# INLINE foldrSMap #-}
195{-# INLINE foldrSMap #-}
174foldrSMap :: MonadIO m => Int -> Stream m Int -> m ()
196foldrSMap :: MonadIO m => Int -> Stream m Int -> m ()
197+foldrSMap n =
198+ composeN n
199+ ( toStream
175−foldrSMap n = composeN n $ Stream.foldrS (\x xs -> x + 1 `Stream.cons` xs) Stream.nil
200+ . StreamK.foldrS (\x xs -> x + 1 `StreamK.cons` xs) StreamK.nil
201+ . fromStream
202+ )
203+#endif
176
204
177{-
205{-
178{-# INLINE foldrT #-}
206{-# INLINE foldrT #-}
@@ -195,14 +223,17 @@ o_1_space_mapping value =
195 [ bgroup
223 [ bgroup
196 "mapping"
224 "mapping"
197 [
225 [
226+#ifdef USE_STREAMK
198 -- Right folds
227 -- Right folds
199 benchIOSink value "foldrS" (foldrS 1)
228 benchIOSink value "foldrS" (foldrS 1)
200 , benchIOSink value "foldrSMap" (foldrSMap 1)
229 , benchIOSink value "foldrSMap" (foldrSMap 1)
230+ ,
231+#endif
201 -- , benchIOSink value "foldrT" (foldrT 1)
232 -- , benchIOSink value "foldrT" (foldrT 1)
202 -- , benchIOSink value "foldrTMap" (foldrTMap 1)
233 -- , benchIOSink value "foldrTMap" (foldrTMap 1)
203
234
204 -- Mapping
235 -- Mapping
205− , benchIOSink value "map" (mapN 1)
236+ benchIOSink value "map" (mapN 1)
206 , bench "sequence" $ nfIO $ randomRIO (1, 1000) >>= \n ->
237 , bench "sequence" $ nfIO $ randomRIO (1, 1000) >>= \n ->
207 sequence (sourceUnfoldrAction value n)
238 sequence (sourceUnfoldrAction value n)
208 , benchIOSink value "mapM" (mapM 1)
239 , benchIOSink value "mapM" (mapM 1)
@@ -273,6 +304,73 @@ o_1_space_functor value =
273 ]
304 ]
274 ]
305 ]
275
306
307+-------------------------------------------------------------------------------
308+-- Iteration/looping utilities
309+-------------------------------------------------------------------------------
310+
311+{-# INLINE iterateN #-}
312+iterateN :: (Int -> a -> a) -> a -> Int -> a
313+iterateN g initial count = f count initial
314+
315+ where
316+
317+ f (0 :: Int) x = x
318+ f i x = f (i - 1) (g i x)
319+
320+#ifdef USE_STREAMK
321+-- Iterate a transformation over a singleton stream
322+{-# INLINE iterateSingleton #-}
323+iterateSingleton :: Applicative m =>
324+ (Int -> StreamK m Int -> StreamK m Int)
325+ -> Int
326+ -> Int
327+ -> Stream m Int
328+iterateSingleton g count n = toStream $ iterateN g (StreamK.fromPure n) count
329+#else
330+-- Iterate a transformation over a singleton stream
331+{-# INLINE iterateSingleton #-}
332+iterateSingleton :: Applicative m =>
333+ (Int -> Stream m Int -> Stream m Int)
334+ -> Int
335+ -> Int
336+ -> Stream m Int
337+iterateSingleton g count n = iterateN g (Stream.fromPure n) count
338+#endif
339+
340+{-
341+-- XXX need to check why this is slower than the explicit recursion above, even
342+-- if the above code is written in a foldr like head recursive way. We also
343+-- need to try this with foldlM' once #150 is fixed.
344+-- However, it is perhaps best to keep the iteration benchmarks independent of
345+-- foldrM and any related fusion issues.
346+{-# INLINE _iterateSingleton #-}
347+_iterateSingleton ::
348+ Monad m
349+ => (Int -> Stream m Int -> Stream m Int)
350+ -> Int
351+ -> Int
352+ -> Stream m Int
353+_iterateSingleton g value n = S.foldrM g (return n) $ sourceIntFromTo value n
354+-}
355+
356+o_n_space_iterated :: Int -> [Benchmark]
357+o_n_space_iterated value =
358+ [ bgroup "iterated"
359+ [ benchIO "(+) (n times) (baseline)" $ \i0 ->
360+ iterateN (\i acc -> acc >>= \n -> return $ i + n) (return i0) value
361+ , benchIOSrc "(<$) (n times)" $
362+ iterateSingleton (<$) value
363+ , benchIOSrc "fmap (n times)" $
364+ iterateSingleton (fmap . (+)) value
365+ {-
366+ , benchIOSrc fromSerial "_(<$) (n times)" $
367+ _iterateSingleton (<$) value
368+ , benchIOSrc fromSerial "_fmap (n times)" $
369+ _iterateSingleton (fmap . (+)) value
370+ -}
371+ ]
372+ ]
373+
276-------------------------------------------------------------------------------
374-------------------------------------------------------------------------------
277-- Size reducing transformations (filtering)
375-- Size reducing transformations (filtering)
278-------------------------------------------------------------------------------
376-------------------------------------------------------------------------------
@@ -317,6 +415,7 @@ takeWhileTrue value n = composeN n $ Stream.takeWhile (<= (value + 1))
317takeWhileMTrue :: MonadIO m => Int -> Int -> Stream m Int -> m ()
415takeWhileMTrue :: MonadIO m => Int -> Int -> Stream m Int -> m ()
318takeWhileMTrue value n = composeN n $ Stream.takeWhileM (return . (<= (value + 1)))
416takeWhileMTrue value n = composeN n $ Stream.takeWhileM (return . (<= (value + 1)))
319
417
418+#if !defined(USE_STREAMLY_CORE) && !defined(USE_PRELUDE)
320{-# INLINE takeInterval #-}
419{-# INLINE takeInterval #-}
321takeInterval :: Double -> Int -> Stream IO Int -> IO ()
420takeInterval :: Double -> Int -> Stream IO Int -> IO ()
322takeInterval i n = composeN n (Stream.takeInterval i)
421takeInterval i n = composeN n (Stream.takeInterval i)
@@ -329,6 +428,18 @@ takeInterval i n = composeN n (Stream.takeInterval i)
329-- inspect $ 'takeInterval `hasNoType` ''D.Step
428-- inspect $ 'takeInterval `hasNoType` ''D.Step
330#endif
429#endif
331
430
431+{-# INLINE dropInterval #-}
432+dropInterval :: Double -> Int -> Stream IO Int -> IO ()
433+dropInterval i n = composeN n (Stream.dropInterval i)
434+
435+-- Inspection testing is disabled for dropInterval
436+-- Enable it when looking at it throughly
437+#ifdef INSPECTION
438+-- inspect $ hasNoTypeClasses 'dropInterval
439+-- inspect $ 'dropInterval `hasNoType` ''D.Step
440+#endif
441+#endif
442+
332{-# INLINE dropOne #-}
443{-# INLINE dropOne #-}
333dropOne :: MonadIO m => Int -> Stream m Int -> m ()
444dropOne :: MonadIO m => Int -> Stream m Int -> m ()
334dropOne n = composeN n $ Stream.drop 1
445dropOne n = composeN n $ Stream.drop 1
@@ -356,17 +467,6 @@ _intervalsOfSum :: MonadAsync m => Double -> Int -> Stream m Int -> m ()
356_intervalsOfSum i n = composeN n (Stream.intervalsOf i FL.sum)
467_intervalsOfSum i n = composeN n (Stream.intervalsOf i FL.sum)
357#endif
468#endif
358
469
359−{-# INLINE dropInterval #-}
360−dropInterval :: Double -> Int -> Stream IO Int -> IO ()
361−dropInterval i n = composeN n (Stream.dropInterval i)
362−
363−-- Inspection testing is disabled for dropInterval
364−-- Enable it when looking at it throughly
365−#ifdef INSPECTION
366−-- inspect $ hasNoTypeClasses 'dropInterval
367−-- inspect $ 'dropInterval `hasNoType` ''D.Step
368−#endif
369−
370{-# INLINE findIndices #-}
470{-# INLINE findIndices #-}
371findIndices :: MonadIO m => Int -> Int -> Stream m Int -> m ()
471findIndices :: MonadIO m => Int -> Int -> Stream m Int -> m ()
372findIndices value n = composeN n $ Stream.findIndices (== (value + 1))
472findIndices value n = composeN n $ Stream.findIndices (== (value + 1))
@@ -421,8 +521,10 @@ o_1_space_filtering value =
421 -- , benchIOSink value "takeWhileM-true" (_takeWhileMTrue value 1)
521 -- , benchIOSink value "takeWhileM-true" (_takeWhileMTrue value 1)
422 , benchIOSink value "drop-one" (dropOne 1)
522 , benchIOSink value "drop-one" (dropOne 1)
423 , benchIOSink value "drop-all" (dropAll value 1)
523 , benchIOSink value "drop-all" (dropAll value 1)
524+#if !defined(USE_STREAMLY_CORE) && !defined(USE_PRELUDE)
424 , benchIOSink value "takeInterval-all" (takeInterval 10000 1)
525 , benchIOSink value "takeInterval-all" (takeInterval 10000 1)
425 , benchIOSink value "dropInterval-all" (dropInterval 10000 1)
526 , benchIOSink value "dropInterval-all" (dropInterval 10000 1)
527+#endif
426 , benchIOSink value "dropWhile-true" (dropWhileTrue value 1)
528 , benchIOSink value "dropWhile-true" (dropWhileTrue value 1)
427 -- , benchIOSink value "dropWhileM-true" (_dropWhileMTrue value 1)
529 -- , benchIOSink value "dropWhileM-true" (_dropWhileMTrue value 1)
428 , benchIOSink
530 , benchIOSink
@@ -574,7 +676,12 @@ benchmarks moduleName size =
574 , o_1_space_indexingX4 size
676 , o_1_space_indexingX4 size
575 ]
677 ]
576 , bgroup (o_n_space_prefix moduleName) $ Prelude.concat
678 , bgroup (o_n_space_prefix moduleName) $ Prelude.concat
679+ [
680+#ifdef USE_STREAMK
577− [ o_n_space_traversable size
681+ o_n_space_traversable size
682+ ,
683+#endif
578− , o_n_space_mapping size
684+ o_n_space_mapping size
685+ , o_n_space_iterated size
579 ]
686 ]
580 ]
687 ]
benchmark/Streamly/Benchmark/Data/Unfold.hs+1−2
@@ -32,11 +32,10 @@ import qualified Streamly.FileSystem.Handle as FH
32import qualified Streamly.Internal.Data.Fold as FL
32import qualified Streamly.Internal.Data.Fold as FL
33import qualified Streamly.Internal.Data.Unfold as UF
33import qualified Streamly.Internal.Data.Unfold as UF
34import qualified Streamly.Internal.Data.Unfold.Exception as UF
34import qualified Streamly.Internal.Data.Unfold.Exception as UF
35−import qualified Streamly.Internal.Data.Stream as S
35+import qualified Streamly.Internal.Data.Stream.StreamD as S
36import qualified Streamly.Internal.Data.Stream.StreamD as D
36import qualified Streamly.Internal.Data.Stream.StreamD as D
37import qualified Streamly.Internal.Data.Stream.StreamK as K
37import qualified Streamly.Internal.Data.Stream.StreamK as K
38
38
39−
40import Gauge hiding (env)
39import Gauge hiding (env)
41import Prelude hiding (take, filter, zipWith, map, mapM, takeWhile)
40import Prelude hiding (take, filter, zipWith, map, mapM, takeWhile)
42import Streamly.Benchmark.Common
41import Streamly.Benchmark.Common
benchmark/Streamly/Benchmark/FileSystem/Handle/Read.hs+23−16
@@ -29,14 +29,16 @@ import GHC.Magic (inline)
29import GHC.Magic (noinline)
29import GHC.Magic (noinline)
30import System.IO (Handle)
30import System.IO (Handle)
31
31
32+import qualified Streamly.Data.Stream as Stream
33+import qualified Streamly.Data.Fold as Fold
32import qualified Streamly.FileSystem.Handle as FH
34import qualified Streamly.FileSystem.Handle as FH
33import qualified Streamly.Internal.Data.Array as A
35import qualified Streamly.Internal.Data.Array as A
34import qualified Streamly.Internal.Data.Array.Type as AT
36import qualified Streamly.Internal.Data.Array.Type as AT
35import qualified Streamly.Internal.Data.Fold as FL
37import qualified Streamly.Internal.Data.Fold as FL
36−import qualified Streamly.Internal.Data.Stream.IsStream as IP
38+import qualified Streamly.Internal.Data.Stream.StreamD as IP
37import qualified Streamly.Internal.FileSystem.Handle as IFH
39import qualified Streamly.Internal.FileSystem.Handle as IFH
38import qualified Streamly.Internal.Unicode.Stream as IUS
40import qualified Streamly.Internal.Unicode.Stream as IUS
39−import qualified Streamly.Prelude as S
41+import qualified Streamly.Data.Stream.Prelude as S
40import qualified Streamly.Unicode.Stream as SS
42import qualified Streamly.Unicode.Stream as SS
41
43
42import Gauge hiding (env)
44import Gauge hiding (env)
@@ -61,7 +63,7 @@ import Test.Inspection
61
63
62-- | Get the last byte from a file bytestream.
64-- | Get the last byte from a file bytestream.
63readLast :: Handle -> IO (Maybe Word8)
65readLast :: Handle -> IO (Maybe Word8)
64−readLast = S.last . S.unfold FH.reader
66+readLast = S.fold Fold.last . S.unfold FH.reader
65
67
66#ifdef INSPECTION
68#ifdef INSPECTION
67inspect $ hasNoTypeClasses 'readLast
69inspect $ hasNoTypeClasses 'readLast
@@ -73,7 +75,7 @@ inspect $ 'readLast `hasNoType` ''MA.ArrayUnsafe -- FH.read/A.read
73-- assert that flattenArrays constructors are not present
75-- assert that flattenArrays constructors are not present
74-- | Count the number of bytes in a file.
76-- | Count the number of bytes in a file.
75readCountBytes :: Handle -> IO Int
77readCountBytes :: Handle -> IO Int
76−readCountBytes = S.length . S.unfold FH.reader
78+readCountBytes = S.fold Fold.length . S.unfold FH.reader
77
79
78#ifdef INSPECTION
80#ifdef INSPECTION
79inspect $ hasNoTypeClasses 'readCountBytes
81inspect $ hasNoTypeClasses 'readCountBytes
@@ -85,7 +87,7 @@ inspect $ 'readCountBytes `hasNoType` ''MA.ArrayUnsafe -- FH.read/A.read
85-- | Count the number of lines in a file.
87-- | Count the number of lines in a file.
86readCountLines :: Handle -> IO Int
88readCountLines :: Handle -> IO Int
87readCountLines =
89readCountLines =
88− S.length
90+ S.fold Fold.length
89 . IUS.lines FL.drain
91 . IUS.lines FL.drain
90 . SS.decodeLatin1
92 . SS.decodeLatin1
91 . S.unfold FH.reader
93 . S.unfold FH.reader
@@ -100,7 +102,7 @@ inspect $ 'readCountLines `hasNoType` ''MA.ArrayUnsafe -- FH.read/A.read
100-- | Count the number of words in a file.
102-- | Count the number of words in a file.
101readCountWords :: Handle -> IO Int
103readCountWords :: Handle -> IO Int
102readCountWords =
104readCountWords =
103− S.length
105+ S.fold Fold.length
104 . IUS.words FL.drain
106 . IUS.words FL.drain
105 . SS.decodeLatin1
107 . SS.decodeLatin1
106 . S.unfold FH.reader
108 . S.unfold FH.reader
@@ -112,7 +114,7 @@ inspect $ hasNoTypeClasses 'readCountWords
112
114
113-- | Sum the bytes in a file.
115-- | Sum the bytes in a file.
114readSumBytes :: Handle -> IO Word8
116readSumBytes :: Handle -> IO Word8
115−readSumBytes = S.sum . S.unfold FH.reader
117+readSumBytes = S.fold Fold.sum . S.unfold FH.reader
116
118
117#ifdef INSPECTION
119#ifdef INSPECTION
118inspect $ hasNoTypeClasses 'readSumBytes
120inspect $ hasNoTypeClasses 'readSumBytes
@@ -132,19 +134,19 @@ inspect $ 'readSumBytes `hasNoType` ''MA.ArrayUnsafe -- FH.read/A.read
132-- fusion-plugin to propagate INLINE phase information such that this problem
134-- fusion-plugin to propagate INLINE phase information such that this problem
133-- does not occur.
135-- does not occur.
134readDrain :: Handle -> IO ()
136readDrain :: Handle -> IO ()
135−readDrain inh = S.drain $ S.unfold FH.reader inh
137+readDrain inh = S.fold Fold.drain $ S.unfold FH.reader inh
136
138
137-- XXX investigate why we need an INLINE in this case (GHC)
139-- XXX investigate why we need an INLINE in this case (GHC)
138{-# INLINE readDecodeLatin1 #-}
140{-# INLINE readDecodeLatin1 #-}
139readDecodeLatin1 :: Handle -> IO ()
141readDecodeLatin1 :: Handle -> IO ()
140readDecodeLatin1 inh =
142readDecodeLatin1 inh =
141− S.drain
143+ S.fold Fold.drain
142 $ SS.decodeLatin1
144 $ SS.decodeLatin1
143 $ S.unfold FH.reader inh
145 $ S.unfold FH.reader inh
144
146
145readDecodeUtf8 :: Handle -> IO ()
147readDecodeUtf8 :: Handle -> IO ()
146readDecodeUtf8 inh =
148readDecodeUtf8 inh =
147− S.drain
149+ S.fold Fold.drain
148 $ SS.decodeUtf8
150 $ SS.decodeUtf8
149 $ S.unfold FH.reader inh
151 $ S.unfold FH.reader inh
150
152
@@ -187,7 +189,7 @@ o_1_space_reduce_read env =
187-- | Count the number of lines in a file.
189-- | Count the number of lines in a file.
188getChunksConcatUnfoldCountLines :: Handle -> IO Int
190getChunksConcatUnfoldCountLines :: Handle -> IO Int
189getChunksConcatUnfoldCountLines inh =
191getChunksConcatUnfoldCountLines inh =
190− S.length
192+ S.fold Fold.length
191 $ IUS.lines FL.drain
193 $ IUS.lines FL.drain
192 $ SS.decodeLatin1
194 $ SS.decodeLatin1
193 -- XXX replace with toBytes
195 -- XXX replace with toBytes
@@ -212,15 +214,18 @@ o_1_space_reduce_toBytes env =
212-------------------------------------------------------------------------------
214-------------------------------------------------------------------------------
213
215
214chunksOfSum :: Int -> Handle -> IO Int
216chunksOfSum :: Int -> Handle -> IO Int
217+chunksOfSum n inh =
215−chunksOfSum n inh = S.length $ S.chunksOf n FL.sum (S.unfold FH.reader inh)
218+ S.fold Fold.length $ IP.chunksOf n FL.sum (S.unfold FH.reader inh)
216
219
217foldManyPostChunksOfSum :: Int -> Handle -> IO Int
220foldManyPostChunksOfSum :: Int -> Handle -> IO Int
218foldManyPostChunksOfSum n inh =
221foldManyPostChunksOfSum n inh =
222+ S.fold Fold.length
219− S.length $ IP.foldManyPost (FL.take n FL.sum) (S.unfold FH.reader inh)
223+ $ IP.foldManyPost (FL.take n FL.sum) (S.unfold FH.reader inh)
220
224
221foldManyChunksOfSum :: Int -> Handle -> IO Int
225foldManyChunksOfSum :: Int -> Handle -> IO Int
222foldManyChunksOfSum n inh =
226foldManyChunksOfSum n inh =
227+ S.fold Fold.length
223− S.length $ IP.foldMany (FL.take n FL.sum) (S.unfold FH.reader inh)
228+ $ IP.foldMany (FL.take n FL.sum) (S.unfold FH.reader inh)
224
229
225-- XXX investigate why we need an INLINE in this case (GHC)
230-- XXX investigate why we need an INLINE in this case (GHC)
226-- Even though allocations remain the same in both cases inlining improves time
231-- Even though allocations remain the same in both cases inlining improves time
@@ -230,7 +235,8 @@ foldManyChunksOfSum n inh =
230chunksOf :: Int -> Handle -> IO Int
235chunksOf :: Int -> Handle -> IO Int
231chunksOf n inh =
236chunksOf n inh =
232 -- writeNUnsafe gives 2.5x boost here over writeN.
237 -- writeNUnsafe gives 2.5x boost here over writeN.
238+ S.fold Fold.length
233− S.length $ S.chunksOf n (AT.writeNUnsafe n) (S.unfold FH.reader inh)
239+ $ IP.chunksOf n (AT.writeNUnsafe n) (S.unfold FH.reader inh)
234
240
235#ifdef INSPECTION
241#ifdef INSPECTION
236inspect $ hasNoTypeClasses 'chunksOf
242inspect $ hasNoTypeClasses 'chunksOf
@@ -243,7 +249,8 @@ inspect $ 'chunksOf `hasNoType` ''IUF.ConcatState -- FH.read/UF.many
243
249
244{-# INLINE arraysOf #-}
250{-# INLINE arraysOf #-}
245arraysOf :: Int -> Handle -> IO Int
251arraysOf :: Int -> Handle -> IO Int
252+arraysOf n inh =
246−arraysOf n inh = S.length $ IP.arraysOf n (S.unfold FH.reader inh)
253+ S.fold Fold.length $ Stream.arraysOf n (S.unfold FH.reader inh)
247
254
248o_1_space_reduce_read_grouped :: BenchEnv -> [Benchmark]
255o_1_space_reduce_read_grouped :: BenchEnv -> [Benchmark]
249o_1_space_reduce_read_grouped env =
256o_1_space_reduce_read_grouped env =
benchmark/Streamly/Benchmark/FileSystem/Handle/ReadWrite.hs+1−1
@@ -32,7 +32,7 @@ import qualified Streamly.FileSystem.Handle as FH
32import qualified Streamly.Internal.Data.Unfold as IUF
32import qualified Streamly.Internal.Data.Unfold as IUF
33import qualified Streamly.Internal.FileSystem.Handle as IFH
33import qualified Streamly.Internal.FileSystem.Handle as IFH
34import qualified Streamly.Data.Array as A
34import qualified Streamly.Data.Array as A
35−import qualified Streamly.Prelude as S
35+import qualified Streamly.Data.Stream.Prelude as S
36
36
37import Gauge hiding (env)
37import Gauge hiding (env)
38import Streamly.Benchmark.Common.Handle
38import Streamly.Benchmark.Common.Handle
benchmark/Streamly/Benchmark/Unicode/Char.hs+1−1
@@ -24,7 +24,7 @@ import Streamly.Internal.Unicode.Char
24import Streamly.Benchmark.Common (o_1_space_prefix)
24import Streamly.Benchmark.Common (o_1_space_prefix)
25
25
26import qualified Streamly.Internal.Data.Array as Array
26import qualified Streamly.Internal.Data.Array as Array
27−import qualified Streamly.Internal.Data.Stream.IsStream as IsStream
27+import qualified Streamly.Internal.Data.Stream.StreamD as IsStream
28import qualified System.Directory as Dir
28import qualified System.Directory as Dir
29
29
30--------------------------------------------------------------------------------
30--------------------------------------------------------------------------------
benchmark/Streamly/Benchmark/Unicode/Stream.hs+12−4
@@ -20,12 +20,14 @@
20{-# OPTIONS_GHC -fplugin Test.Inspection.Plugin #-}
20{-# OPTIONS_GHC -fplugin Test.Inspection.Plugin #-}
21#endif
21#endif
22
22
23+import Streamly.Data.Stream (Stream)
24+import Streamly.Data.Fold (Fold)
23import Prelude hiding (last, length)
25import Prelude hiding (last, length)
24import System.IO (Handle)
26import System.IO (Handle)
25
27
26import qualified Streamly.Data.Array as Array
28import qualified Streamly.Data.Array as Array
27import qualified Streamly.Data.Fold as Fold
29import qualified Streamly.Data.Fold as Fold
28−import qualified Streamly.Internal.Data.Stream.IsStream as Stream
30+import qualified Streamly.Internal.Data.Stream.StreamD as Stream
29import qualified Streamly.Internal.Data.Unfold as Unfold
31import qualified Streamly.Internal.Data.Unfold as Unfold
30import qualified Streamly.Internal.FileSystem.Handle as Handle
32import qualified Streamly.Internal.FileSystem.Handle as Handle
31import qualified Streamly.Internal.Unicode.Array as UnicodeArr
33import qualified Streamly.Internal.Unicode.Array as UnicodeArr
@@ -75,13 +77,19 @@ o_1_space_decode_encode_chunked env =
75-- copy with group/ungroup transformations
77-- copy with group/ungroup transformations
76-------------------------------------------------------------------------------
78-------------------------------------------------------------------------------
77
79
80+{-# INLINE splitOnSuffix #-}
81+splitOnSuffix
82+ :: (Monad m)
83+ => (a -> Bool) -> Fold m a b -> Stream m a -> Stream m b
84+splitOnSuffix predicate f = Stream.foldMany (Fold.takeEndBy_ predicate f)
85+
78{-# NOINLINE linesUnlinesCopy #-}
86{-# NOINLINE linesUnlinesCopy #-}
79linesUnlinesCopy :: Handle -> Handle -> IO ()
87linesUnlinesCopy :: Handle -> Handle -> IO ()
80linesUnlinesCopy inh outh =
88linesUnlinesCopy inh outh =
81 Stream.fold (Handle.write outh)
89 Stream.fold (Handle.write outh)
82 $ Unicode.encodeLatin1'
90 $ Unicode.encodeLatin1'
83 $ Unicode.unlines Unfold.fromList
91 $ Unicode.unlines Unfold.fromList
84− $ Stream.splitOnSuffix (== '\n') Fold.toList
92+ $ splitOnSuffix (== '\n') Fold.toList
85 $ Unicode.decodeLatin1
93 $ Unicode.decodeLatin1
86 $ Stream.unfold Handle.reader inh
94 $ Stream.unfold Handle.reader inh
87
95
@@ -90,7 +98,7 @@ linesUnlinesArrayWord8Copy :: Handle -> Handle -> IO ()
90linesUnlinesArrayWord8Copy inh outh =
98linesUnlinesArrayWord8Copy inh outh =
91 Stream.fold (Handle.write outh)
99 Stream.fold (Handle.write outh)
92 $ Stream.interposeSuffix 10 Array.reader
100 $ Stream.interposeSuffix 10 Array.reader
93− $ Stream.splitOnSuffix (== 10) Array.write
101+ $ splitOnSuffix (== 10) Array.write
94 $ Stream.unfold Handle.reader inh
102 $ Stream.unfold Handle.reader inh
95
103
96-- XXX splitSuffixOn requires -funfolding-use-threshold=150 for better fusion
104-- XXX splitSuffixOn requires -funfolding-use-threshold=150 for better fusion
@@ -280,7 +288,7 @@ _copyStreamUtf8Parser :: Handle -> Handle -> IO ()
280_copyStreamUtf8Parser inh outh =
288_copyStreamUtf8Parser inh outh =
281 Stream.fold (Handle.write outh)
289 Stream.fold (Handle.write outh)
282 $ Unicode.encodeUtf8
290 $ Unicode.encodeUtf8
283− $ Stream.rights $ Stream.parseMany
291+ $ Stream.catRights $ Stream.parseMany
284 (Unicode.parseCharUtf8With Unicode.TransliterateCodingFailure)
292 (Unicode.parseCharUtf8With Unicode.TransliterateCodingFailure)
285 $ Stream.unfold Handle.reader inh
293 $ Stream.unfold Handle.reader inh
286
294
benchmark/bench-runner/Main.hs+45−39
@@ -14,20 +14,19 @@ rtsOpts exeName benchName0 = unwords [general, exeSpecific, benchSpecific]
14
14
15 -- Drop All.
15 -- Drop All.
16 benchName = drop 4 benchName0
16 benchName = drop 4 benchName0
17+
17 general
18 general
18 | "o-1-sp" `isInfixOf` benchName = "-K36K -M16M"
19 | "o-1-sp" `isInfixOf` benchName = "-K36K -M16M"
19 | "o-n-h" `isInfixOf` benchName = "-K36K -M32M"
20 | "o-n-h" `isInfixOf` benchName = "-K36K -M32M"
20 | "o-n-st" `isInfixOf` benchName = "-K1M -M16M"
21 | "o-n-st" `isInfixOf` benchName = "-K1M -M16M"
21 | "o-n-sp" `isInfixOf` benchName = "-K1M -M32M"
22 | "o-n-sp" `isInfixOf` benchName = "-K1M -M32M"
22 | otherwise = ""
23 | otherwise = ""
24+
23 exeSpecific
25 exeSpecific
24 | "Prelude.Concurrent" `isSuffixOf` exeName = "-K512K -M384M"
26 | "Prelude.Concurrent" `isSuffixOf` exeName = "-K512K -M384M"
25 | otherwise = ""
27 | otherwise = ""
28+
26 benchSpecific
29 benchSpecific
27− | "Data.Stream.StreamD/o-n-space.elimination.toList" == benchName =
28− "-K2M"
29− | "Data.Stream.StreamK/o-n-space.elimination.toList" == benchName =
30− "-K2M"
31 | "Prelude.Parallel/o-n-heap.mapping.mapM" == benchName = "-M256M"
30 | "Prelude.Parallel/o-n-heap.mapping.mapM" == benchName = "-M256M"
32 | "Prelude.Parallel/o-n-heap.monad-outer-product."
31 | "Prelude.Parallel/o-n-heap.monad-outer-product."
33 `isPrefixOf` benchName = "-M256M"
32 `isPrefixOf` benchName = "-M256M"
@@ -35,25 +34,6 @@ rtsOpts exeName benchName0 = unwords [general, exeSpecific, benchSpecific]
35 `isPrefixOf` benchName = "-K2M -M256M"
34 `isPrefixOf` benchName = "-K2M -M256M"
36 | "Prelude.Rate/o-1-space." `isPrefixOf` benchName = "-K128K"
35 | "Prelude.Rate/o-1-space." `isPrefixOf` benchName = "-K128K"
37 | "Prelude.Rate/o-1-space.asyncly." `isPrefixOf` benchName = "-K128K"
36 | "Prelude.Rate/o-1-space.asyncly." `isPrefixOf` benchName = "-K128K"
38− | "Data.Stream/o-1-space.mixed.sum-product-fold" == benchName =
39− "-K64M"
40− | "Data.Stream/o-n-heap.grouping.classifySessionsOf"
41− `isPrefixOf` benchName = "-K1M -M32M"
42− | "Data.Stream/o-n-heap.Functor." `isPrefixOf` benchName =
43− "-K4M -M32M"
44− | "Data.Stream/o-n-heap.transformer." `isPrefixOf` benchName =
45− "-K8M -M64M"
46− | "Data.Stream/o-n-space.Functor." `isPrefixOf` benchName =
47− "-K4M -M64M"
48− | "Data.Stream/o-n-space.Applicative." `isPrefixOf` benchName =
49− "-K8M -M128M"
50− | "Data.Stream/o-n-space.Monad." `isPrefixOf` benchName =
51− "-K8M -M64M"
52− | "Data.Stream/o-n-space.grouping." `isPrefixOf` benchName = ""
53− | "Data.Stream/o-n-space." `isPrefixOf` benchName = "-K4M"
54− | "Data.Stream.ConcurrentInterleaved/o-1-space.monad-outer-product.toNullAp" `isPrefixOf` benchName = "-M32M"
55− | "Data.Stream.ConcurrentEager/o-1-space.monad-outer-product.toNullAp" `isPrefixOf` benchName = "-M2048M -K4M"
56− | "Data.Stream.ConcurrentEager/o-1-space." `isPrefixOf` benchName = "-M512M -K4M"
57 | "Prelude.WSerial/o-n-space." `isPrefixOf` benchName = "-K4M"
37 | "Prelude.WSerial/o-n-space." `isPrefixOf` benchName = "-K4M"
58 | "Prelude.Async/o-n-space.monad-outer-product." `isPrefixOf` benchName =
38 | "Prelude.Async/o-n-space.monad-outer-product." `isPrefixOf` benchName =
59 "-K4M"
39 "-K4M"
@@ -66,27 +46,53 @@ rtsOpts exeName benchName0 = unwords [general, exeSpecific, benchSpecific]
66 "-M64M"
46 "-M64M"
67 | "Prelude.WAsync/o-n-space.monad-outer-product." `isPrefixOf` benchName =
47 | "Prelude.WAsync/o-n-space.monad-outer-product." `isPrefixOf` benchName =
68 "-K4M"
48 "-K4M"
49+
50+ -----------------------------------------------------------------------
51+
69− | "Data.Parser.ParserD/o-1-space.some" == benchName = "-K8M"
52+ | "Data.Stream.StreamD/o-n-space.elimination.toList" == benchName =
53+ "-K2M"
70− | "Data.Parser/o-1-space.some" == benchName = "-K8M"
54+ | "Data.Stream.StreamK/o-n-space.elimination.toList" == benchName =
71− | "Data.Parser.ParserD/o-1-space.manyTill" == benchName = "-K4M"
55+ "-K2M"
56+
57+ -----------------------------------------------------------------------
58+
59+ | "Data.Stream/o-1-space.grouping.classifySessionsOf"
60+ `isPrefixOf` benchName = "-K512K"
61+ | "Data.Stream/o-n-space.foldr.foldrM/"
72− | "Data.Parser/o-1-space.manyTill" == benchName = "-K4M"
62+ `isPrefixOf` benchName = "-K4M"
73− | "Data.Parser/o-n-heap.manyAlt" == benchName = "-K4M -M128M"
63+ | "Data.Stream/o-n-space.iterated."
74− | "Data.Parser/o-n-heap.someAlt" == benchName = "-K4M -M128M"
64+ `isPrefixOf` benchName = "-K4M"
75− | "Data.Parser/o-n-heap.choice" == benchName = "-K16M -M32M"
65+
76− | "Data.Parser.ParserK/o-n-heap.manyAlt" == benchName = "-K4M -M128M"
66+ | "Data.Stream.StreamDK/o-1-space.grouping.classifySessionsOf"
77− | "Data.Parser.ParserK/o-n-heap.someAlt" == benchName = "-K4M -M128M"
67+ `isPrefixOf` benchName = "-K512K"
78− | "Data.Parser.ParserK/o-n-heap.sequence" == benchName = "-M64M"
68+ | "Data.Stream.StreamDK/o-n-space.foldr.foldrM/"
79− | "Data.Parser.ParserK/o-n-heap.sequenceA" == benchName = "-M64M"
69+ `isPrefixOf` benchName = "-K4M"
70+ | "Data.Stream.StreamDK/o-n-space.iterated."
71+ `isPrefixOf` benchName = "-K4M -M64M"
72+ | "Data.Stream.StreamDK/o-n-space.traversable."
73+ `isPrefixOf` benchName = "-K2M"
74+
75+ | "Data.Stream.ConcurrentInterleaved/o-1-space.monad-outer-product.toNullAp"
76+ `isPrefixOf` benchName = "-M32M"
77+
78+ | "Data.Stream.ConcurrentEager/o-1-space.monad-outer-product.toNullAp"
79+ `isPrefixOf` benchName = "-M512M"
80+ | "Data.Stream.ConcurrentEager/o-1-space."
81+ `isPrefixOf` benchName = "-M128M"
82+
83+ ----------------------------------------------------------------------
84+
80 | "Data.Array" `isPrefixOf` benchName
85 | "Data.Array" `isPrefixOf` benchName
81 && "/o-1-space.generation.read" `isSuffixOf` benchName = "-M32M"
86 && "/o-1-space.generation.read" `isSuffixOf` benchName = "-M32M"
82 | "Data.Array" `isPrefixOf` benchName
87 | "Data.Array" `isPrefixOf` benchName
83 && "/o-1-space.generation.show" `isSuffixOf` benchName = "-M32M"
88 && "/o-1-space.generation.show" `isSuffixOf` benchName = "-M32M"
84− | "Data.Array.Generic/o-1-space.transformationX4.map" == benchName = "-M32M"
89+ | "Data.Array.Generic/o-1-space.transformationX4.map"
85− | "Data.Array/o-1-space.elimination.foldable.foldl"
86− `isPrefixOf` benchName = "-K8M"
90+ `isPrefixOf` benchName = "-M32M"
87− | "Data.Array/o-1-space.elimination.foldable.sum" == benchName =
91+
88− "-K8M"
92+ -----------------------------------------------------------------------
93+
89 | "Unicode.Char/o-1-space." `isPrefixOf` benchName = "-M32M"
94 | "Unicode.Char/o-1-space." `isPrefixOf` benchName = "-M32M"
95+
90 | otherwise = ""
96 | otherwise = ""
91
97
92speedOpts :: String -> String -> Maybe Quickness
98speedOpts :: String -> String -> Maybe Quickness
benchmark/lib/Streamly/Benchmark/Common.hs+1−1
@@ -54,7 +54,7 @@ import Data.Functor.Identity (Identity, runIdentity)
54import System.Random (randomRIO)
54import System.Random (randomRIO)
55
55
56import qualified Streamly.Internal.Data.Fold as Fold
56import qualified Streamly.Internal.Data.Fold as Fold
57−import qualified Streamly.Internal.Data.Stream as S
57+import qualified Streamly.Internal.Data.Stream.StreamD as S
58
58
59import Gauge
59import Gauge
60
60
benchmark/streamly-benchmarks.cabal+186−113
@@ -73,15 +73,49 @@ flag use-prelude
73-- Common stanzas
73-- Common stanzas
74-------------------------------------------------------------------------------
74-------------------------------------------------------------------------------
75
75
76+common default-extensions
77+ default-extensions:
78+ BangPatterns
79+ CApiFFI
80+ CPP
81+ ConstraintKinds
82+ DeriveDataTypeable
83+ DeriveGeneric
84+ DeriveTraversable
85+ ExistentialQuantification
86+ FlexibleContexts
87+ FlexibleInstances
88+ GeneralizedNewtypeDeriving
89+ InstanceSigs
90+ KindSignatures
91+ LambdaCase
92+ MagicHash
93+ MultiParamTypeClasses
94+ PatternSynonyms
95+ RankNTypes
96+ RecordWildCards
97+ ScopedTypeVariables
98+ TupleSections
99+ TypeApplications
100+ TypeFamilies
101+ TypeOperators
102+ ViewPatterns
103+
104+ -- MonoLocalBinds, enabled by TypeFamilies, causes performance
105+ -- regressions. Disable it. This must come after TypeFamilies,
106+ -- otherwise TypeFamilies will enable it again.
107+ NoMonoLocalBinds
108+
109+ -- UndecidableInstances -- Does not show any perf impact
110+ -- UnboxedTuples -- interferes with (#.)
111+
76common compile-options
112common compile-options
113+ import: default-extensions
77 default-language: Haskell2010
114 default-language: Haskell2010
78
115
79 if flag(use-streamly-core)
116 if flag(use-streamly-core)
80 cpp-options: -DUSE_STREAMLY_CORE
117 cpp-options: -DUSE_STREAMLY_CORE
81
118
82− if flag(use-prelude)
83− cpp-options: -DUSE_PRELUDE
84−
85 if flag(dev)
119 if flag(dev)
86 cpp-options: -DDEVBUILD
120 cpp-options: -DDEVBUILD
87
121
@@ -191,7 +225,7 @@ library
191 hs-source-dirs: lib
225 hs-source-dirs: lib
192 exposed-modules: Streamly.Benchmark.Common
226 exposed-modules: Streamly.Benchmark.Common
193 , Streamly.Benchmark.Common.Handle
227 , Streamly.Benchmark.Common.Handle
194− if !flag(use-streamly-core)
228+ if flag(use-prelude)
195 exposed-modules: Streamly.Benchmark.Prelude
229 exposed-modules: Streamly.Benchmark.Prelude
196
230
197
231
@@ -232,12 +266,37 @@ benchmark Data.Stream
232 Stream.Transform
266 Stream.Transform
233 Stream.Reduce
267 Stream.Reduce
234 Stream.Expand
268 Stream.Expand
269+ Stream.Lift
270+ Stream.Common
271+ if !flag(use-streamly-core)
272+ other-modules:
235 Stream.Exceptions
273 Stream.Exceptions
274+ if flag(limit-build-mem)
275+ if flag(dev)
276+ ghc-options: +RTS -M3500M -RTS
277+ else
278+ ghc-options: +RTS -M2500M -RTS
279+
280+benchmark Data.Stream.StreamDK
281+ import: bench-options
282+ type: exitcode-stdio-1.0
283+ hs-source-dirs: Streamly/Benchmark/Data
284+ main-is: Stream.hs
285+ other-modules:
286+ Stream.Generate
287+ Stream.Eliminate
288+ Stream.Transform
289+ Stream.Reduce
290+ Stream.Expand
236 Stream.Lift
291 Stream.Lift
237 Stream.Common
292 Stream.Common
238− if flag(use-prelude)
293+ if !flag(use-streamly-core)
239 other-modules:
294 other-modules:
240− Stream.Split
295+ Stream.Exceptions
296+ -- Cannot use USE_STREAMK and USE_PRELUDE together
297+ if flag(use-prelude)
298+ buildable: False
299+ cpp-options: -DUSE_STREAMK
241 if flag(limit-build-mem)
300 if flag(limit-build-mem)
242 if flag(dev)
301 if flag(dev)
243 ghc-options: +RTS -M3500M -RTS
302 ghc-options: +RTS -M3500M -RTS
@@ -296,92 +355,6 @@ benchmark Data.Stream.ConcurrentOrdered
296 else
355 else
297 buildable: True
356 buildable: True
298
357
299−benchmark Prelude.WSerial
300− import: bench-options
301− type: exitcode-stdio-1.0
302− hs-source-dirs: Streamly/Benchmark/Prelude
303− main-is: WSerial.hs
304− if flag(use-streamly-core) || impl(ghcjs)
305− buildable: False
306− else
307− buildable: True
308− if flag(limit-build-mem)
309− ghc-options: +RTS -M750M -RTS
310−
311−benchmark Prelude.Merge
312− import: bench-options
313− type: exitcode-stdio-1.0
314− hs-source-dirs: Streamly/Benchmark/Prelude
315− main-is: Merge.hs
316− if flag(use-streamly-core) || impl(ghcjs)
317− buildable: False
318− else
319− buildable: True
320−
321−benchmark Prelude.ZipSerial
322− import: bench-options
323− type: exitcode-stdio-1.0
324− hs-source-dirs: Streamly/Benchmark/Prelude
325− main-is: ZipSerial.hs
326− if flag(use-streamly-core) || impl(ghcjs)
327− buildable: False
328− else
329− buildable: True
330−
331−benchmark Prelude.ZipAsync
332− import: bench-options
333− type: exitcode-stdio-1.0
334− hs-source-dirs: Streamly/Benchmark/Prelude
335− main-is: ZipAsync.hs
336− if flag(use-streamly-core) || impl(ghcjs)
337− buildable: False
338− else
339− buildable: True
340− if flag(limit-build-mem)
341− ghc-options: +RTS -M1000M -RTS
342−
343−benchmark Prelude.Ahead
344− import: bench-options-threaded
345− type: exitcode-stdio-1.0
346− hs-source-dirs: Streamly/Benchmark/Prelude
347− main-is: Ahead.hs
348− if flag(use-streamly-core) || impl(ghcjs)
349− buildable: False
350− else
351− buildable: True
352−
353−benchmark Prelude.Async
354− import: bench-options-threaded
355− type: exitcode-stdio-1.0
356− hs-source-dirs: Streamly/Benchmark/Prelude
357− main-is: Async.hs
358− if flag(use-streamly-core) || impl(ghcjs)
359− buildable: False
360− else
361− buildable: True
362−
363−benchmark Prelude.WAsync
364− import: bench-options-threaded
365− type: exitcode-stdio-1.0
366− hs-source-dirs: Streamly/Benchmark/Prelude
367− main-is: WAsync.hs
368− if flag(use-streamly-core) || impl(ghcjs)
369− buildable: False
370− else
371− buildable: True
372−
373−benchmark Prelude.Parallel
374− import: bench-options-threaded
375− type: exitcode-stdio-1.0
376− hs-source-dirs: Streamly/Benchmark/Prelude
377− main-is: Parallel.hs
378− if flag(use-streamly-core) || impl(ghcjs)
379− buildable: False
380− else
381− buildable: True
382− if flag(limit-build-mem)
383− ghc-options: +RTS -M2000M -RTS
384−
385
358
386benchmark Data.Unfold
359benchmark Data.Unfold
387 import: bench-options
360 import: bench-options
@@ -483,8 +456,6 @@ benchmark Data.Stream.StreamD
483 main-is: StreamD.hs
456 main-is: StreamD.hs
484 if impl(ghcjs)
457 if impl(ghcjs)
485 buildable: False
458 buildable: False
486− else
487− buildable: True
488
459
489benchmark Data.Stream.StreamK
460benchmark Data.Stream.StreamK
490 import: bench-options
461 import: bench-options
@@ -493,20 +464,16 @@ benchmark Data.Stream.StreamK
493 main-is: StreamK.hs
464 main-is: StreamK.hs
494 if impl(ghcjs)
465 if impl(ghcjs)
495 buildable: False
466 buildable: False
496− else
497− buildable: True
498
467
499benchmark Data.Stream.ToStreamK
468benchmark Data.Stream.ToStreamK
500 import: bench-options
469 import: bench-options
501 type: exitcode-stdio-1.0
470 type: exitcode-stdio-1.0
502 hs-source-dirs: Streamly/Benchmark/Data/Stream
471 hs-source-dirs: Streamly/Benchmark/Data/Stream
503 main-is: ToStreamK.hs
472 main-is: ToStreamK.hs
504− if impl(ghcjs)
473+ if !flag(dev) || impl(ghcjs)
505 buildable: False
474 buildable: False
506− else
507− buildable: True
508
475
509−benchmark Data.Stream.StreamDK
476+benchmark Data.Stream.StreamK.Alt
510 import: bench-options
477 import: bench-options
511 type: exitcode-stdio-1.0
478 type: exitcode-stdio-1.0
512 hs-source-dirs: Streamly/Benchmark/Data/Stream
479 hs-source-dirs: Streamly/Benchmark/Data/Stream
@@ -518,11 +485,115 @@ executable nano-bench
518 import: bench-options
485 import: bench-options
519 hs-source-dirs: .
486 hs-source-dirs: .
520 main-is: NanoBenchmarks.hs
487 main-is: NanoBenchmarks.hs
521− if flag(dev)
488+ if !flag(dev)
522− buildable: True
523− else
524 buildable: False
489 buildable: False
525
490
491+-------------------------------------------------------------------------------
492+-- Streamly.Prelude
493+-------------------------------------------------------------------------------
494+
495+benchmark Prelude
496+ import: bench-options
497+ type: exitcode-stdio-1.0
498+ hs-source-dirs: Streamly/Benchmark/Data
499+ main-is: Stream.hs
500+ other-modules:
501+ Stream.Generate
502+ Stream.Eliminate
503+ Stream.Transform
504+ Stream.Reduce
505+ Stream.Expand
506+ Stream.Lift
507+ Stream.Common
508+ Stream.Split
509+ Stream.Exceptions
510+ cpp-options: -DUSE_PRELUDE
511+ if !flag(use-prelude)
512+ buildable: False
513+ if flag(limit-build-mem)
514+ if flag(dev)
515+ ghc-options: +RTS -M3500M -RTS
516+ else
517+ ghc-options: +RTS -M2500M -RTS
518+
519+benchmark Prelude.WSerial
520+ import: bench-options
521+ type: exitcode-stdio-1.0
522+ hs-source-dirs: Streamly/Benchmark/Prelude
523+ main-is: WSerial.hs
524+ cpp-options: -DUSE_PRELUDE
525+ if !flag(use-prelude)
526+ buildable: False
527+ if flag(limit-build-mem)
528+ ghc-options: +RTS -M750M -RTS
529+
530+benchmark Prelude.Merge
531+ import: bench-options
532+ type: exitcode-stdio-1.0
533+ hs-source-dirs: Streamly/Benchmark/Prelude
534+ main-is: Merge.hs
535+ cpp-options: -DUSE_PRELUDE
536+ if !flag(use-prelude)
537+ buildable: False
538+
539+benchmark Prelude.ZipSerial
540+ import: bench-options
541+ type: exitcode-stdio-1.0
542+ hs-source-dirs: Streamly/Benchmark/Prelude
543+ main-is: ZipSerial.hs
544+ cpp-options: -DUSE_PRELUDE
545+ if !flag(use-prelude)
546+ buildable: False
547+
548+benchmark Prelude.ZipAsync
549+ import: bench-options
550+ type: exitcode-stdio-1.0
551+ hs-source-dirs: Streamly/Benchmark/Prelude
552+ main-is: ZipAsync.hs
553+ cpp-options: -DUSE_PRELUDE
554+ if !flag(use-prelude)
555+ buildable: False
556+ if flag(limit-build-mem)
557+ ghc-options: +RTS -M1000M -RTS
558+
559+benchmark Prelude.Ahead
560+ import: bench-options-threaded
561+ type: exitcode-stdio-1.0
562+ hs-source-dirs: Streamly/Benchmark/Prelude
563+ main-is: Ahead.hs
564+ cpp-options: -DUSE_PRELUDE
565+ if !flag(use-prelude)
566+ buildable: False
567+
568+benchmark Prelude.Async
569+ import: bench-options-threaded
570+ type: exitcode-stdio-1.0
571+ hs-source-dirs: Streamly/Benchmark/Prelude
572+ main-is: Async.hs
573+ cpp-options: -DUSE_PRELUDE
574+ if !flag(use-prelude)
575+ buildable: False
576+
577+benchmark Prelude.WAsync
578+ import: bench-options-threaded
579+ type: exitcode-stdio-1.0
580+ hs-source-dirs: Streamly/Benchmark/Prelude
581+ main-is: WAsync.hs
582+ cpp-options: -DUSE_PRELUDE
583+ if !flag(use-prelude)
584+ buildable: False
585+
586+benchmark Prelude.Parallel
587+ import: bench-options-threaded
588+ type: exitcode-stdio-1.0
589+ hs-source-dirs: Streamly/Benchmark/Prelude
590+ main-is: Parallel.hs
591+ cpp-options: -DUSE_PRELUDE
592+ if !flag(use-prelude)
593+ buildable: False
594+ if flag(limit-build-mem)
595+ ghc-options: +RTS -M2000M -RTS
596+
526-------------------------------------------------------------------------------
597-------------------------------------------------------------------------------
527-- Concurrent Streams
598-- Concurrent Streams
528-------------------------------------------------------------------------------
599-------------------------------------------------------------------------------
@@ -532,30 +603,27 @@ benchmark Prelude.Concurrent
532 type: exitcode-stdio-1.0
603 type: exitcode-stdio-1.0
533 hs-source-dirs: Streamly/Benchmark/Prelude
604 hs-source-dirs: Streamly/Benchmark/Prelude
534 main-is: Concurrent.hs
605 main-is: Concurrent.hs
606+ cpp-options: -DUSE_PRELUDE
535− if flag(use-streamly-core)
607+ if !flag(use-prelude)
536 buildable: False
608 buildable: False
537− else
538− buildable: True
539
609
540benchmark Prelude.Adaptive
610benchmark Prelude.Adaptive
541 import: bench-options-threaded
611 import: bench-options-threaded
542 type: exitcode-stdio-1.0
612 type: exitcode-stdio-1.0
543 hs-source-dirs: Streamly/Benchmark/Prelude
613 hs-source-dirs: Streamly/Benchmark/Prelude
544 main-is: Adaptive.hs
614 main-is: Adaptive.hs
545− if flag(use-streamly-core) || impl(ghcjs)
615+ cpp-options: -DUSE_PRELUDE
616+ if !flag(use-prelude)
546 buildable: False
617 buildable: False
547− else
548− buildable: True
549
618
550benchmark Prelude.Rate
619benchmark Prelude.Rate
551 import: bench-options-threaded
620 import: bench-options-threaded
552 type: exitcode-stdio-1.0
621 type: exitcode-stdio-1.0
553 hs-source-dirs: Streamly/Benchmark/Prelude
622 hs-source-dirs: Streamly/Benchmark/Prelude
554 main-is: Rate.hs
623 main-is: Rate.hs
555− if flag(use-streamly-core) || impl(ghcjs)
624+ cpp-options: -DUSE_PRELUDE
625+ if !flag(use-prelude)
556 buildable: False
626 buildable: False
557− else
558− buildable: True
559
627
560-------------------------------------------------------------------------------
628-------------------------------------------------------------------------------
561-- Array Benchmarks
629-- Array Benchmarks
@@ -564,8 +632,10 @@ benchmark Prelude.Rate
564benchmark Data.Array.Generic
632benchmark Data.Array.Generic
565 import: bench-options
633 import: bench-options
566 type: exitcode-stdio-1.0
634 type: exitcode-stdio-1.0
567− hs-source-dirs: .
635+ hs-source-dirs: ., Streamly/Benchmark/Data
568 main-is: Streamly/Benchmark/Data/Array/Generic.hs
636 main-is: Streamly/Benchmark/Data/Array/Generic.hs
637+ other-modules:
638+ Stream.Common
569 if flag(use-streamly-core)
639 if flag(use-streamly-core)
570 buildable: False
640 buildable: False
571 else
641 else
@@ -585,7 +655,10 @@ benchmark Data.SmallArray
585benchmark Data.Array
655benchmark Data.Array
586 import: bench-options
656 import: bench-options
587 type: exitcode-stdio-1.0
657 type: exitcode-stdio-1.0
658+ hs-source-dirs: ., Streamly/Benchmark/Data
588 main-is: Streamly/Benchmark/Data/Array.hs
659 main-is: Streamly/Benchmark/Data/Array.hs
660+ other-modules:
661+ Stream.Common
589 if flag(use-streamly-core)
662 if flag(use-streamly-core)
590 buildable: False
663 buildable: False
591 else
664 else
cabal.project.doctest+1−1
@@ -1,6 +1,6 @@
1packages: streamly.cabal
1packages: streamly.cabal
2 , core/streamly-core.cabal
2 , core/streamly-core.cabal
3− , docs/streamly-docs.cabal
3+ -- , docs/streamly-docs.cabal
4 -- for QuickCheck in property doctests
4 -- for QuickCheck in property doctests
5 , test/streamly-tests.cabal
5 , test/streamly-tests.cabal
6
6
core/src/Streamly/Data/Stream.hs+40−45
@@ -25,24 +25,6 @@
25-- allows high performance combinatorial programming even when using byte level
25-- allows high performance combinatorial programming even when using byte level
26-- streams. Streamly API is similar to Haskell lists.
26-- streams. Streamly API is similar to Haskell lists.
27--
27--
28−-- Streams can be constructed like lists, except that they use 'nil' instead of
29−-- '[]' and 'cons' instead of ':'.
30−--
31−-- `cons` adds a pure value at the head of the stream:
32−--
33−-- >>> import Streamly.Data.Stream (Stream, cons, consM, nil)
34−-- >>> stream = 1 `cons` 2 `cons` nil :: Stream IO Int
35−-- >>> Stream.fold Fold.toList stream -- IO [Int]
36−-- [1,2]
37−--
38−-- `consM` adds an effect at the head of the stream:
39−--
40−-- >>> stream = effect 1 `consM` effect 2 `consM` nil
41−-- >>> Stream.fold Fold.toList stream
42−-- 1
43−-- 2
44−-- [1,2]
45−--
46-- == Console Echo Example
28-- == Console Echo Example
47--
29--
48-- In the following example, 'repeatM' generates an infinite stream of 'String'
30-- In the following example, 'repeatM' generates an infinite stream of 'String'
@@ -69,25 +51,40 @@
69-- "Data.List" like functions and many more powerful combinators to perform
51-- "Data.List" like functions and many more powerful combinators to perform
70-- common programming tasks.
52-- common programming tasks.
71--
53--
54+-- == Performance Notes
55+--
56+-- The 'Stream' type represents a stream by composing state as data which
57+-- enables stream fusion. Stream fusion generates a tight loop without any
58+-- constructor allocations between the stages, providing C like performance for
59+-- the loop. Stream fusion works when multiple functions are combined in a
60+-- pipeline statically. Therefore, the operations in this module must be
61+-- inlined and must not be used recursively to allow for stream fusion.
62+--
63+-- Using the 'Stream' type binary stream construction operations like 'cons',
64+-- 'append' etc. degrade quadratically (O(n^2)) when combined many times. If
65+-- you need to combine these operations, say more than 50 times in a single
66+-- loop, then you should use the continuation style stream type 'StreamK'
67+-- instead. Also, if you need to use these operations in a recursive loop you
68+-- should use 'StreamK' instead.
69+--
70+-- The 'StreamK' type represents a stream by composing function calls,
71+-- therefore, a function call overhead is incurred at each composition. It is
72+-- quite fast in general but may be a few times slower than a fused stream.
73+-- However, it allows for scalable dynamic composition and control flow
74+-- manipulation. Using the 'StreamK' type binary operations like 'cons' and
75+-- 'append' provide linear (O(n)) performance.
76+--
77+-- 'Stream' and 'StreamK' types can be interconverted.
78+--
72-- == Useful Idioms
79-- == Useful Idioms
73--
80--
74-- >>> fromListM = Stream.sequence . Stream.fromList
81-- >>> fromListM = Stream.sequence . Stream.fromList
75−-- >>> fromFoldableM = Stream.sequence . Stream.fromFoldable
76-- >>> fromIndices f = fmap f $ Stream.enumerateFrom 0
82-- >>> fromIndices f = fmap f $ Stream.enumerateFrom 0
77--
83--
78-- Also see "Streamly.Internal.Data.Stream" module for many more @Pre-release@
84-- Also see "Streamly.Internal.Data.Stream" module for many more @Pre-release@
79-- combinators. See the <https://github.com/composewell/streamly-examples>
85-- combinators. See the <https://github.com/composewell/streamly-examples>
80-- repository for many more real world examples of stream programming.
86-- repository for many more real world examples of stream programming.
81--
87--
82−-- == Performance Notes
83−--
84−-- Operations annotated as /CPS/ force the use of continuation passing style
85−-- streams. Therefore, such operations are not subjected to stream fusion.
86−-- However, for some of these operations you can find fusible alternatives in
87−-- the internal modules, which are perfectly fine to use but you need to
88−-- understand the implications especially the O(n^2) nature of those
89−-- operations..
90−--
91module Streamly.Data.Stream
88module Streamly.Data.Stream
92 (
89 (
93 Stream
90 Stream
@@ -107,8 +104,6 @@ module Streamly.Data.Stream
107 , nilM
104 , nilM
108 , cons
105 , cons
109 , consM
106 , consM
110− -- , cons2 -- fused version
111− -- , consM2 -- fused version
112
107
113 -- ** Unfolding
108 -- ** Unfolding
114 -- | 'unfoldrM' is the most general way of generating a stream efficiently.
109 -- | 'unfoldrM' is the most general way of generating a stream efficiently.
@@ -152,7 +147,6 @@ module Streamly.Data.Stream
152 -- | Convert an input structure, container or source into a stream. All of
147 -- | Convert an input structure, container or source into a stream. All of
153 -- these can be expressed in terms of primitives.
148 -- these can be expressed in terms of primitives.
154 , fromList
149 , fromList
155− , fromFoldable
156
150
157 -- ** From Unfolds
151 -- ** From Unfolds
158 -- | Most of the above stream generation operations can also be expressed
152 -- | Most of the above stream generation operations can also be expressed
@@ -366,28 +360,31 @@ module Streamly.Data.Stream
366 , append
360 , append
367
361
368 -- ** Interleaving
362 -- ** Interleaving
363+ -- | When interleaving more than two streams you may want to interleave
364+ -- them pairwise creating a balanced binary merge tree.
369 , interleave
365 , interleave
370− -- , interleave2
371
366
372 -- ** Merging
367 -- ** Merging
368+ -- | When merging more than two streams you may want to merging them
369+ -- pairwise creating a balanced binary merge tree.
370+ --
373− -- | Merging of @n@ streams can be performed by combining the streams pair
371+ -- Merging of @n@ streams can be performed by combining the streams pair
374 -- wise using 'mergeMapWith' to give O(n * log n) time complexity. If used
372 -- wise using 'mergeMapWith' to give O(n * log n) time complexity. If used
375 -- with 'concatMapWith' it will have O(n^2) performance.
373 -- with 'concatMapWith' it will have O(n^2) performance.
376
374
377 , mergeBy
375 , mergeBy
378 , mergeByM
376 , mergeByM
379− -- , mergeBy2
380− -- , mergeByM2
381
377
382 -- ** Zipping
378 -- ** Zipping
379+ -- | When zipping more than two streams you may want to zip them
380+ -- pairwise creating a balanced binary tree.
381+ --
383− -- | Zipping of @n@ streams can be performed by combining the streams pair
382+ -- Zipping of @n@ streams can be performed by combining the streams pair
384 -- wise using 'mergeMapWith' with O(n * log n) time complexity. If used
383 -- wise using 'mergeMapWith' with O(n * log n) time complexity. If used
385 -- with 'concatMapWith' it will have O(n^2) performance.
384 -- with 'concatMapWith' it will have O(n^2) performance.
386 , zipWith
385 , zipWith
387 , zipWithM
386 , zipWithM
388− -- , zipWith2
389− -- , zipWithM2
390− , ZipStream (..)
387+ -- , ZipStream (..)
391
388
392 -- ** Cross Product
389 -- ** Cross Product
393 -- XXX The argument order in this operation is such that it seems we are
390 -- XXX The argument order in this operation is such that it seems we are
@@ -399,7 +396,7 @@ module Streamly.Data.Stream
399 , crossWith
396 , crossWith
400 -- , cross
397 -- , cross
401 -- , joinInner
398 -- , joinInner
402− , CrossStream (..)
399+ -- , CrossStream (..)
403
400
404 -- * Unfold Each
401 -- * Unfold Each
405 , unfoldMany
402 , unfoldMany
@@ -428,21 +425,18 @@ module Streamly.Data.Stream
428 --
425 --
429
426
430 , concatEffect
427 , concatEffect
431− , concatMapWith
432 , concatMap
428 , concatMap
433 , concatMapM
429 , concatMapM
434− , mergeMapWith
435
430
436 -- * Repeated Fold
431 -- * Repeated Fold
437 , foldMany -- XXX Rename to foldRepeat
432 , foldMany -- XXX Rename to foldRepeat
438 , parseMany
433 , parseMany
439− , arraysOf
434+ , Array.arraysOf
440
435
441 -- * Buffered Operations
436 -- * Buffered Operations
442 -- | Operations that require buffering of the stream.
437 -- | Operations that require buffering of the stream.
443 -- Reverse is essentially a left fold followed by an unfold.
438 -- Reverse is essentially a left fold followed by an unfold.
444 , reverse
439 , reverse
445− , sortBy
446
440
447 -- * Multi-Stream folds
441 -- * Multi-Stream folds
448 -- | Operations that consume multiple streams at the same time.
442 -- | Operations that consume multiple streams at the same time.
@@ -496,7 +490,8 @@ module Streamly.Data.Stream
496 )
490 )
497where
491where
498
492
493+import qualified Streamly.Internal.Data.Array.Type as Array
499−import Streamly.Internal.Data.Stream
494+import Streamly.Internal.Data.Stream.StreamD
500import Prelude
495import Prelude
501 hiding (filter, drop, dropWhile, take, takeWhile, zipWith, foldr,
496 hiding (filter, drop, dropWhile, take, takeWhile, zipWith, foldr,
502 foldl, map, mapM, mapM_, sequence, all, any, sum, product, elem,
497 foldl, map, mapM, mapM_, sequence, all, any, sum, product, elem,
core/src/Streamly/Data/Stream/StreamDK.hsnew file+505
@@ -0,0 +1,505 @@
1+-- |
2+-- Module : Streamly.Data.Stream.StreamDK
3+-- Copyright : (c) 2017 Composewell Technologies
4+--
5+-- License : BSD3
6+-- Maintainer : streamly@composewell.com
7+-- Stability : released
8+-- Portability : GHC
9+--
10+-- To run examples in this module:
11+--
12+-- >>> import qualified Streamly.Data.Fold as Fold
13+-- >>> import qualified Streamly.Data.Stream.StreamDK as Stream
14+--
15+-- We will add some more imports in the examples as needed.
16+--
17+-- For effectful streams we will use the following IO action:
18+--
19+-- >>> effect n = print n >> return n
20+--
21+-- = Overview
22+--
23+-- Streamly is a framework for modular data flow based programming and
24+-- declarative concurrency. Powerful stream fusion framework in streamly
25+-- allows high performance combinatorial programming even when using byte level
26+-- streams. Streamly API is similar to Haskell lists.
27+--
28+-- Streams can be constructed like lists, except that they use 'nil' instead of
29+-- '[]' and 'cons' instead of ':'.
30+--
31+-- `cons` adds a pure value at the head of the stream:
32+--
33+-- >>> import Streamly.Data.Stream.StreamDK (Stream, cons, consM, nil)
34+-- >>> stream = 1 `cons` 2 `cons` nil :: Stream IO Int
35+-- >>> Stream.fold Fold.toList stream -- IO [Int]
36+-- [1,2]
37+--
38+-- `consM` adds an effect at the head of the stream:
39+--
40+-- >>> stream = effect 1 `consM` effect 2 `consM` nil
41+-- >>> Stream.fold Fold.toList stream
42+-- 1
43+-- 2
44+-- [1,2]
45+--
46+-- == Console Echo Example
47+--
48+-- In the following example, 'repeatM' generates an infinite stream of 'String'
49+-- by repeatedly performing the 'getLine' IO action. 'mapM' then applies
50+-- 'putStrLn' on each element in the stream converting it to stream of '()'.
51+-- Finally, 'drain' folds the stream to IO discarding the () values, thus
52+-- producing only effects.
53+--
54+-- >>> import Data.Function ((&))
55+--
56+-- >>> :{
57+-- echo =
58+-- Stream.repeatM getLine -- Stream IO String
59+-- & Stream.mapM putStrLn -- Stream IO ()
60+-- & Stream.fold Fold.drain -- IO ()
61+-- :}
62+--
63+-- This is a console echo program. It is an example of a declarative loop
64+-- written using streaming combinators. Compare it with an imperative @while@
65+-- loop.
66+--
67+-- Hopefully, this gives you an idea how we can program declaratively by
68+-- representing loops using streams. In this module, you can find all
69+-- "Data.List" like functions and many more powerful combinators to perform
70+-- common programming tasks.
71+--
72+-- == Useful Idioms
73+--
74+-- >>> fromListM = Stream.sequence . Stream.fromList
75+-- >>> fromFoldableM = Stream.sequence . Stream.fromFoldable
76+-- >>> fromIndices f = fmap f $ Stream.enumerateFrom 0
77+--
78+-- Also see "Streamly.Internal.Data.Stream.StreamDK" module for many more @Pre-release@
79+-- combinators. See the <https://github.com/composewell/streamly-examples>
80+-- repository for many more real world examples of stream programming.
81+--
82+-- == Performance Notes
83+--
84+-- Operations annotated as /CPS/ force the use of continuation passing style
85+-- streams. Therefore, such operations are not subjected to stream fusion.
86+-- However, for some of these operations you can find fusible alternatives in
87+-- the internal modules, which are perfectly fine to use but you need to
88+-- understand the implications especially the O(n^2) nature of those
89+-- operations..
90+--
91+module Streamly.Data.Stream.StreamDK
92+ (
93+ Stream
94+ -- * Construction
95+ -- | Functions ending in the general shape @b -> Stream m a@.
96+ --
97+ -- See also: "Streamly.Internal.Data.Stream.Generate" for
98+ -- @Pre-release@ functions.
99+
100+ -- ** Primitives
101+ -- | Primitives to construct a stream from pure values or monadic actions.
102+ -- All other stream construction and generation combinators described later
103+ -- can be expressed in terms of these primitives. However, the special
104+ -- versions provided in this module can be much more efficient in most
105+ -- cases. Users can create custom combinators using these primitives.
106+ , nil
107+ , nilM
108+ , cons
109+ , consM
110+ -- , cons2 -- fused version
111+ -- , consM2 -- fused version
112+
113+ -- ** Unfolding
114+ -- | 'unfoldrM' is the most general way of generating a stream efficiently.
115+ -- All other generation operations can be expressed using it.
116+ , unfoldr
117+ , unfoldrM
118+
119+ -- ** From Values
120+ -- | Generate a monadic stream from a seed value or values.
121+ , fromPure
122+ , fromEffect
123+ , repeat
124+ , repeatM
125+ , replicate
126+ , replicateM
127+
128+ -- Note: Using enumeration functions e.g. 'Prelude.enumFromThen' turns out
129+ -- to be slightly faster than the idioms like @[from, then..]@.
130+ --
131+ -- ** Enumeration
132+ -- | We can use the 'Enum' type class to enumerate a type producing a list
133+ -- and then convert it to a stream:
134+ --
135+ -- @
136+ -- 'fromList' $ 'Prelude.enumFromThen' from then
137+ -- @
138+ --
139+ -- However, this is not particularly efficient.
140+ -- The 'Enumerable' type class provides corresponding functions that
141+ -- generate a stream instead of a list, efficiently.
142+
143+ , Enumerable (..)
144+ , enumerate
145+ , enumerateTo
146+
147+ -- ** Iteration
148+ , iterate
149+ , iterateM
150+
151+ -- ** From Containers
152+ -- | Convert an input structure, container or source into a stream. All of
153+ -- these can be expressed in terms of primitives.
154+ , fromList
155+ , fromFoldable
156+
157+ -- ** From Unfolds
158+ -- | Most of the above stream generation operations can also be expressed
159+ -- using the corresponding unfolds in the "Streamly.Data.Unfold" module.
160+ , unfold -- XXX rename to fromUnfold?
161+
162+ -- * Elimination
163+ -- | Functions ending in the general shape @Stream m a -> m b@ or @Stream m
164+ -- a -> m (b, Stream m a)@
165+ --
166+ -- See also: "Streamly.Internal.Data.Stream.Eliminate" for @Pre-release@
167+ -- functions.
168+
169+-- EXPLANATION: In imperative terms a fold can be considered as a loop over the stream
170+-- that reduces the stream to a single value.
171+-- Left and right folds both use a fold function @f@ and an identity element
172+-- @z@ (@zero@) to deconstruct a recursive data structure and reconstruct a
173+-- new data structure. The new structure may be a recursive construction (a
174+-- container) or a non-recursive single value reduction of the original
175+-- structure.
176+--
177+-- Both right and left folds are mathematical duals of each other, they are
178+-- functionally equivalent. Operationally, a left fold on a left associated
179+-- structure behaves exactly in the same way as a right fold on a right
180+-- associated structure. Similarly, a left fold on a right associated structure
181+-- behaves in the same way as a right fold on a left associated structure.
182+-- However, the behavior of a right fold on a right associated structure is
183+-- operationally different (even though functionally equivalent) than a left
184+-- fold on the same structure.
185+--
186+-- On right associated structures like Haskell @cons@ lists or Streamly
187+-- streams, a lazy right fold is naturally suitable for lazy recursive
188+-- reconstruction of a new structure, while a strict left fold is naturally
189+-- suitable for efficient reduction. In right folds control is in the hand of
190+-- the @puller@ whereas in left folds the control is in the hand of the
191+-- @pusher@.
192+--
193+-- The behavior of right and left folds are described in detail in the
194+-- individual fold's documentation. To illustrate the two folds for right
195+-- associated @cons@ lists:
196+--
197+-- > foldr :: (a -> b -> b) -> b -> [a] -> b
198+-- > foldr f z [] = z
199+-- > foldr f z (x:xs) = x `f` foldr f z xs
200+-- >
201+-- > foldl :: (b -> a -> b) -> b -> [a] -> b
202+-- > foldl f z [] = z
203+-- > foldl f z (x:xs) = foldl f (z `f` x) xs
204+--
205+-- @foldr@ is conceptually equivalent to:
206+--
207+-- > foldr f z [] = z
208+-- > foldr f z [x] = f x z
209+-- > foldr f z xs = foldr f (foldr f z (tail xs)) [head xs]
210+--
211+-- @foldl@ is conceptually equivalent to:
212+--
213+-- > foldl f z [] = z
214+-- > foldl f z [x] = f z x
215+-- > foldl f z xs = foldl f (foldl f z (init xs)) [last xs]
216+--
217+-- Left and right folds are duals of each other.
218+--
219+-- @
220+-- foldr f z xs = foldl (flip f) z (reverse xs)
221+-- foldl f z xs = foldr (flip f) z (reverse xs)
222+-- @
223+--
224+-- More generally:
225+--
226+-- @
227+-- foldr f z xs = foldl g id xs z where g k x = k . f x
228+-- foldl f z xs = foldr g id xs z where g x k = k . flip f x
229+-- @
230+--
231+
232+-- NOTE: Folds are inherently serial as each step needs to use the result of
233+-- the previous step. However, it is possible to fold parts of the stream in
234+-- parallel and then combine the results using a monoid.
235+
236+ -- ** Primitives
237+ -- Consuming a part of the stream and returning the rest. Functions
238+ -- ending in the general shape @Stream m a -> m (b, Stream m a)@
239+ , uncons
240+
241+ -- ** Folding
242+ -- XXX Need to have a general parse operation here which can be used to
243+ -- express all others.
244+ , fold -- XXX rename to run? We can have a Stream.run and Fold.run.
245+ -- XXX fold1 can be achieved using Monoids or Refolds.
246+ -- XXX We can call this just "break" and parseBreak as "munch"
247+ , foldBreak
248+
249+ -- XXX should we have a Fold returning function in stream module?
250+ -- , foldAdd
251+ -- , buildl
252+
253+ -- ** Parsing
254+ , parse
255+ , parseBreak
256+
257+ -- -- ** Lazy Right Folds
258+ -- Consuming a stream to build a right associated expression, suitable
259+ -- for lazy evaluation. Evaluation of the input happens when the output of
260+ -- the fold is evaluated, the fold output is a lazy thunk.
261+ --
262+ -- This is suitable for stream transformation operations, for example,
263+ -- operations like mapping a function over the stream.
264+ -- , foldrM
265+ -- , foldr
266+
267+ -- * Mapping
268+ -- | Stateless one-to-one transformations. Use 'fmap' for mapping a pure
269+ -- function on a stream.
270+
271+ -- EXPLANATION:
272+ -- In imperative terms a map operation can be considered as a loop over
273+ -- the stream that transforms the stream into another stream by performing
274+ -- an operation on each element of the stream.
275+ --
276+ -- 'map' is the least powerful transformation operation with strictest
277+ -- guarantees. A map, (1) is a stateless loop which means that no state is
278+ -- allowed to be carried from one iteration to another, therefore,
279+ -- operations on different elements are guaranteed to not affect each
280+ -- other, (2) is a strictly one-to-one transformation of stream elements
281+ -- which means it guarantees that no elements can be added or removed from
282+ -- the stream, it can merely transform them.
283+ , sequence
284+ , mapM
285+ -- , trace -- XXX Use "tracing" map instead?
286+ , tap
287+ , delay
288+
289+ -- * Scanning
290+ -- | Stateful one-to-one transformations.
291+ --
292+ -- See also: "Streamly.Internal.Data.Stream.Transform" for
293+ -- @Pre-release@ functions.
294+ , scan
295+ , postscan
296+ -- XXX postscan1 can be implemented using Monoids or Refolds.
297+ -- Indexing can be considered as a special type of zipping where we zip a
298+ -- stream with an index stream.
299+ , indexed
300+
301+ -- * Insertion
302+ -- | Add elements to the stream.
303+
304+ -- Inserting elements is a special case of interleaving/merging streams.
305+ , insertBy
306+ , intersperseM
307+ , intersperseM_
308+ , intersperse
309+
310+ -- * Filtering
311+ -- | Remove elements from the stream.
312+
313+ -- ** Stateless Filters
314+ -- | 'mapMaybeM' is the most general stateless filtering operation. All
315+ -- other filtering operations can be expressed using it.
316+
317+ -- EXPLANATION:
318+ -- In imperative terms a filter over a stream corresponds to a loop with a
319+ -- @continue@ clause for the cases when the predicate fails.
320+
321+ , mapMaybe
322+ , mapMaybeM
323+ , filter
324+ , filterM
325+
326+ -- Filter and concat
327+ , catMaybes
328+ , catLefts
329+ , catRights
330+ , catEithers
331+
332+ -- ** Stateful Filters
333+ -- | 'scanMaybe' is the most general stateful filtering operation. The
334+ -- filtering folds (folds returning a 'Maybe' type) in
335+ -- "Streamly.Internal.Data.Fold" can be used along with 'scanMaybe' to
336+ -- perform stateful filtering operations in general.
337+ , scanMaybe
338+ , take
339+ , takeWhile
340+ , takeWhileM
341+ , drop
342+ , dropWhile
343+ , dropWhileM
344+
345+ -- XXX These are available as scans in folds. We need to check the
346+ -- performance though. If these are common and we need convenient stream
347+ -- ops then we can expose these.
348+
349+ -- , deleteBy
350+ -- , uniq
351+ -- , uniqBy
352+
353+ -- -- ** Sampling
354+ -- , strideFromThen
355+
356+ -- -- ** Searching
357+ -- Finding the presence or location of an element, a sequence of elements
358+ -- or another stream within a stream.
359+
360+ -- -- ** Searching Elements
361+ -- , findIndices
362+ -- , elemIndices
363+
364+ -- * Combining Two Streams
365+ -- ** Appending
366+ , append
367+
368+ -- ** Interleaving
369+ , interleave
370+ -- , interleave2
371+
372+ -- ** Merging
373+ -- | Merging of @n@ streams can be performed by combining the streams pair
374+ -- wise using 'mergeMapWith' to give O(n * log n) time complexity. If used
375+ -- with 'concatMapWith' it will have O(n^2) performance.
376+
377+ , mergeBy
378+ , mergeByM
379+ -- , mergeBy2
380+ -- , mergeByM2
381+
382+ -- ** Zipping
383+ -- | Zipping of @n@ streams can be performed by combining the streams pair
384+ -- wise using 'mergeMapWith' with O(n * log n) time complexity. If used
385+ -- with 'concatMapWith' it will have O(n^2) performance.
386+ , zipWith
387+ , zipWithM
388+ -- , zipWith2
389+ -- , zipWithM2
390+ , ZipStream (..)
391+
392+ -- ** Cross Product
393+ -- XXX The argument order in this operation is such that it seems we are
394+ -- transforming the first stream using the second stream because the second
395+ -- stream is evaluated many times or buffered and better be finite, first
396+ -- stream could potentially be infinite. In the tradition of using the
397+ -- transformed stream at the end we can have a flipped version called
398+ -- "crossMap" or "nestWith".
399+ , crossWith
400+ -- , cross
401+ -- , joinInner
402+ , CrossStream (..)
403+
404+ -- * Unfold Each
405+ , unfoldMany
406+ , intercalate
407+ , intercalateSuffix
408+
409+ -- * Stream of streams
410+ -- | Stream operations like map and filter represent loop processing in
411+ -- imperative programming terms. Similarly, the imperative concept of
412+ -- nested loops are represented by streams of streams. The 'concatMap'
413+ -- operation represents nested looping.
414+ -- A 'concatMap' operation loops over the input stream and then for each
415+ -- element of the input stream generates another stream and then loops over
416+ -- that inner stream as well producing effects and generating a single
417+ -- output stream.
418+ --
419+ -- One dimension loops are just a special case of nested loops. For
420+ -- example, 'concatMap' can degenerate to a simple map operation:
421+ --
422+ -- > map f m = S.concatMap (\x -> S.fromPure (f x)) m
423+ --
424+ -- Similarly, 'concatMap' can perform filtering by mapping an element to a
425+ -- 'nil' stream:
426+ --
427+ -- > filter p m = S.concatMap (\x -> if p x then S.fromPure x else S.nil) m
428+ --
429+
430+ , concatEffect
431+ , concatMapWith
432+ , concatMap
433+ , concatMapM
434+ , mergeMapWith
435+
436+ -- * Repeated Fold
437+ , foldMany -- XXX Rename to foldRepeat
438+ , parseMany
439+ , arraysOf
440+
441+ -- * Buffered Operations
442+ -- | Operations that require buffering of the stream.
443+ -- Reverse is essentially a left fold followed by an unfold.
444+ , reverse
445+ , sortBy
446+
447+ -- * Multi-Stream folds
448+ -- | Operations that consume multiple streams at the same time.
449+ , eqBy
450+ , cmpBy
451+ , isPrefixOf
452+ , isSubsequenceOf
453+
454+ -- trimming sequences
455+ , stripPrefix
456+
457+ -- Exceptions and resource management depend on the "exceptions" package
458+ -- XXX We can have IO Stream operations not depending on "exceptions"
459+ -- in Exception.Base
460+
461+ -- * Exceptions
462+ -- | Most of these combinators inhibit stream fusion, therefore, when
463+ -- possible, they should be called in an outer loop to mitigate the cost.
464+ -- For example, instead of calling them on a stream of chars call them on a
465+ -- stream of arrays before flattening it to a stream of chars.
466+ --
467+ -- See also: "Streamly.Internal.Data.Stream.Exception" for
468+ -- @Pre-release@ functions.
469+
470+ , onException
471+ , handle
472+
473+ -- * Resource Management
474+ -- | 'bracket' is the most general resource management operation, all other
475+ -- operations can be expressed using it. These functions have IO suffix
476+ -- because the allocation and cleanup functions are IO actions. For
477+ -- generalized allocation and cleanup functions see the functions without
478+ -- the IO suffix in the "streamly" package.
479+ , before
480+ , afterIO
481+ , finallyIO
482+ , bracketIO
483+ , bracketIO3
484+
485+ -- * Transforming Inner Monad
486+
487+ , morphInner
488+ , liftInner
489+ , runReaderT
490+ , runStateT
491+
492+ -- -- * Stream Types
493+ -- $serial
494+ -- , Interleave
495+ -- , Zip
496+ )
497+where
498+
499+import Streamly.Internal.Data.Stream.StreamDK
500+import Prelude
501+ hiding (filter, drop, dropWhile, take, takeWhile, zipWith, foldr,
502+ foldl, map, mapM, mapM_, sequence, all, any, sum, product, elem,
503+ notElem, maximum, minimum, head, last, tail, length, null,
504+ reverse, iterate, init, and, or, lookup, foldr1, (!!),
505+ scanl, scanl1, repeat, replicate, concatMap, span)
core/src/Streamly/Data/Stream/StreamK.hsnew file+93
@@ -0,0 +1,93 @@
1+-- |
2+-- Module : Streamly.Data.Stream.StreamK
3+-- Copyright : (c) 2017 Composewell Technologies
4+--
5+-- License : BSD3
6+-- Maintainer : streamly@composewell.com
7+-- Stability : released
8+-- Portability : GHC
9+--
10+-- Streams using Continuation Passing Style (CPS). See notes in "Data.Stream"
11+-- module to know when to use this module.
12+
13+-- primitive/open loop operations that can be used recursively e.g. uncons,
14+-- foldBreak, parseBreak should not be converted from StreamD for use in
15+-- StreamK, instead native StreamK impl should be used.
16+--
17+-- Closed loop operations like repeat, replicate, iterate etc can be converted
18+-- from StreamD.
19+--
20+-- In the last phase any operation like (toStreamK . f . toStreamD) should be
21+-- rewritten to a K version of f.
22+-- XXX Need to add rewrite rules for all missing StreamD operations.
23+--
24+module Streamly.Data.Stream.StreamK
25+ (
26+ StreamK
27+
28+ -- * Construction
29+ -- ** Primitives
30+ , nil
31+ , nilM
32+ , cons
33+ , consM
34+
35+ -- ** From Values
36+ , fromPure
37+ , fromEffect
38+
39+ -- ** From Stream
40+ , fromStream
41+ , toStream
42+
43+ -- ** From Containers
44+ , fromFoldable
45+
46+ -- * Elimination
47+
48+ -- ** Primitives
49+ , uncons
50+
51+ -- -- ** Folding
52+ -- , foldBreak
53+
54+ -- ** Parsing
55+ , parseBreak
56+
57+ -- * Combining Two Streams
58+ -- ** Appending
59+ , append
60+
61+ -- ** Interleaving
62+ , interleave
63+
64+ -- ** Merging
65+ , mergeBy
66+ , mergeByM
67+
68+ -- ** Zipping
69+ , zipWith
70+ , zipWithM
71+
72+ -- ** Cross Product
73+ -- XXX is "bind/concatFor" better to have than crossWith?
74+ -- crossWith f xs1 xs2 = concatFor xs1 (\x -> fmap (f x) xs2)
75+ , crossWith
76+ -- , cross
77+ -- , joinInner
78+ -- , CrossStreamK (..)
79+
80+ -- * Stream of streams
81+ , concatEffect
82+ -- , concatMap
83+ , concatMapWith
84+ , mergeMapWith
85+
86+ -- * Buffered Operations
87+ , reverse
88+ , sortBy
89+ )
90+where
91+
92+import Streamly.Internal.Data.Stream.StreamK
93+import Prelude hiding (reverse, zipWith)
core/src/Streamly/Internal/Console/Stdio.hs+3−2
@@ -47,12 +47,13 @@ import System.IO (stdin, stdout, stderr)
47import Prelude hiding (read)
47import Prelude hiding (read)
48
48
49import Streamly.Internal.Data.Array.Type (Array(..))
49import Streamly.Internal.Data.Array.Type (Array(..))
50−import Streamly.Internal.Data.Stream (Stream)
50+import Streamly.Internal.Data.Stream.StreamD (Stream)
51import Streamly.Internal.Data.Unfold (Unfold)
51import Streamly.Internal.Data.Unfold (Unfold)
52import Streamly.Internal.Data.Fold (Fold)
52import Streamly.Internal.Data.Fold (Fold)
53
53
54import qualified Streamly.Internal.Data.Array as Array
54import qualified Streamly.Internal.Data.Array as Array
55−import qualified Streamly.Internal.Data.Stream as Stream (intersperseMSuffix)
55+import qualified Streamly.Internal.Data.Stream.StreamD as Stream
56+ (intersperseMSuffix)
56import qualified Streamly.Internal.Data.Unfold as Unfold
57import qualified Streamly.Internal.Data.Unfold as Unfold
57import qualified Streamly.Internal.FileSystem.Handle as Handle
58import qualified Streamly.Internal.FileSystem.Handle as Handle
58import qualified Streamly.Internal.Unicode.Stream as Unicode
59import qualified Streamly.Internal.Unicode.Stream as Unicode
core/src/Streamly/Internal/Data/Array.hs+8−10
@@ -139,7 +139,7 @@ import Streamly.Internal.Data.Array.Type
139 (Array(..), length, asPtrUnsafe)
139 (Array(..), length, asPtrUnsafe)
140import Streamly.Internal.Data.Fold.Type (Fold(..))
140import Streamly.Internal.Data.Fold.Type (Fold(..))
141import Streamly.Internal.Data.Producer.Type (Producer(..))
141import Streamly.Internal.Data.Producer.Type (Producer(..))
142−import Streamly.Internal.Data.Stream (Stream)
142+import Streamly.Internal.Data.Stream.StreamD (Stream)
143import Streamly.Internal.Data.Tuple.Strict (Tuple3Fused'(..))
143import Streamly.Internal.Data.Tuple.Strict (Tuple3Fused'(..))
144import Streamly.Internal.Data.Unfold.Type (Unfold(..))
144import Streamly.Internal.Data.Unfold.Type (Unfold(..))
145import Streamly.Internal.System.IO (unsafeInlineIO)
145import Streamly.Internal.System.IO (unsafeInlineIO)
@@ -151,9 +151,8 @@ import qualified Streamly.Internal.Data.Fold as FL
151import qualified Streamly.Internal.Data.Producer.Type as Producer
151import qualified Streamly.Internal.Data.Producer.Type as Producer
152import qualified Streamly.Internal.Data.Producer as Producer
152import qualified Streamly.Internal.Data.Producer as Producer
153import qualified Streamly.Internal.Data.Ring.Unboxed as RB
153import qualified Streamly.Internal.Data.Ring.Unboxed as RB
154−import qualified Streamly.Internal.Data.Stream.Common as P
155import qualified Streamly.Internal.Data.Stream.StreamD as D
154import qualified Streamly.Internal.Data.Stream.StreamD as D
156−import qualified Streamly.Internal.Data.Stream.Type as Stream
155+import qualified Streamly.Internal.Data.Stream.StreamD as Stream
157import qualified Streamly.Internal.Data.Unfold as Unfold
156import qualified Streamly.Internal.Data.Unfold as Unfold
158
157
159-------------------------------------------------------------------------------
158-------------------------------------------------------------------------------
@@ -169,7 +168,7 @@ import qualified Streamly.Internal.Data.Unfold as Unfold
169fromStreamN :: (MonadIO m, Unbox a) => Int -> Stream m a -> m (Array a)
168fromStreamN :: (MonadIO m, Unbox a) => Int -> Stream m a -> m (Array a)
170fromStreamN n m = do
169fromStreamN n m = do
171 when (n < 0) $ error "writeN: negative write count specified"
170 when (n < 0) $ error "writeN: negative write count specified"
172− A.fromStreamDN n $ Stream.toStreamD m
171+ A.fromStreamDN n m
173
172
174-- | Create an 'Array' from a stream. This is useful when we want to create a
173-- | Create an 'Array' from a stream. This is useful when we want to create a
175-- single array from a stream of unknown size. 'writeN' is at least twice
174-- single array from a stream of unknown size. 'writeN' is at least twice
@@ -182,7 +181,7 @@ fromStreamN n m = do
182-- /Pre-release/
181-- /Pre-release/
183{-# INLINE fromStream #-}
182{-# INLINE fromStream #-}
184fromStream :: (MonadIO m, Unbox a) => Stream m a -> m (Array a)
183fromStream :: (MonadIO m, Unbox a) => Stream m a -> m (Array a)
185−fromStream m = P.fold A.write $ Stream.toStreamK m
184+fromStream = Stream.fold A.write
186-- write m = A.fromStreamD $ D.fromStreamK m
185-- write m = A.fromStreamD $ D.fromStreamK m
187
186
188-------------------------------------------------------------------------------
187-------------------------------------------------------------------------------
@@ -373,8 +372,7 @@ getSliceUnsafe index len (Array contents start e) =
373splitOn :: (Monad m, Unbox a) =>
372splitOn :: (Monad m, Unbox a) =>
374 (a -> Bool) -> Array a -> Stream m (Array a)
373 (a -> Bool) -> Array a -> Stream m (Array a)
375splitOn predicate arr =
374splitOn predicate arr =
376− Stream.fromStreamD
377− $ fmap (\(i, len) -> getSliceUnsafe i len arr)
375+ fmap (\(i, len) -> getSliceUnsafe i len arr)
378 $ D.sliceOnSuffix predicate (A.toStreamD arr)
376 $ D.sliceOnSuffix predicate (A.toStreamD arr)
379
377
380{-# INLINE genSlicesFromLen #-}
378{-# INLINE genSlicesFromLen #-}
@@ -438,7 +436,7 @@ getIndex i arr =
438{-# INLINE getIndices #-}
436{-# INLINE getIndices #-}
439getIndices :: (Monad m, Unbox a) => Stream m Int -> Unfold m (Array a) a
437getIndices :: (Monad m, Unbox a) => Stream m Int -> Unfold m (Array a) a
440getIndices m =
438getIndices m =
441− let unf = MA.getIndicesD (return . unsafeInlineIO) $ D.fromStreamK $ Stream.toStreamK m
439+ let unf = MA.getIndicesD (return . unsafeInlineIO) m
442 in Unfold.lmap A.unsafeThaw unf
440 in Unfold.lmap A.unsafeThaw unf
443
441
444-- | Unfolds @(from, then, to, array)@ generating a finite stream whose first
442-- | Unfolds @(from, then, to, array)@ generating a finite stream whose first
@@ -488,7 +486,7 @@ runPipe f arr = P.runPipe (toArrayMinChunk (length arr)) $ f (A.read arr)
488streamTransform :: forall m a b. (MonadIO m, Unbox a, Unbox b)
486streamTransform :: forall m a b. (MonadIO m, Unbox a, Unbox b)
489 => (Stream m a -> Stream m b) -> Array a -> m (Array b)
487 => (Stream m a -> Stream m b) -> Array a -> m (Array b)
490streamTransform f arr =
488streamTransform f arr =
491− P.fold (A.writeWith (length arr)) $ Stream.toStreamK $ f (A.read arr)
489+ Stream.fold (A.writeWith (length arr)) $ f (A.read arr)
492
490
493-------------------------------------------------------------------------------
491-------------------------------------------------------------------------------
494-- Casts
492-- Casts
@@ -553,7 +551,7 @@ asCStringUnsafe arr act = do
553-- /Pre-release/
551-- /Pre-release/
554{-# INLINE fold #-}
552{-# INLINE fold #-}
555fold :: forall m a b. (Monad m, Unbox a) => Fold m a b -> Array a -> m b
553fold :: forall m a b. (Monad m, Unbox a) => Fold m a b -> Array a -> m b
556−fold f arr = P.fold f (Stream.toStreamK (A.read arr))
554+fold f arr = Stream.fold f (A.read arr)
557
555
558-- | Fold an array using a stream fold operation.
556-- | Fold an array using a stream fold operation.
559--
557--
core/src/Streamly/Internal/Data/Array/Generic.hs+7−7
@@ -55,7 +55,7 @@ import GHC.IO (unsafePerformIO)
55import Text.Read (readPrec)
55import Text.Read (readPrec)
56
56
57import Streamly.Internal.Data.Fold.Type (Fold(..))
57import Streamly.Internal.Data.Fold.Type (Fold(..))
58−import Streamly.Internal.Data.Stream.Type (Stream)
58+import Streamly.Internal.Data.Stream.StreamD.Type (Stream)
59import Streamly.Internal.Data.Tuple.Strict (Tuple'(..), Tuple3'(..))
59import Streamly.Internal.Data.Tuple.Strict (Tuple'(..), Tuple3'(..))
60import Streamly.Internal.Data.Unfold.Type (Unfold(..))
60import Streamly.Internal.Data.Unfold.Type (Unfold(..))
61import Streamly.Internal.System.IO (unsafeInlineIO)
61import Streamly.Internal.System.IO (unsafeInlineIO)
@@ -65,8 +65,8 @@ import qualified Streamly.Internal.Data.Fold.Type as FL
65import qualified Streamly.Internal.Data.Producer.Type as Producer
65import qualified Streamly.Internal.Data.Producer.Type as Producer
66import qualified Streamly.Internal.Data.Producer as Producer
66import qualified Streamly.Internal.Data.Producer as Producer
67import qualified Streamly.Internal.Data.Ring as RB
67import qualified Streamly.Internal.Data.Ring as RB
68−import qualified Streamly.Internal.Data.Stream.StreamD as D
68+import qualified Streamly.Internal.Data.Stream.StreamD.Type as D
69−import qualified Streamly.Internal.Data.Stream.Type as Stream
69+import qualified Streamly.Internal.Data.Stream.StreamD.Generate as D
70import qualified Text.ParserCombinators.ReadPrec as ReadPrec
70import qualified Text.ParserCombinators.ReadPrec as ReadPrec
71
71
72import Data.IORef
72import Data.IORef
@@ -150,11 +150,11 @@ fromStreamD = D.fold write
150fromStreamN :: MonadIO m => Int -> Stream m a -> m (Array a)
150fromStreamN :: MonadIO m => Int -> Stream m a -> m (Array a)
151fromStreamN n m = do
151fromStreamN n m = do
152 when (n < 0) $ error "fromStreamN: negative write count specified"
152 when (n < 0) $ error "fromStreamN: negative write count specified"
153− fromStreamDN n $ Stream.toStreamD m
153+ fromStreamDN n m
154
154
155{-# INLINE fromStream #-}
155{-# INLINE fromStream #-}
156fromStream :: MonadIO m => Stream m a -> m (Array a)
156fromStream :: MonadIO m => Stream m a -> m (Array a)
157−fromStream = fromStreamD . Stream.toStreamD
157+fromStream = fromStreamD
158
158
159{-# INLINABLE fromListN #-}
159{-# INLINABLE fromListN #-}
160fromListN :: Int -> [a] -> Array a
160fromListN :: Int -> [a] -> Array a
@@ -205,11 +205,11 @@ readRevStreamD arr@Array{..} =
205
205
206{-# INLINE_EARLY read #-}
206{-# INLINE_EARLY read #-}
207read :: MonadIO m => Array a -> Stream m a
207read :: MonadIO m => Array a -> Stream m a
208−read = Stream.fromStreamD . readStreamD
208+read = readStreamD
209
209
210{-# INLINE_EARLY readRev #-}
210{-# INLINE_EARLY readRev #-}
211readRev :: Monad m => Array a -> Stream m a
211readRev :: Monad m => Array a -> Stream m a
212−readRev = Stream.fromStreamD . readRevStreamD
212+readRev = readRevStreamD
213
213
214-------------------------------------------------------------------------------
214-------------------------------------------------------------------------------
215-- Elimination - using Folds
215-- Elimination - using Folds
core/src/Streamly/Internal/Data/Array/Generic/Mut/Type.hs+3−2
@@ -176,8 +176,9 @@ import Streamly.Internal.Data.Unfold.Type (Unfold(..))
176
176
177import qualified Streamly.Internal.Data.Fold.Type as FL
177import qualified Streamly.Internal.Data.Fold.Type as FL
178import qualified Streamly.Internal.Data.Producer as Producer
178import qualified Streamly.Internal.Data.Producer as Producer
179−import qualified Streamly.Internal.Data.Stream.StreamD as D
179+import qualified Streamly.Internal.Data.Stream.StreamD.Type as D
180+import qualified Streamly.Internal.Data.Stream.StreamD.Generate as D
180−import qualified Streamly.Internal.Data.Stream.StreamK as K
181+import qualified Streamly.Internal.Data.Stream.StreamK.Type as K
181
182
182import Prelude hiding (read)
183import Prelude hiding (read)
183
184
core/src/Streamly/Internal/Data/Array/Mut.hs+3−6
@@ -34,13 +34,11 @@ where
34
34
35import Control.Monad.IO.Class (MonadIO(..))
35import Control.Monad.IO.Class (MonadIO(..))
36import Streamly.Internal.Data.Unboxed (Unbox)
36import Streamly.Internal.Data.Unboxed (Unbox)
37−import Streamly.Internal.Data.Stream (Stream)
37+import Streamly.Internal.Data.Stream.StreamD (Stream)
38import Streamly.Internal.Data.Unfold.Type (Unfold(..))
38import Streamly.Internal.Data.Unfold.Type (Unfold(..))
39
39
40import qualified Streamly.Internal.Data.Stream.StreamD as D
40import qualified Streamly.Internal.Data.Stream.StreamD as D
41−import qualified Streamly.Internal.Data.Stream.Type as Stream
42import qualified Streamly.Internal.Data.Unfold as Unfold
41import qualified Streamly.Internal.Data.Unfold as Unfold
43−-- import qualified Streamly.Internal.Data.Stream.Common as P
44
42
45import Prelude hiding (foldr, length, read, splitAt)
43import Prelude hiding (foldr, length, read, splitAt)
46import Streamly.Internal.Data.Array.Mut.Type
44import Streamly.Internal.Data.Array.Mut.Type
@@ -53,8 +51,7 @@ import Streamly.Internal.Data.Array.Mut.Type
53splitOn :: (MonadIO m, Unbox a) =>
51splitOn :: (MonadIO m, Unbox a) =>
54 (a -> Bool) -> Array a -> Stream m (Array a)
52 (a -> Bool) -> Array a -> Stream m (Array a)
55splitOn predicate arr =
53splitOn predicate arr =
56− Stream.fromStreamD
57− $ fmap (\(i, len) -> getSliceUnsafe i len arr)
54+ fmap (\(i, len) -> getSliceUnsafe i len arr)
58 $ D.sliceOnSuffix predicate (toStreamD arr)
55 $ D.sliceOnSuffix predicate (toStreamD arr)
59
56
60-- | Generate a stream of array slice descriptors ((index, len)) of specified
57-- | Generate a stream of array slice descriptors ((index, len)) of specified
@@ -99,5 +96,5 @@ getSlicesFromLen from len =
99-- /Pre-release/
96-- /Pre-release/
100{-# INLINE fromStream #-}
97{-# INLINE fromStream #-}
101fromStream :: (MonadIO m, Unbox a) => Stream m a -> m (Array a)
98fromStream :: (MonadIO m, Unbox a) => Stream m a -> m (Array a)
102−fromStream = fromStreamD . Stream.toStreamD
99+fromStream = fromStreamD
103-- fromStream (Stream m) = P.fold write m
100-- fromStream (Stream m) = P.fold write m
core/src/Streamly/Internal/Data/Array/Mut/Stream.hs+6−9
@@ -35,14 +35,13 @@ import Streamly.Internal.Data.Unboxed (Unbox, sizeOf)
35import Streamly.Internal.Data.Array.Mut.Type (Array(..))
35import Streamly.Internal.Data.Array.Mut.Type (Array(..))
36import Streamly.Internal.Data.Fold.Type (Fold(..))
36import Streamly.Internal.Data.Fold.Type (Fold(..))
37import Streamly.Internal.Data.Parser (ParseError)
37import Streamly.Internal.Data.Parser (ParseError)
38−import Streamly.Internal.Data.Stream.Type (Stream)
38+import Streamly.Internal.Data.Stream.StreamD.Type (Stream)
39import Streamly.Internal.Data.Tuple.Strict (Tuple'(..))
39import Streamly.Internal.Data.Tuple.Strict (Tuple'(..))
40
40
41import qualified Streamly.Internal.Data.Array.Mut.Type as MArray
41import qualified Streamly.Internal.Data.Array.Mut.Type as MArray
42import qualified Streamly.Internal.Data.Fold.Type as FL
42import qualified Streamly.Internal.Data.Fold.Type as FL
43import qualified Streamly.Internal.Data.Stream.StreamD as D
43import qualified Streamly.Internal.Data.Stream.StreamD as D
44import qualified Streamly.Internal.Data.Parser.ParserD as ParserD
44import qualified Streamly.Internal.Data.Parser.ParserD as ParserD
45−import qualified Streamly.Internal.Data.Stream.Type as Stream
46
45
47-- | @arraysOf n stream@ groups the elements in the input stream into arrays of
46-- | @arraysOf n stream@ groups the elements in the input stream into arrays of
48-- @n@ elements each.
47-- @n@ elements each.
@@ -55,7 +54,7 @@ import qualified Streamly.Internal.Data.Stream.Type as Stream
55{-# INLINE arraysOf #-}
54{-# INLINE arraysOf #-}
56arraysOf :: (MonadIO m, Unbox a)
55arraysOf :: (MonadIO m, Unbox a)
57 => Int -> Stream m a -> Stream m (Array a)
56 => Int -> Stream m a -> Stream m (Array a)
58−arraysOf n = Stream.fromStreamD . MArray.arraysOf n . Stream.toStreamD
57+arraysOf = MArray.arraysOf
59
58
60-------------------------------------------------------------------------------
59-------------------------------------------------------------------------------
61-- Compact
60-- Compact
@@ -194,7 +193,7 @@ lpackArraysChunksOf n (Fold step1 initial1 extract1) =
194{-# INLINE compact #-}
193{-# INLINE compact #-}
195compact :: (MonadIO m, Unbox a)
194compact :: (MonadIO m, Unbox a)
196 => Int -> Stream m (Array a) -> Stream m (Array a)
195 => Int -> Stream m (Array a) -> Stream m (Array a)
197−compact n = Stream.fromStreamD . packArraysChunksOf n . Stream.toStreamD
196+compact = packArraysChunksOf
198
197
199-- | Coalesce adjacent arrays in incoming stream to form bigger arrays of a
198-- | Coalesce adjacent arrays in incoming stream to form bigger arrays of a
200-- maximum specified size. Note that if a single array is bigger than the
199-- maximum specified size. Note that if a single array is bigger than the
@@ -299,10 +298,9 @@ compactGEFold n = Fold step initial extract
299-- maximum specified size in bytes.
298-- maximum specified size in bytes.
300--
299--
301-- /Internal/
300-- /Internal/
302−compactLE :: (Monad m, MonadIO m, Unbox a) =>
301+compactLE :: (MonadIO m, Unbox a) =>
303 Int -> Stream m (Array a) -> Stream m (Either ParseError (Array a))
302 Int -> Stream m (Array a) -> Stream m (Either ParseError (Array a))
304−compactLE n =
303+compactLE n = D.parseManyD (compactLEParserD n)
305− Stream.fromStreamD . D.parseMany (compactLEParserD n) . Stream.toStreamD
306
304
307-- | Like 'compactLE' but generates arrays of exactly equal to the size
305-- | Like 'compactLE' but generates arrays of exactly equal to the size
308-- specified except for the last array in the stream which could be shorter.
306-- specified except for the last array in the stream which could be shorter.
@@ -322,5 +320,4 @@ compactEQ _n _xs = undefined
322compactGE ::
320compactGE ::
323 (MonadIO m, Unbox a)
321 (MonadIO m, Unbox a)
324 => Int -> Stream m (Array a) -> Stream m (Array a)
322 => Int -> Stream m (Array a) -> Stream m (Array a)
325−compactGE n =
326− Stream.fromStreamD . D.foldMany (compactGEFold n) . Stream.toStreamD
323+compactGE n = D.foldMany (compactGEFold n)
core/src/Streamly/Internal/Data/Array/Mut/Type.hs+2−3
@@ -243,7 +243,7 @@ import GHC.Ptr (Ptr(..))
243
243
244import Streamly.Internal.Data.Fold.Type (Fold(..))
244import Streamly.Internal.Data.Fold.Type (Fold(..))
245import Streamly.Internal.Data.Producer.Type (Producer (..))
245import Streamly.Internal.Data.Producer.Type (Producer (..))
246−import Streamly.Internal.Data.Stream.Type (Stream)
246+import Streamly.Internal.Data.Stream.StreamD.Type (Stream)
247import Streamly.Internal.Data.SVar.Type (adaptState, defState)
247import Streamly.Internal.Data.SVar.Type (adaptState, defState)
248import Streamly.Internal.Data.Unfold.Type (Unfold(..))
248import Streamly.Internal.Data.Unfold.Type (Unfold(..))
249import Streamly.Internal.System.IO (arrayPayloadSize, defaultChunkSize)
249import Streamly.Internal.System.IO (arrayPayloadSize, defaultChunkSize)
@@ -252,7 +252,6 @@ import qualified Streamly.Internal.Data.Fold.Type as FL
252import qualified Streamly.Internal.Data.Producer as Producer
252import qualified Streamly.Internal.Data.Producer as Producer
253import qualified Streamly.Internal.Data.Stream.StreamD.Type as D
253import qualified Streamly.Internal.Data.Stream.StreamD.Type as D
254import qualified Streamly.Internal.Data.Stream.StreamK.Type as K
254import qualified Streamly.Internal.Data.Stream.StreamK.Type as K
255−import qualified Streamly.Internal.Data.Stream.Type as Stream
256import qualified Streamly.Internal.Data.Unboxed as Unboxed
255import qualified Streamly.Internal.Data.Unboxed as Unboxed
257import qualified Prelude
256import qualified Prelude
258
257
@@ -1036,7 +1035,7 @@ getIndicesD liftio (D.Stream stepi sti) = Unfold step inject
1036
1035
1037{-# INLINE getIndices #-}
1036{-# INLINE getIndices #-}
1038getIndices :: (MonadIO m, Unbox a) => Stream m Int -> Unfold m (Array a) a
1037getIndices :: (MonadIO m, Unbox a) => Stream m Int -> Unfold m (Array a) a
1039−getIndices = getIndicesD liftIO . Stream.toStreamD
1038+getIndices = getIndicesD liftIO
1040
1039
1041-------------------------------------------------------------------------------
1040-------------------------------------------------------------------------------
1042-- Subarrays
1041-- Subarrays
core/src/Streamly/Internal/Data/Array/Type.hs+12−6
@@ -90,7 +90,7 @@ import GHC.IO (unsafePerformIO)
90import GHC.Ptr (Ptr(..))
90import GHC.Ptr (Ptr(..))
91import Streamly.Internal.Data.Array.Mut.Type (MutableByteArray)
91import Streamly.Internal.Data.Array.Mut.Type (MutableByteArray)
92import Streamly.Internal.Data.Fold.Type (Fold(..))
92import Streamly.Internal.Data.Fold.Type (Fold(..))
93−import Streamly.Internal.Data.Stream.Type (Stream)
93+import Streamly.Internal.Data.Stream.StreamD.Type (Stream)
94import Streamly.Internal.Data.Unboxed (Unbox, peekWith, sizeOf)
94import Streamly.Internal.Data.Unboxed (Unbox, peekWith, sizeOf)
95import Streamly.Internal.Data.Unfold.Type (Unfold(..))
95import Streamly.Internal.Data.Unfold.Type (Unfold(..))
96import Text.Read (readPrec)
96import Text.Read (readPrec)
@@ -101,7 +101,6 @@ import qualified GHC.Exts as Exts
101import qualified Streamly.Internal.Data.Array.Mut.Type as MA
101import qualified Streamly.Internal.Data.Array.Mut.Type as MA
102import qualified Streamly.Internal.Data.Stream.StreamD.Type as D
102import qualified Streamly.Internal.Data.Stream.StreamD.Type as D
103import qualified Streamly.Internal.Data.Stream.StreamK.Type as K
103import qualified Streamly.Internal.Data.Stream.StreamK.Type as K
104−import qualified Streamly.Internal.Data.Stream.Type as Stream
105import qualified Streamly.Internal.Data.Unboxed as Unboxed
104import qualified Streamly.Internal.Data.Unboxed as Unboxed
106import qualified Streamly.Internal.Data.Unfold.Type as Unfold
105import qualified Streamly.Internal.Data.Unfold.Type as Unfold
107import qualified Text.ParserCombinators.ReadPrec as ReadPrec
106import qualified Text.ParserCombinators.ReadPrec as ReadPrec
@@ -113,6 +112,7 @@ import Streamly.Internal.System.IO (unsafeInlineIO, defaultChunkSize)
113-- >>> :m
112-- >>> :m
114-- >>> :set -XMagicHash
113-- >>> :set -XMagicHash
115-- >>> import Prelude hiding (length, foldr, read, unlines, splitAt)
114-- >>> import Prelude hiding (length, foldr, read, unlines, splitAt)
115+-- >>> import Streamly.Data.Stream as Stream
116-- >>> import Streamly.Internal.Data.Array as Array
116-- >>> import Streamly.Internal.Data.Array as Array
117
117
118-------------------------------------------------------------------------------
118-------------------------------------------------------------------------------
@@ -265,8 +265,14 @@ bufferChunks :: (MonadIO m, Unbox a) =>
265 D.Stream m a -> m (K.Stream m (Array a))
265 D.Stream m a -> m (K.Stream m (Array a))
266bufferChunks m = D.foldr K.cons K.nil $ arraysOf defaultChunkSize m
266bufferChunks m = D.foldr K.cons K.nil $ arraysOf defaultChunkSize m
267
267
268−-- | @arraysOf n stream@ groups the input stream into a stream of
268+-- | @arraysOf n stream@ groups the elements in the input stream into arrays of
269−-- arrays of size n.
269+-- @n@ elements each.
270+--
271+-- Same as the following but may be more efficient:
272+--
273+-- >>> arraysOf n = Stream.foldMany (Array.writeN n)
274+--
275+-- /Pre-release/
270{-# INLINE_NORMAL arraysOf #-}
276{-# INLINE_NORMAL arraysOf #-}
271arraysOf :: forall m a. (MonadIO m, Unbox a)
277arraysOf :: forall m a. (MonadIO m, Unbox a)
272 => Int -> D.Stream m a -> D.Stream m (Array a)
278 => Int -> D.Stream m a -> D.Stream m (Array a)
@@ -360,7 +366,7 @@ toStreamKRev arr =
360-- /Pre-release/
366-- /Pre-release/
361{-# INLINE_EARLY read #-}
367{-# INLINE_EARLY read #-}
362read :: (Monad m, Unbox a) => Array a -> Stream m a
368read :: (Monad m, Unbox a) => Array a -> Stream m a
363−read = Stream.fromStreamD . toStreamD
369+read = toStreamD
364
370
365-- | Same as 'read'
371-- | Same as 'read'
366--
372--
@@ -377,7 +383,7 @@ toStream = read
377-- /Pre-release/
383-- /Pre-release/
378{-# INLINE_EARLY readRev #-}
384{-# INLINE_EARLY readRev #-}
379readRev :: (Monad m, Unbox a) => Array a -> Stream m a
385readRev :: (Monad m, Unbox a) => Array a -> Stream m a
380−readRev = Stream.fromStreamD . toStreamDRev
386+readRev = toStreamDRev
381
387
382-- | Same as 'readRev'
388-- | Same as 'readRev'
383--
389--
core/src/Streamly/Internal/Data/Fold.hs+14−15
@@ -160,7 +160,7 @@ module Streamly.Internal.Data.Fold
160
160
161 -- * Running A Fold
161 -- * Running A Fold
162 , drive
162 , drive
163− , breakStream
163+ -- , breakStream
164
164
165 -- * Building Incrementally
165 -- * Building Incrementally
166 , extractM
166 , extractM
@@ -325,7 +325,7 @@ import Streamly.Internal.Data.Pipe.Type (Pipe (..), PipeState(..))
325import Streamly.Internal.Data.Unboxed (Unbox, sizeOf)
325import Streamly.Internal.Data.Unboxed (Unbox, sizeOf)
326import Streamly.Internal.Data.Unfold.Type (Unfold(..))
326import Streamly.Internal.Data.Unfold.Type (Unfold(..))
327import Streamly.Internal.Data.Tuple.Strict (Tuple'(..), Tuple3'(..))
327import Streamly.Internal.Data.Tuple.Strict (Tuple'(..), Tuple3'(..))
328−import Streamly.Internal.Data.Stream.Type (Stream)
328+import Streamly.Internal.Data.Stream.StreamD.Type (Stream)
329
329
330import qualified Prelude
330import qualified Prelude
331import qualified Streamly.Internal.Data.Array.Mut.Type as MA
331import qualified Streamly.Internal.Data.Array.Mut.Type as MA
@@ -334,8 +334,6 @@ import qualified Streamly.Internal.Data.Fold.Window as FoldW
334import qualified Streamly.Internal.Data.Pipe.Type as Pipe
334import qualified Streamly.Internal.Data.Pipe.Type as Pipe
335import qualified Streamly.Internal.Data.Ring.Unboxed as Ring
335import qualified Streamly.Internal.Data.Ring.Unboxed as Ring
336import qualified Streamly.Internal.Data.Stream.StreamD.Type as StreamD
336import qualified Streamly.Internal.Data.Stream.StreamD.Type as StreamD
337−import qualified Streamly.Internal.Data.Stream.StreamK as K
338−import qualified Streamly.Internal.Data.Stream.Type as Stream
339
337
340import Prelude hiding
338import Prelude hiding
341 ( filter, foldl1, drop, dropWhile, take, takeWhile, zipWith
339 ( filter, foldl1, drop, dropWhile, take, takeWhile, zipWith
@@ -366,7 +364,6 @@ import Streamly.Internal.Data.Fold.Tee
366-- >>> import qualified Streamly.Internal.Data.Fold.Type as Fold
364-- >>> import qualified Streamly.Internal.Data.Fold.Type as Fold
367-- >>> import qualified Streamly.Internal.Data.Fold.Window as FoldW
365-- >>> import qualified Streamly.Internal.Data.Fold.Window as FoldW
368-- >>> import qualified Streamly.Internal.Data.Parser as Parser
366-- >>> import qualified Streamly.Internal.Data.Parser as Parser
369−-- >>> import qualified Streamly.Internal.Data.Stream.Type as Stream
370-- >>> import qualified Streamly.Internal.Data.Unfold as Unfold
367-- >>> import qualified Streamly.Internal.Data.Unfold as Unfold
371-- >>> import Prelude hiding (break, map, span, splitAt)
368-- >>> import Prelude hiding (break, map, span, splitAt)
372
369
@@ -388,8 +385,9 @@ import Streamly.Internal.Data.Fold.Tee
388--
385--
389{-# INLINE drive #-}
386{-# INLINE drive #-}
390drive :: Monad m => Stream m a -> Fold m a b -> m b
387drive :: Monad m => Stream m a -> Fold m a b -> m b
391−drive strm fl = StreamD.fold fl $ StreamD.fromStreamK $ Stream.toStreamK strm
388+drive = flip StreamD.fold
392
389
390+{-
393-- | Like 'drive' but also returns the remaining stream. The resulting stream
391-- | Like 'drive' but also returns the remaining stream. The resulting stream
394-- would be 'Stream.nil' if the stream finished before the fold.
392-- would be 'Stream.nil' if the stream finished before the fold.
395--
393--
@@ -399,13 +397,14 @@ drive strm fl = StreamD.fold fl $ StreamD.fromStreamK $ Stream.toStreamK strm
399--
397--
400-- /CPS/
398-- /CPS/
401--
399--
402−{-# INLINE breakStream #-}
400+{-# INLINE breakStreamK #-}
403−breakStream :: Monad m => Stream m a -> Fold m a b -> m (b, Stream m a)
401+breakStreamK :: Monad m => StreamK m a -> Fold m a b -> m (b, StreamK m a)
404−breakStream strm fl = fmap f $ K.foldBreak fl (Stream.toStreamK strm)
402+breakStreamK strm fl = fmap f $ K.foldBreak fl (Stream.toStreamK strm)
405
403
406 where
404 where
407
405
408 f (b, str) = (b, Stream.fromStreamK str)
406 f (b, str) = (b, Stream.fromStreamK str)
407+-}
409
408
410-- | Append a stream to a fold to build the fold accumulator incrementally. We
409-- | Append a stream to a fold to build the fold accumulator incrementally. We
411-- can repeatedly call 'addStream' on the same fold to continue building the
410-- can repeatedly call 'addStream' on the same fold to continue building the
@@ -2386,12 +2385,12 @@ chunksBetween _low _high _f1 _f2 = undefined
2386-- /Warning!/ working on large streams accumulated as buffers in memory could
2385-- /Warning!/ working on large streams accumulated as buffers in memory could
2387-- be very inefficient, consider using "Streamly.Data.Array" instead.
2386-- be very inefficient, consider using "Streamly.Data.Array" instead.
2388--
2387--
2389−-- >>> toStream = fmap Stream.fromStreamK Fold.toStreamK
2388+-- >>> toStream = fmap Stream.fromList Fold.toList
2390--
2389--
2391-- /Pre-release/
2390-- /Pre-release/
2392{-# INLINE toStream #-}
2391{-# INLINE toStream #-}
2393−toStream :: Monad m => Fold m a (Stream n a)
2392+toStream :: (Monad m, Monad n) => Fold m a (Stream n a)
2394−toStream = fmap Stream.fromStreamK toStreamK
2393+toStream = fmap StreamD.fromList toList
2395
2394
2396-- This is more efficient than 'toStream'. toStream is exactly the same as
2395-- This is more efficient than 'toStream'. toStream is exactly the same as
2397-- reversing the stream after toStreamRev.
2396-- reversing the stream after toStreamRev.
@@ -2399,7 +2398,7 @@ toStream = fmap Stream.fromStreamK toStreamK
2399-- | Buffers the input stream to a pure stream in the reverse order of the
2398-- | Buffers the input stream to a pure stream in the reverse order of the
2400-- input.
2399-- input.
2401--
2400--
2402−-- >>> toStreamRev = fmap Stream.fromStreamK Fold.toStreamKRev
2401+-- >>> toStreamRev = fmap Stream.fromList Fold.toListRev
2403--
2402--
2404-- /Warning!/ working on large streams accumulated as buffers in memory could
2403-- /Warning!/ working on large streams accumulated as buffers in memory could
2405-- be very inefficient, consider using "Streamly.Data.Array" instead.
2404-- be very inefficient, consider using "Streamly.Data.Array" instead.
@@ -2408,8 +2407,8 @@ toStream = fmap Stream.fromStreamK toStreamK
2408
2407
2409-- xn : ... : x2 : x1 : []
2408-- xn : ... : x2 : x1 : []
2410{-# INLINE toStreamRev #-}
2409{-# INLINE toStreamRev #-}
2411−toStreamRev :: Monad m => Fold m a (Stream n a)
2410+toStreamRev :: (Monad m, Monad n) => Fold m a (Stream n a)
2412−toStreamRev = fmap Stream.fromStreamK toStreamKRev
2411+toStreamRev = fmap StreamD.fromList toListRev
2413
2412
2414-- XXX This does not fuse. It contains a recursive step function. We will need
2413-- XXX This does not fuse. It contains a recursive step function. We will need
2415-- a Skip input constructor in the fold type to make it fuse.
2414-- a Skip input constructor in the fold type to make it fuse.
core/src/Streamly/Internal/Data/Fold/Chunked.hs+4−14
@@ -6,6 +6,8 @@
6-- Stability : experimental
6-- Stability : experimental
7-- Portability : GHC
7-- Portability : GHC
8--
8--
9+-- Use "Streamly.Data.Parser.Chunked" instead.
10+--
9-- Fold a stream of foreign arrays. @Fold m a b@ in this module works
11-- Fold a stream of foreign arrays. @Fold m a b@ in this module works
10-- on a stream of "Array a" and produces an output of type @b@.
12-- on a stream of "Array a" and produces an output of type @b@.
11--
13--
@@ -20,12 +22,12 @@
20-- >>> import qualified Streamly.Data.Fold as Fold
22-- >>> import qualified Streamly.Data.Fold as Fold
21-- >>> import qualified Streamly.Internal.Data.Stream.Chunked as ArrayStream
23-- >>> import qualified Streamly.Internal.Data.Stream.Chunked as ArrayStream
22-- >>> import qualified Streamly.Internal.Data.Fold.Chunked as ChunkFold
24-- >>> import qualified Streamly.Internal.Data.Fold.Chunked as ChunkFold
23−-- >>> import qualified Streamly.Internal.Data.Stream as Stream (arraysOf)
24-- >>> import qualified Streamly.Data.Stream as Stream
25-- >>> import qualified Streamly.Data.Stream as Stream
26+-- >>> import qualified Streamly.Data.Stream.StreamK as StreamK
25--
27--
26-- >>> f = ChunkFold.fromFold (Fold.take 7 Fold.toList)
28-- >>> f = ChunkFold.fromFold (Fold.take 7 Fold.toList)
27-- >>> s = Stream.arraysOf 5 $ Stream.fromList "hello world"
29-- >>> s = Stream.arraysOf 5 $ Stream.fromList "hello world"
28−-- >>> ArrayStream.runArrayFold f s
30+-- >>> ArrayStream.runArrayFold f (StreamK.fromStream s)
29-- Right "hello w"
31-- Right "hello w"
30--
32--
31module Streamly.Internal.Data.Fold.Chunked
33module Streamly.Internal.Data.Fold.Chunked
@@ -98,11 +100,7 @@ newtype ChunkFold m a b = ChunkFold (ParserD.Parser (Array a) m b)
98--
100--
99-- /Pre-release/
101-- /Pre-release/
100{-# INLINE fromFold #-}
102{-# INLINE fromFold #-}
101−#ifdef DEVBUILD
102−fromFold :: forall m a b. (MonadIO m) =>
103−#else
104fromFold :: forall m a b. (MonadIO m, Unbox a) =>
103fromFold :: forall m a b. (MonadIO m, Unbox a) =>
105−#endif
106 Fold.Fold m a b -> ChunkFold m a b
104 Fold.Fold m a b -> ChunkFold m a b
107fromFold (Fold.Fold fstep finitial fextract) =
105fromFold (Fold.Fold fstep finitial fextract) =
108 ChunkFold (ParserD.Parser step initial (fmap (Done 0) . fextract))
106 ChunkFold (ParserD.Parser step initial (fmap (Done 0) . fextract))
@@ -140,11 +138,7 @@ fromFold (Fold.Fold fstep finitial fextract) =
140--
138--
141-- /Pre-release/
139-- /Pre-release/
142{-# INLINE fromParserD #-}
140{-# INLINE fromParserD #-}
143−#ifdef DEVBUILD
144−fromParserD :: forall m a b. (MonadIO m) =>
145−#else
146fromParserD :: forall m a b. (MonadIO m, Unbox a) =>
141fromParserD :: forall m a b. (MonadIO m, Unbox a) =>
147−#endif
148 ParserD.Parser a m b -> ChunkFold m a b
142 ParserD.Parser a m b -> ChunkFold m a b
149fromParserD (ParserD.Parser step1 initial1 extract1) =
143fromParserD (ParserD.Parser step1 initial1 extract1) =
150 ChunkFold (ParserD.Parser step initial1 extract1)
144 ChunkFold (ParserD.Parser step initial1 extract1)
@@ -186,11 +180,7 @@ fromParserD (ParserD.Parser step1 initial1 extract1) =
186--
180--
187-- /Pre-release/
181-- /Pre-release/
188{-# INLINE fromParser #-}
182{-# INLINE fromParser #-}
189−#ifdef DEVBUILD
190−fromParser :: forall m a b. (MonadIO m) =>
191−#else
192fromParser :: forall m a b. (MonadIO m, Unbox a) =>
183fromParser :: forall m a b. (MonadIO m, Unbox a) =>
193−#endif
194 Parser.Parser a m b -> ChunkFold m a b
184 Parser.Parser a m b -> ChunkFold m a b
195fromParser = fromParserD . ParserD.fromParserK
185fromParser = fromParserD . ParserD.fromParserK
196
186
core/src/Streamly/Internal/Data/Fold/Type.hs+1−1
@@ -445,7 +445,7 @@ import Prelude hiding (concatMap, filter, foldr, map, take)
445-- >>> import Data.Maybe (fromJust, isJust)
445-- >>> import Data.Maybe (fromJust, isJust)
446-- >>> import Data.Monoid (Endo(..))
446-- >>> import Data.Monoid (Endo(..))
447-- >>> import Streamly.Data.Fold (Fold)
447-- >>> import Streamly.Data.Fold (Fold)
448−-- >>> import Streamly.Internal.Data.Stream.Type (Stream)
448+-- >>> import Streamly.Data.Stream (Stream)
449-- >>> import qualified Data.Foldable as Foldable
449-- >>> import qualified Data.Foldable as Foldable
450-- >>> import qualified Streamly.Data.Fold as Fold
450-- >>> import qualified Streamly.Data.Fold as Fold
451-- >>> import qualified Streamly.Internal.Data.Fold as Fold
451-- >>> import qualified Streamly.Internal.Data.Fold as Fold
core/src/Streamly/Internal/Data/Parser.hs+10−4
@@ -251,13 +251,19 @@ where
251
251
252import Streamly.Internal.Data.Fold.Type (Fold(..))
252import Streamly.Internal.Data.Fold.Type (Fold(..))
253import Streamly.Internal.Data.Parser.ParserK.Type (Parser)
253import Streamly.Internal.Data.Parser.ParserK.Type (Parser)
254−import Streamly.Internal.Data.Stream.Type (Stream)
255
254
256import qualified Data.Foldable as Foldable
255import qualified Data.Foldable as Foldable
257import qualified Streamly.Internal.Data.Fold.Type as FL
256import qualified Streamly.Internal.Data.Fold.Type as FL
258import qualified Streamly.Internal.Data.Parser.ParserD as D
257import qualified Streamly.Internal.Data.Parser.ParserD as D
259import qualified Streamly.Internal.Data.Parser.ParserK.Type as K
258import qualified Streamly.Internal.Data.Parser.ParserK.Type as K
259+
260+#ifdef USE_STREAMK
261+import Streamly.Internal.Data.StreamK (Stream)
262+import qualified Streamly.Internal.Data.StreamK as Stream
263+#else
264+import Streamly.Internal.Data.Stream.StreamD.Type (Stream)
260−import qualified Streamly.Internal.Data.Stream.Type as Stream
265+import qualified Streamly.Internal.Data.Stream.StreamD.Type as Stream
266+#endif
261
267
262import Prelude hiding
268import Prelude hiding
263 ( any, all, dropWhile, take, takeWhile, sequence, concatMap, maybe, either
269 ( any, all, dropWhile, take, takeWhile, sequence, concatMap, maybe, either
@@ -1007,7 +1013,7 @@ groupByRollingEither eq f1 = D.toParserK . D.groupByRollingEither eq f1
1007--
1013--
1008{-# INLINE streamEqBy #-}
1014{-# INLINE streamEqBy #-}
1009streamEqBy :: Monad m => (a -> a -> Bool) -> Stream m a -> Parser a m ()
1015streamEqBy :: Monad m => (a -> a -> Bool) -> Stream m a -> Parser a m ()
1010−streamEqBy cmp = D.toParserK . D.streamEqBy cmp . Stream.toStreamD
1016+streamEqBy cmp = D.toParserK . D.streamEqBy cmp
1011
1017
1012-- | Match the given sequence of elements using the given comparison function.
1018-- | Match the given sequence of elements using the given comparison function.
1013-- Returns the original sequence if successful.
1019-- Returns the original sequence if successful.
@@ -1259,7 +1265,7 @@ concatSequence ::
1259 Monad m =>
1265 Monad m =>
1260 Fold m b c -> Stream m (Parser a m b) -> Parser a m c
1266 Fold m b c -> Stream m (Parser a m b) -> Parser a m c
1261concatSequence f p =
1267concatSequence f p =
1262− let sp = fmap D.fromParserK $ Stream.toStreamD p
1268+ let sp = fmap D.fromParserK p
1263 in D.toParserK $ D.sequence sp f
1269 in D.toParserK $ D.sequence sp f
1264
1270
1265-- | Map a 'Parser' returning function on the result of a 'Parser'.
1271-- | Map a 'Parser' returning function on the result of a 'Parser'.
core/src/Streamly/Internal/Data/Parser/Chunked.hs+9−10
@@ -42,7 +42,7 @@ import GHC.Types (SPEC(..))
42import Streamly.Internal.Data.Array.Type (Array(..))
42import Streamly.Internal.Data.Array.Type (Array(..))
43import Streamly.Internal.Data.Parser.Chunked.Type (ChunkParser (..))
43import Streamly.Internal.Data.Parser.Chunked.Type (ChunkParser (..))
44import Streamly.Internal.Data.Parser.ParserD.Type (Initial(..), Step(..))
44import Streamly.Internal.Data.Parser.ParserD.Type (Initial(..), Step(..))
45−import Streamly.Internal.Data.Stream.Type (Stream)
45+import Streamly.Internal.Data.Stream.StreamK.Type (StreamK)
46import Streamly.Internal.Data.SVar.Type (defState)
46import Streamly.Internal.Data.SVar.Type (defState)
47import Streamly.Internal.Data.Unboxed (peekWith, sizeOf, Unbox)
47import Streamly.Internal.Data.Unboxed (peekWith, sizeOf, Unbox)
48
48
@@ -51,7 +51,6 @@ import qualified Streamly.Internal.Data.Parser.Chunked.Type as K
51import qualified Streamly.Internal.Data.Parser.ParserD as D
51import qualified Streamly.Internal.Data.Parser.ParserD as D
52 hiding (fromParserK, toParserK)
52 hiding (fromParserK, toParserK)
53import qualified Streamly.Internal.Data.Stream.StreamK as StreamK
53import qualified Streamly.Internal.Data.Stream.StreamK as StreamK
54−import qualified Streamly.Internal.Data.Stream.Type as Stream
55import Streamly.Internal.Data.Parser.ParserD (ParseError(..))
54import Streamly.Internal.Data.Parser.ParserD (ParseError(..))
56
55
57-------------------------------------------------------------------------------
56-------------------------------------------------------------------------------
@@ -97,11 +96,11 @@ parserDone (K.Failure n e) _ _ = return $ K.Error n e
97parseBreak
96parseBreak
98 :: (Monad m, Unbox a)
97 :: (Monad m, Unbox a)
99 => ChunkParser a m b
98 => ChunkParser a m b
100− -> Stream m (Array a)
99+ -> StreamK m (Array a)
101− -> m (Either ParseError b, Stream m (Array a))
100+ -> m (Either ParseError b, StreamK m (Array a))
102parseBreak parser input = do
101parseBreak parser input = do
103 let parserk = \arr -> K.runParser parser 0 0 arr parserDone
102 let parserk = \arr -> K.runParser parser 0 0 arr parserDone
104− in go [] parserk (Stream.toStreamK input)
103+ in go [] parserk input
105
104
106 where
105 where
107
106
@@ -127,13 +126,13 @@ parseBreak parser input = do
127 let (s1, backBuf1) = backTrack n1 backBuf StreamK.nil
126 let (s1, backBuf1) = backTrack n1 backBuf StreamK.nil
128 in go backBuf1 cont1 s1
127 in go backBuf1 cont1 s1
129 K.Done 0 b ->
128 K.Done 0 b ->
130− return (Right b, Stream.nil)
129+ return (Right b, StreamK.nil)
131 K.Done n b -> do
130 K.Done n b -> do
132 let n1 = negate n
131 let n1 = negate n
133 assertM(n1 >= 0 && n1 <= sum (map Array.length backBuf))
132 assertM(n1 >= 0 && n1 <= sum (map Array.length backBuf))
134 let (s1, _) = backTrack n1 backBuf StreamK.nil
133 let (s1, _) = backTrack n1 backBuf StreamK.nil
135− in return (Right b, Stream.fromStreamK s1)
134+ in return (Right b, s1)
136− K.Error _ err -> return (Left (ParseError err), Stream.nil)
135+ K.Error _ err -> return (Left (ParseError err), StreamK.nil)
137
136
138 seekErr n len =
137 seekErr n len =
139 error $ "parseBreak: Partial: forward seek not implemented n = "
138 error $ "parseBreak: Partial: forward seek not implemented n = "
@@ -175,8 +174,8 @@ parseBreak parser input = do
175 let n1 = len - n
174 let n1 = len - n
176 assertM(n1 <= sum (map Array.length (arr:backBuf)))
175 assertM(n1 <= sum (map Array.length (arr:backBuf)))
177 let (s1, _) = backTrack n1 (arr:backBuf) stream
176 let (s1, _) = backTrack n1 (arr:backBuf) stream
178− in return (Right b, Stream.fromStreamK s1)
177+ in return (Right b, s1)
179− K.Error _ err -> return (Left (ParseError err), Stream.nil)
178+ K.Error _ err -> return (Left (ParseError err), StreamK.nil)
180
179
181 go backBuf parserk stream = do
180 go backBuf parserk stream = do
182 let stop = goStop backBuf parserk
181 let stop = goStop backBuf parserk
core/src/Streamly/Internal/Data/Ring/Unboxed.hs+1−1
@@ -84,7 +84,7 @@ import GHC.ForeignPtr (mallocPlainForeignPtrAlignedBytes)
84import GHC.Ptr (Ptr(..))
84import GHC.Ptr (Ptr(..))
85import Streamly.Internal.Data.Array.Mut.Type (Array)
85import Streamly.Internal.Data.Array.Mut.Type (Array)
86import Streamly.Internal.Data.Fold.Type (Fold(..), Step(..), lmap)
86import Streamly.Internal.Data.Fold.Type (Fold(..), Step(..), lmap)
87−import Streamly.Internal.Data.Stream.Type (Stream)
87+import Streamly.Internal.Data.Stream.StreamD.Type (Stream)
88import Streamly.Internal.Data.Stream.StreamD.Step (Step(..))
88import Streamly.Internal.Data.Stream.StreamD.Step (Step(..))
89import Streamly.Internal.Data.Unfold.Type (Unfold(..))
89import Streamly.Internal.Data.Unfold.Type (Unfold(..))
90import Streamly.Internal.System.IO (unsafeInlineIO)
90import Streamly.Internal.System.IO (unsafeInlineIO)
core/src/Streamly/Internal/Data/Stream.hs+3−32
@@ -1,43 +1,14 @@
1-- |
1-- |
2-- Module : Streamly.Internal.Data.Stream
2-- Module : Streamly.Internal.Data.Stream
3−-- Copyright : (c) 2017 Composewell Technologies
3+-- Copyright : (c) 2019 Composewell Technologies
4-- License : BSD-3-Clause
4-- License : BSD-3-Clause
5-- Maintainer : streamly@composewell.com
5-- Maintainer : streamly@composewell.com
6-- Stability : experimental
6-- Stability : experimental
7-- Portability : GHC
7-- Portability : GHC
8--
8--
9module Streamly.Internal.Data.Stream
9module Streamly.Internal.Data.Stream
10− ( module Streamly.Internal.Data.Stream.Type
10+ ( module Streamly.Internal.Data.Stream.StreamD
11− , module Streamly.Internal.Data.Stream.Bottom
12− , module Streamly.Internal.Data.Stream.Eliminate
13− , module Streamly.Internal.Data.Stream.Exception
14− , module Streamly.Internal.Data.Stream.Expand
15− , module Streamly.Internal.Data.Stream.Generate
16− , module Streamly.Internal.Data.Stream.Lift
17− , module Streamly.Internal.Data.Stream.Reduce
18− , module Streamly.Internal.Data.Stream.Transform
19− , module Streamly.Internal.Data.Stream.Top
20− , module Streamly.Internal.Data.Stream.Cross
21− , module Streamly.Internal.Data.Stream.Zip
22−
23− -- modules having dependencies on libraries other than base
24− , module Streamly.Internal.Data.Stream.Transformer
25− , module Streamly.Internal.Data.Stream.Container
26 )
11 )
27where
12where
28
13
29−import Streamly.Internal.Data.Stream.Bottom
14+import Streamly.Internal.Data.Stream.StreamD
30−import Streamly.Internal.Data.Stream.Cross
31−import Streamly.Internal.Data.Stream.Eliminate
32−import Streamly.Internal.Data.Stream.Exception
33−import Streamly.Internal.Data.Stream.Expand
34−import Streamly.Internal.Data.Stream.Generate
35−import Streamly.Internal.Data.Stream.Lift
36−import Streamly.Internal.Data.Stream.Reduce
37−import Streamly.Internal.Data.Stream.Top
38−import Streamly.Internal.Data.Stream.Transform
39−import Streamly.Internal.Data.Stream.Type
40−import Streamly.Internal.Data.Stream.Zip
41−
42−import Streamly.Internal.Data.Stream.Container
43−import Streamly.Internal.Data.Stream.Transformer
core/src/Streamly/Internal/Data/Stream/Bottom.hs+7−7
@@ -131,7 +131,7 @@ import Streamly.Internal.Data.Stream.Type
131--
131--
132{-# INLINE timesWith #-}
132{-# INLINE timesWith #-}
133timesWith :: MonadIO m => Double -> Stream m (AbsTime, RelTime64)
133timesWith :: MonadIO m => Double -> Stream m (AbsTime, RelTime64)
134−timesWith g = fromStreamD $ D.times g
134+timesWith g = fromStreamD $ D.timesWith g
135
135
136-- | @absTimesWith g@ returns a stream of absolute timestamps using a clock of
136-- | @absTimesWith g@ returns a stream of absolute timestamps using a clock of
137-- granularity @g@ specified in seconds. A low granularity clock is more
137-- granularity @g@ specified in seconds. A low granularity clock is more
@@ -186,7 +186,7 @@ relTimesWith = fmap snd . timesWith
186--
186--
187{-# INLINE foldAddLazy #-}
187{-# INLINE foldAddLazy #-}
188foldAddLazy :: Monad m => Fold m a b -> Stream m a -> Fold m a b
188foldAddLazy :: Monad m => Fold m a b -> Stream m a -> Fold m a b
189−foldAddLazy f s = D.foldContinue f $ toStreamD s
189+foldAddLazy f s = D.foldAddLazy f $ toStreamD s
190
190
191-- >>> foldAdd f = Stream.foldAddLazy f >=> Fold.reduce
191-- >>> foldAdd f = Stream.foldAddLazy f >=> Fold.reduce
192
192
@@ -385,7 +385,7 @@ map f = fromStreamD . D.map f . toStreamD
385--
385--
386{-# INLINE postscan #-}
386{-# INLINE postscan #-}
387postscan :: Monad m => Fold m a b -> Stream m a -> Stream m b
387postscan :: Monad m => Fold m a b -> Stream m a -> Stream m b
388−postscan fld = fromStreamD . D.postscanOnce fld . toStreamD
388+postscan fld = fromStreamD . D.postscan fld . toStreamD
389
389
390-- $smapM_Notes
390-- $smapM_Notes
391--
391--
@@ -531,8 +531,8 @@ intersperseM m = fromStreamD . D.intersperseM m . toStreamD
531-- >>> reverse = Stream.foldlT (flip Stream.cons) Stream.nil
531-- >>> reverse = Stream.foldlT (flip Stream.cons) Stream.nil
532--
532--
533{-# INLINE reverse #-}
533{-# INLINE reverse #-}
534−reverse :: Monad m => Stream m a -> Stream m a
534+reverse :: Stream m a -> Stream m a
535−reverse s = fromStreamD $ D.reverse $ toStreamD s
535+reverse s = fromStreamK $ K.reverse $ toStreamK s
536
536
537-- | Like 'reverse' but several times faster, requires a 'Storable' instance.
537-- | Like 'reverse' but several times faster, requires a 'Storable' instance.
538--
538--
@@ -651,7 +651,7 @@ foldManyPost f m = fromStreamD $ D.foldManyPost f (toStreamD m)
651{-# INLINE zipWithM #-}
651{-# INLINE zipWithM #-}
652zipWithM :: Monad m =>
652zipWithM :: Monad m =>
653 (a -> b -> m c) -> Stream m a -> Stream m b -> Stream m c
653 (a -> b -> m c) -> Stream m a -> Stream m b -> Stream m c
654−zipWithM f m1 m2 = fromStreamD $ D.zipWithM f (toStreamD m1) (toStreamD m2)
654+zipWithM f m1 m2 = fromStreamK $ K.zipWithM f (toStreamK m1) (toStreamK m2)
655
655
656-- | Stream @a@ is evaluated first, followed by stream @b@, the resulting
656-- | Stream @a@ is evaluated first, followed by stream @b@, the resulting
657-- elements @a@ and @b@ are then zipped using the supplied zip function and the
657-- elements @a@ and @b@ are then zipped using the supplied zip function and the
@@ -667,4 +667,4 @@ zipWithM f m1 m2 = fromStreamD $ D.zipWithM f (toStreamD m1) (toStreamD m2)
667--
667--
668{-# INLINE zipWith #-}
668{-# INLINE zipWith #-}
669zipWith :: Monad m => (a -> b -> c) -> Stream m a -> Stream m b -> Stream m c
669zipWith :: Monad m => (a -> b -> c) -> Stream m a -> Stream m b -> Stream m c
670−zipWith f m1 m2 = fromStreamD $ D.zipWith f (toStreamD m1) (toStreamD m2)
670+zipWith f m1 m2 = fromStreamK $ K.zipWith f (toStreamK m1) (toStreamK m2)
core/src/Streamly/Internal/Data/Stream/Chunked.hs+65−61
@@ -23,27 +23,42 @@ module Streamly.Internal.Data.Stream.Chunked
23
23
24 -- * Elimination
24 -- * Elimination
25 -- ** Element Folds
25 -- ** Element Folds
26+ -- The byte level foldBreak can work as efficiently as the chunk level. We
27+ -- can flatten the stream to byte stream and use that. But if we want the
28+ -- remaining stream to be a chunk stream then this could be handy. But it
29+ -- could also be implemented using parseBreak.
26− , foldBreak
30+ , foldBreak -- StreamK.foldBreakChunks
27 , foldBreakD
31 , foldBreakD
32+ -- The byte level parseBreak cannot work efficiently. Because the stream
33+ -- will have to be a StreamK for backtracking, StreamK at byte level would
34+ -- not be efficient.
28− , parseBreak
35+ , parseBreak -- StreamK.parseBreakChunks
29 -- , parseBreakD
36 -- , parseBreakD
37+ -- , foldManyChunks
38+ -- , parseManyChunks
30
39
31 -- ** Array Folds
40 -- ** Array Folds
41+ -- XXX Use Parser.Chunked instead, need only chunkedParseBreak,
42+ -- foldBreak can be implemented using parseBreak. Use StreamK.
32 , runArrayFold
43 , runArrayFold
33 , runArrayFoldBreak
44 , runArrayFoldBreak
34 -- , parseArr
45 -- , parseArr
35− , runArrayParserDBreak
46+ , runArrayParserDBreak -- StreamK.chunkedParseBreak
36− , runArrayFoldMany
47+ , runArrayFoldMany -- StreamK.chunkedParseMany
37
48
38 , toArray
49 , toArray
39
50
40 -- * Compaction
51 -- * Compaction
52+ -- We can use something like foldManyChunks, parseManyChunks with a take
53+ -- fold.
41− , lpackArraysChunksOf
54+ , lpackArraysChunksOf -- Fold.compactChunks
42− , compact
55+ , compact -- rechunk, compactChunks
43
56
44 -- * Splitting
57 -- * Splitting
58+ -- We can use something like foldManyChunks, parseManyChunks with an
59+ -- appropriate splitting fold.
45− , splitOn
60+ , splitOn -- Stream.rechunkOn
46− , splitOnSuffix
61+ , splitOnSuffix -- Stream.rechunkOnSuffix
47 )
62 )
48where
63where
49
64
@@ -62,12 +77,11 @@ import GHC.Types (SPEC(..))
62import Prelude hiding (null, last, (!!), read, concat, unlines)
77import Prelude hiding (null, last, (!!), read, concat, unlines)
63
78
64import Streamly.Data.Fold (Fold)
79import Streamly.Data.Fold (Fold)
65−import Streamly.Data.Stream (Stream)
66import Streamly.Internal.Data.Array.Type (Array(..))
80import Streamly.Internal.Data.Array.Type (Array(..))
67import Streamly.Internal.Data.Fold.Chunked (ChunkFold(..))
81import Streamly.Internal.Data.Fold.Chunked (ChunkFold(..))
68import Streamly.Internal.Data.Parser (ParseError(..))
82import Streamly.Internal.Data.Parser (ParseError(..))
69−import Streamly.Internal.Data.Stream
83+import Streamly.Internal.Data.Stream.StreamD (Stream)
70− (fromStreamD, fromStreamK, toStreamD, toStreamK)
84+import Streamly.Internal.Data.Stream.StreamK (StreamK, fromStream, toStream)
71import Streamly.Internal.Data.SVar.Type (adaptState, defState)
85import Streamly.Internal.Data.SVar.Type (adaptState, defState)
72import Streamly.Internal.Data.Array.Mut.Type
86import Streamly.Internal.Data.Array.Mut.Type
73 (allocBytesToElemCount)
87 (allocBytesToElemCount)
@@ -83,15 +97,8 @@ import qualified Streamly.Internal.Data.Fold.Type as FL (Fold(..), Step(..))
83import qualified Streamly.Internal.Data.Parser as PR
97import qualified Streamly.Internal.Data.Parser as PR
84import qualified Streamly.Internal.Data.Parser.ParserD as PRD
98import qualified Streamly.Internal.Data.Parser.ParserD as PRD
85 (Parser(..), Initial(..), fromParserK)
99 (Parser(..), Initial(..), fromParserK)
86−import qualified Streamly.Internal.Data.Stream as S
87import qualified Streamly.Internal.Data.Stream.StreamD as D
100import qualified Streamly.Internal.Data.Stream.StreamD as D
88− ( fromList, nil, cons, map
89− , unfoldMany, append, splitInnerBy, splitInnerBySuffix, foldlM'
90− )
91−import qualified Streamly.Internal.Data.Stream.StreamD.Type as D
92− (Step(Yield, Stop, Skip), Stream(Stream))
93−import qualified Streamly.Internal.Data.Stream.StreamK.Type as K
101+import qualified Streamly.Internal.Data.Stream.StreamK as K
94− (Stream, cons, nil, fromPure, foldStream)
95
102
96-- XXX Since these are immutable arrays MonadIO constraint can be removed from
103-- XXX Since these are immutable arrays MonadIO constraint can be removed from
97-- most places.
104-- most places.
@@ -109,7 +116,7 @@ import qualified Streamly.Internal.Data.Stream.StreamK.Type as K
109{-# INLINE arraysOf #-}
116{-# INLINE arraysOf #-}
110arraysOf :: (MonadIO m, Unbox a)
117arraysOf :: (MonadIO m, Unbox a)
111 => Int -> Stream m a -> Stream m (Array a)
118 => Int -> Stream m a -> Stream m (Array a)
112−arraysOf n str = fromStreamD $ A.arraysOf n (toStreamD str)
119+arraysOf = A.arraysOf
113
120
114-------------------------------------------------------------------------------
121-------------------------------------------------------------------------------
115-- Append
122-- Append
@@ -130,7 +137,7 @@ arraysOf n str = fromStreamD $ A.arraysOf n (toStreamD str)
130concat :: (Monad m, Unbox a) => Stream m (Array a) -> Stream m a
137concat :: (Monad m, Unbox a) => Stream m (Array a) -> Stream m a
131-- concat m = fromStreamD $ A.flattenArrays (toStreamD m)
138-- concat m = fromStreamD $ A.flattenArrays (toStreamD m)
132-- concat m = fromStreamD $ D.concatMap A.toStreamD (toStreamD m)
139-- concat m = fromStreamD $ D.concatMap A.toStreamD (toStreamD m)
133−concat m = fromStreamD $ D.unfoldMany A.reader (toStreamD m)
140+concat = D.unfoldMany A.reader
134
141
135-- | Convert a stream of arrays into a stream of their elements reversing the
142-- | Convert a stream of arrays into a stream of their elements reversing the
136-- contents of each array before flattening.
143-- contents of each array before flattening.
@@ -141,7 +148,7 @@ concat m = fromStreamD $ D.unfoldMany A.reader (toStreamD m)
141{-# INLINE concatRev #-}
148{-# INLINE concatRev #-}
142concatRev :: (Monad m, Unbox a) => Stream m (Array a) -> Stream m a
149concatRev :: (Monad m, Unbox a) => Stream m (Array a) -> Stream m a
143-- concatRev m = fromStreamD $ A.flattenArraysRev (toStreamD m)
150-- concatRev m = fromStreamD $ A.flattenArraysRev (toStreamD m)
144−concatRev m = fromStreamD $ D.unfoldMany A.readerRev (toStreamD m)
151+concatRev = D.unfoldMany A.readerRev
145
152
146-------------------------------------------------------------------------------
153-------------------------------------------------------------------------------
147-- Intersperse and append
154-- Intersperse and append
@@ -153,12 +160,12 @@ concatRev m = fromStreamD $ D.unfoldMany A.readerRev (toStreamD m)
153-- /Pre-release/
160-- /Pre-release/
154{-# INLINE interpose #-}
161{-# INLINE interpose #-}
155interpose :: (Monad m, Unbox a) => a -> Stream m (Array a) -> Stream m a
162interpose :: (Monad m, Unbox a) => a -> Stream m (Array a) -> Stream m a
156−interpose x = S.interpose x A.reader
163+interpose x = D.interpose x A.reader
157
164
158{-# INLINE intercalateSuffix #-}
165{-# INLINE intercalateSuffix #-}
159intercalateSuffix :: (Monad m, Unbox a)
166intercalateSuffix :: (Monad m, Unbox a)
160 => Array a -> Stream m (Array a) -> Stream m a
167 => Array a -> Stream m (Array a) -> Stream m a
161−intercalateSuffix = S.intercalateSuffix A.reader
168+intercalateSuffix = D.intercalateSuffix A.reader
162
169
163-- | Flatten a stream of arrays appending the given element after each
170-- | Flatten a stream of arrays appending the given element after each
164-- array.
171-- array.
@@ -168,12 +175,13 @@ intercalateSuffix = S.intercalateSuffix A.reader
168interposeSuffix :: (Monad m, Unbox a)
175interposeSuffix :: (Monad m, Unbox a)
169 => a -> Stream m (Array a) -> Stream m a
176 => a -> Stream m (Array a) -> Stream m a
170-- interposeSuffix x = fromStreamD . A.unlines x . toStreamD
177-- interposeSuffix x = fromStreamD . A.unlines x . toStreamD
171−interposeSuffix x = S.interposeSuffix x A.reader
178+interposeSuffix x = D.interposeSuffix x A.reader
172
179
173data FlattenState s =
180data FlattenState s =
174 OuterLoop s
181 OuterLoop s
175 | InnerLoop s !MA.MutableByteArray !Int !Int
182 | InnerLoop s !MA.MutableByteArray !Int !Int
176
183
184+-- XXX This is a special case of interposeSuffix, can be removed.
177-- XXX Remove monadIO constraint
185-- XXX Remove monadIO constraint
178{-# INLINE_NORMAL unlines #-}
186{-# INLINE_NORMAL unlines #-}
179unlines :: forall m a. (MonadIO m, Unbox a)
187unlines :: forall m a. (MonadIO m, Unbox a)
@@ -203,6 +211,11 @@ unlines sep (D.Stream step state) = D.Stream step' (OuterLoop state)
203-- XXX These would not be needed once we implement compactLEFold, see
211-- XXX These would not be needed once we implement compactLEFold, see
204-- module Streamly.Internal.Data.Array.Mut.Stream
212-- module Streamly.Internal.Data.Array.Mut.Stream
205--
213--
214+-- XXX Note that this thaws immutable arrays for appending, that may be
215+-- problematic if multiple users do the same thing, however, immutable arrays
216+-- would usually have no capacity to append, therefore, a copy will be forced
217+-- anyway. Confirm this. We can forcefully trim the array capacity before thaw
218+-- to ensure this.
206{-# INLINE_NORMAL packArraysChunksOf #-}
219{-# INLINE_NORMAL packArraysChunksOf #-}
207packArraysChunksOf :: (MonadIO m, Unbox a)
220packArraysChunksOf :: (MonadIO m, Unbox a)
208 => Int -> D.Stream m (Array a) -> D.Stream m (Array a)
221 => Int -> D.Stream m (Array a) -> D.Stream m (Array a)
@@ -211,6 +224,8 @@ packArraysChunksOf n str =
211
224
212-- XXX instead of writing two different versions of this operation, we should
225-- XXX instead of writing two different versions of this operation, we should
213-- write it as a pipe.
226-- write it as a pipe.
227+--
228+-- XXX Confirm that immutable arrays won't be modified.
214{-# INLINE_NORMAL lpackArraysChunksOf #-}
229{-# INLINE_NORMAL lpackArraysChunksOf #-}
215lpackArraysChunksOf :: (MonadIO m, Unbox a)
230lpackArraysChunksOf :: (MonadIO m, Unbox a)
216 => Int -> Fold m (Array a) () -> Fold m (Array a) ()
231 => Int -> Fold m (Array a) () -> Fold m (Array a) ()
@@ -224,7 +239,7 @@ lpackArraysChunksOf n fld =
224{-# INLINE compact #-}
239{-# INLINE compact #-}
225compact :: (MonadIO m, Unbox a)
240compact :: (MonadIO m, Unbox a)
226 => Int -> Stream m (Array a) -> Stream m (Array a)
241 => Int -> Stream m (Array a) -> Stream m (Array a)
227−compact n xs = fromStreamD $ packArraysChunksOf n (toStreamD xs)
242+compact = packArraysChunksOf
228
243
229-------------------------------------------------------------------------------
244-------------------------------------------------------------------------------
230-- Split
245-- Split
@@ -298,8 +313,7 @@ splitOn
298 => Word8
313 => Word8
299 -> Stream m (Array Word8)
314 -> Stream m (Array Word8)
300 -> Stream m (Array Word8)
315 -> Stream m (Array Word8)
301−splitOn byte s =
302− fromStreamD $ D.splitInnerBy (A.breakOn byte) A.splice $ toStreamD s
316+splitOn byte = D.splitInnerBy (A.breakOn byte) A.splice
303
317
304{-# INLINE splitOnSuffix #-}
318{-# INLINE splitOnSuffix #-}
305splitOnSuffix
319splitOnSuffix
@@ -308,8 +322,7 @@ splitOnSuffix
308 -> Stream m (Array Word8)
322 -> Stream m (Array Word8)
309 -> Stream m (Array Word8)
323 -> Stream m (Array Word8)
310-- splitOn byte s = fromStreamD $ A.splitOn byte $ toStreamD s
324-- splitOn byte s = fromStreamD $ A.splitOn byte $ toStreamD s
311−splitOnSuffix byte s =
312− fromStreamD $ D.splitInnerBySuffix (A.breakOn byte) A.splice $ toStreamD s
325+splitOnSuffix byte = D.splitInnerBySuffix (A.breakOn byte) A.splice
313
326
314-------------------------------------------------------------------------------
327-------------------------------------------------------------------------------
315-- Elimination - Running folds
328-- Elimination - Running folds
@@ -395,13 +408,10 @@ foldBreakK (FL.Fold fstep initial extract) stream = do
395foldBreak ::
408foldBreak ::
396 (MonadIO m, Unbox a)
409 (MonadIO m, Unbox a)
397 => Fold m a b
410 => Fold m a b
398− -> Stream m (A.Array a)
411+ -> StreamK m (A.Array a)
399− -> m (b, Stream m (A.Array a))
412+ -> m (b, StreamK m (A.Array a))
400-- foldBreak f s = fmap fromStreamD <$> foldBreakD f (toStreamD s)
413-- foldBreak f s = fmap fromStreamD <$> foldBreakD f (toStreamD s)
401−foldBreak f =
402− fmap (fmap fromStreamK)
403− . foldBreakK f
414+foldBreak = foldBreakK
404− . toStreamK
405-- If foldBreak performs better than runArrayFoldBreak we can use a rewrite
415-- If foldBreak performs better than runArrayFoldBreak we can use a rewrite
406-- rule to rewrite runArrayFoldBreak to fold.
416-- rule to rewrite runArrayFoldBreak to fold.
407-- foldBreak f = runArrayFoldBreak (ChunkFold.fromFold f)
417-- foldBreak f = runArrayFoldBreak (ChunkFold.fromFold f)
@@ -457,10 +467,6 @@ splitAtArrayListRev n ls
457-- Fold to a single Array
467-- Fold to a single Array
458-------------------------------------------------------------------------------
468-------------------------------------------------------------------------------
459
469
460−{-# INLINE foldlM' #-}
461−foldlM' :: Monad m => (b -> a -> m b) -> m b -> Stream m a -> m b
462−foldlM' step begin = D.foldlM' step begin . S.toStreamD
463−
464-- XXX Both of these implementations of splicing seem to perform equally well.
470-- XXX Both of these implementations of splicing seem to perform equally well.
465-- We need to perform benchmarks over a range of sizes though.
471-- We need to perform benchmarks over a range of sizes though.
466
472
@@ -471,16 +477,16 @@ spliceArraysLenUnsafe :: (MonadIO m, Unbox a)
471 => Int -> Stream m (MA.Array a) -> m (MA.Array a)
477 => Int -> Stream m (MA.Array a) -> m (MA.Array a)
472spliceArraysLenUnsafe len buffered = do
478spliceArraysLenUnsafe len buffered = do
473 arr <- liftIO $ MA.newPinned len
479 arr <- liftIO $ MA.newPinned len
474− foldlM' MA.spliceUnsafe (return arr) buffered
480+ D.foldlM' MA.spliceUnsafe (return arr) buffered
475
481
476{-# INLINE _spliceArrays #-}
482{-# INLINE _spliceArrays #-}
477_spliceArrays :: (MonadIO m, Unbox a)
483_spliceArrays :: (MonadIO m, Unbox a)
478 => Stream m (Array a) -> m (Array a)
484 => Stream m (Array a) -> m (Array a)
479_spliceArrays s = do
485_spliceArrays s = do
480− buffered <- S.foldr S.cons S.nil s
486+ buffered <- D.foldr K.cons K.nil s
481− len <- S.fold FL.sum (fmap Array.length buffered)
487+ len <- K.fold FL.sum (fmap Array.length buffered)
482 arr <- liftIO $ MA.newPinned len
488 arr <- liftIO $ MA.newPinned len
483− final <- foldlM' writeArr (return arr) s
489+ final <- D.foldlM' writeArr (return arr) (toStream buffered)
484 return $ A.unsafeFreeze final
490 return $ A.unsafeFreeze final
485
491
486 where
492 where
@@ -491,9 +497,10 @@ _spliceArrays s = do
491_spliceArraysBuffered :: (MonadIO m, Unbox a)
497_spliceArraysBuffered :: (MonadIO m, Unbox a)
492 => Stream m (Array a) -> m (Array a)
498 => Stream m (Array a) -> m (Array a)
493_spliceArraysBuffered s = do
499_spliceArraysBuffered s = do
494− buffered <- S.foldr S.cons S.nil s
500+ buffered <- D.foldr K.cons K.nil s
495− len <- S.fold FL.sum (fmap Array.length buffered)
501+ len <- K.fold FL.sum (fmap Array.length buffered)
502+ A.unsafeFreeze <$>
496− A.unsafeFreeze <$> spliceArraysLenUnsafe len (fmap A.unsafeThaw s)
503+ spliceArraysLenUnsafe len (fmap A.unsafeThaw (toStream buffered))
497
504
498{-# INLINE spliceArraysRealloced #-}
505{-# INLINE spliceArraysRealloced #-}
499spliceArraysRealloced :: forall m a. (MonadIO m, Unbox a)
506spliceArraysRealloced :: forall m a. (MonadIO m, Unbox a)
@@ -502,7 +509,7 @@ spliceArraysRealloced s = do
502 let n = allocBytesToElemCount (undefined :: a) (4 * 1024)
509 let n = allocBytesToElemCount (undefined :: a) (4 * 1024)
503 idst = liftIO $ MA.newPinned n
510 idst = liftIO $ MA.newPinned n
504
511
505− arr <- foldlM' MA.spliceExp idst (fmap A.unsafeThaw s)
512+ arr <- D.foldlM' MA.spliceExp idst (fmap A.unsafeThaw s)
506 liftIO $ A.unsafeFreeze <$> MA.rightSize arr
513 liftIO $ A.unsafeFreeze <$> MA.rightSize arr
507
514
508-- XXX This should just be "fold A.write"
515-- XXX This should just be "fold A.write"
@@ -776,16 +783,13 @@ parseBreakK (PRD.Parser pstep initial extract) stream = do
776parseBreak ::
783parseBreak ::
777 (MonadIO m, Unbox a)
784 (MonadIO m, Unbox a)
778 => PR.Parser a m b
785 => PR.Parser a m b
779− -> Stream m (A.Array a)
786+ -> StreamK m (A.Array a)
780− -> m (Either ParseError b, Stream m (A.Array a))
787+ -> m (Either ParseError b, StreamK m (A.Array a))
781{-
788{-
782parseBreak p s =
789parseBreak p s =
783 fmap fromStreamD <$> parseBreakD (PRD.fromParserK p) (toStreamD s)
790 fmap fromStreamD <$> parseBreakD (PRD.fromParserK p) (toStreamD s)
784-}
791-}
785−parseBreak p =
786− fmap (fmap fromStreamK)
787− . parseBreakK (PRD.fromParserK p)
792+parseBreak p = parseBreakK (PRD.fromParserK p)
788− . toStreamK
789
793
790-------------------------------------------------------------------------------
794-------------------------------------------------------------------------------
791-- Elimination - Running Array Folds and parsers
795-- Elimination - Running Array Folds and parsers
@@ -947,8 +951,8 @@ parseArr p s = fmap fromStreamD <$> parseBreakD p (toStreamD s)
947--
951--
948{-# INLINE runArrayFold #-}
952{-# INLINE runArrayFold #-}
949runArrayFold :: (MonadIO m, Unbox a) =>
953runArrayFold :: (MonadIO m, Unbox a) =>
950− ChunkFold m a b -> Stream m (A.Array a) -> m (Either ParseError b)
954+ ChunkFold m a b -> StreamK m (A.Array a) -> m (Either ParseError b)
951−runArrayFold (ChunkFold p) s = fst <$> runArrayParserDBreak p (toStreamD s)
955+runArrayFold (ChunkFold p) s = fst <$> runArrayParserDBreak p (toStream s)
952
956
953-- | Like 'fold' but also returns the remaining stream.
957-- | Like 'fold' but also returns the remaining stream.
954--
958--
@@ -956,9 +960,9 @@ runArrayFold (ChunkFold p) s = fst <$> runArrayParserDBreak p (toStreamD s)
956--
960--
957{-# INLINE runArrayFoldBreak #-}
961{-# INLINE runArrayFoldBreak #-}
958runArrayFoldBreak :: (MonadIO m, Unbox a) =>
962runArrayFoldBreak :: (MonadIO m, Unbox a) =>
959− ChunkFold m a b -> Stream m (A.Array a) -> m (Either ParseError b, Stream m (A.Array a))
963+ ChunkFold m a b -> StreamK m (A.Array a) -> m (Either ParseError b, StreamK m (A.Array a))
960runArrayFoldBreak (ChunkFold p) s =
964runArrayFoldBreak (ChunkFold p) s =
961− second fromStreamD <$> runArrayParserDBreak p (toStreamD s)
965+ second fromStream <$> runArrayParserDBreak p (toStream s)
962
966
963{-# ANN type ParseChunksState Fuse #-}
967{-# ANN type ParseChunksState Fuse #-}
964data ParseChunksState x inpBuf st pst =
968data ParseChunksState x inpBuf st pst =
@@ -1205,6 +1209,6 @@ runArrayFoldManyD
1205runArrayFoldMany
1209runArrayFoldMany
1206 :: (Monad m, Unbox a)
1210 :: (Monad m, Unbox a)
1207 => ChunkFold m a b
1211 => ChunkFold m a b
1208− -> Stream m (Array a)
1212+ -> StreamK m (Array a)
1209− -> Stream m (Either ParseError b)
1213+ -> StreamK m (Either ParseError b)
1210−runArrayFoldMany p m = fromStreamD $ runArrayFoldManyD p (toStreamD m)
1214+runArrayFoldMany p m = fromStream $ runArrayFoldManyD p (toStream m)
core/src/Streamly/Internal/Data/Stream/Cross.hs+1−1
@@ -121,7 +121,7 @@ instance Monad m => Monad (CrossStream m) where
121 CrossStream
121 CrossStream
122 (Stream.fromStreamK
122 (Stream.fromStreamK
123 $ K.bindWith
123 $ K.bindWith
124− K.serial
124+ K.append
125 (Stream.toStreamK m)
125 (Stream.toStreamK m)
126 (Stream.toStreamK . unCrossStream . f))
126 (Stream.toStreamK . unCrossStream . f))
127
127
core/src/Streamly/Internal/Data/Stream/Eliminate.hs+3−3
@@ -217,7 +217,7 @@ foldlS f z =
217--
217--
218{-# INLINE_NORMAL parseD #-}
218{-# INLINE_NORMAL parseD #-}
219parseD :: Monad m => PRD.Parser a m b -> Stream m a -> m (Either ParseError b)
219parseD :: Monad m => PRD.Parser a m b -> Stream m a -> m (Either ParseError b)
220−parseD p = D.parse p . toStreamD
220+parseD p = D.parseD p . toStreamD
221
221
222-- XXX Drive directly as parserK rather than converting to parserD first.
222-- XXX Drive directly as parserK rather than converting to parserD first.
223
223
@@ -248,7 +248,7 @@ parse = parseD . PRD.fromParserK
248parseBreakD :: Monad m =>
248parseBreakD :: Monad m =>
249 PRD.Parser a m b -> Stream m a -> m (Either ParseError b, Stream m a)
249 PRD.Parser a m b -> Stream m a -> m (Either ParseError b, Stream m a)
250parseBreakD parser strm = do
250parseBreakD parser strm = do
251− (b, strmD) <- D.parseBreak parser (toStreamD strm)
251+ (b, strmD) <- D.parseBreakD parser (toStreamD strm)
252 return $! (b, fromStreamD strmD)
252 return $! (b, fromStreamD strmD)
253
253
254-- | Parse a stream using the supplied 'Parser'.
254-- | Parse a stream using the supplied 'Parser'.
@@ -257,7 +257,7 @@ parseBreakD parser strm = do
257--
257--
258{-# INLINE parseBreak #-}
258{-# INLINE parseBreak #-}
259parseBreak :: Monad m => Parser a m b -> Stream m a -> m (Either ParseError b, Stream m a)
259parseBreak :: Monad m => Parser a m b -> Stream m a -> m (Either ParseError b, Stream m a)
260−parseBreak p strm = fmap f $ K.parseBreak (PRD.fromParserK p) (toStreamK strm)
260+parseBreak p strm = fmap f $ K.parseBreak p (toStreamK strm)
261
261
262 where
262 where
263
263
core/src/Streamly/Internal/Data/Stream/Exception.hs+6−6
@@ -63,7 +63,7 @@ before action xs = fromStreamD $ D.before action $ toStreamD xs
63--
63--
64{-# INLINE afterUnsafe #-}
64{-# INLINE afterUnsafe #-}
65afterUnsafe :: Monad m => m b -> Stream m a -> Stream m a
65afterUnsafe :: Monad m => m b -> Stream m a -> Stream m a
66−afterUnsafe action xs = fromStreamD $ D.after_ action $ toStreamD xs
66+afterUnsafe action xs = fromStreamD $ D.afterUnsafe action $ toStreamD xs
67
67
68-- | Run the action @IO b@ whenever the stream is evaluated to completion, or
68-- | Run the action @IO b@ whenever the stream is evaluated to completion, or
69-- if it is garbage collected after a partial lazy evaluation.
69-- if it is garbage collected after a partial lazy evaluation.
@@ -75,7 +75,7 @@ afterUnsafe action xs = fromStreamD $ D.after_ action $ toStreamD xs
75--
75--
76{-# INLINE afterIO #-}
76{-# INLINE afterIO #-}
77afterIO :: MonadIO m => IO b -> Stream m a -> Stream m a
77afterIO :: MonadIO m => IO b -> Stream m a -> Stream m a
78−afterIO action xs = fromStreamD $ D.after action $ toStreamD xs
78+afterIO action xs = fromStreamD $ D.afterIO action $ toStreamD xs
79
79
80-- | Run the action @m b@ if the stream evaluation is aborted due to an
80-- | Run the action @m b@ if the stream evaluation is aborted due to an
81-- exception. The exception is not caught, simply rethrown.
81-- exception. The exception is not caught, simply rethrown.
@@ -98,7 +98,7 @@ onException action xs = fromStreamD $ D.onException action $ toStreamD xs
98--
98--
99{-# INLINE finallyUnsafe #-}
99{-# INLINE finallyUnsafe #-}
100finallyUnsafe :: MonadCatch m => m b -> Stream m a -> Stream m a
100finallyUnsafe :: MonadCatch m => m b -> Stream m a -> Stream m a
101−finallyUnsafe action xs = fromStreamD $ D.finally_ action $ toStreamD xs
101+finallyUnsafe action xs = fromStreamD $ D.finallyUnsafe action $ toStreamD xs
102
102
103-- | Run the action @IO b@ whenever the stream stream stops normally, aborts
103-- | Run the action @IO b@ whenever the stream stream stops normally, aborts
104-- due to an exception or if it is garbage collected after a partial lazy
104-- due to an exception or if it is garbage collected after a partial lazy
@@ -116,7 +116,7 @@ finallyUnsafe action xs = fromStreamD $ D.finally_ action $ toStreamD xs
116{-# INLINE finallyIO #-}
116{-# INLINE finallyIO #-}
117finallyIO :: (MonadIO m, MonadCatch m) =>
117finallyIO :: (MonadIO m, MonadCatch m) =>
118 IO b -> Stream m a -> Stream m a
118 IO b -> Stream m a -> Stream m a
119−finallyIO action xs = fromStreamD $ D.finally action $ toStreamD xs
119+finallyIO action xs = fromStreamD $ D.finallyIO action $ toStreamD xs
120
120
121-- | Like 'bracket' but with following differences:
121-- | Like 'bracket' but with following differences:
122--
122--
@@ -132,7 +132,7 @@ finallyIO action xs = fromStreamD $ D.finally action $ toStreamD xs
132{-# INLINE bracketUnsafe #-}
132{-# INLINE bracketUnsafe #-}
133bracketUnsafe :: MonadCatch m
133bracketUnsafe :: MonadCatch m
134 => m b -> (b -> m c) -> (b -> Stream m a) -> Stream m a
134 => m b -> (b -> m c) -> (b -> Stream m a) -> Stream m a
135−bracketUnsafe bef aft bet = fromStreamD $ D.bracket_ bef aft (toStreamD . bet)
135+bracketUnsafe bef aft bet = fromStreamD $ D.bracketUnsafe bef aft (toStreamD . bet)
136
136
137-- | Run the alloc action @IO b@ with async exceptions disabled but keeping
137-- | Run the alloc action @IO b@ with async exceptions disabled but keeping
138-- blocking operations interruptible (see 'Control.Exception.mask'). Use the
138-- blocking operations interruptible (see 'Control.Exception.mask'). Use the
@@ -188,7 +188,7 @@ bracketIO3 :: (MonadIO m, MonadCatch m)
188 -> (b -> Stream m a)
188 -> (b -> Stream m a)
189 -> Stream m a
189 -> Stream m a
190bracketIO3 bef aft gc exc bet = fromStreamD $
190bracketIO3 bef aft gc exc bet = fromStreamD $
191− D.bracket' bef aft exc gc (toStreamD . bet)
191+ D.bracketIO3 bef aft exc gc (toStreamD . bet)
192
192
193-- | Like 'handle' but the exception handler is also provided with the stream
193-- | Like 'handle' but the exception handler is also provided with the stream
194-- that generated the exception as input. The exception handler can thus
194-- that generated the exception as input. The exception handler can thus
core/src/Streamly/Internal/Data/Stream/Expand.hs+9−9
@@ -281,7 +281,7 @@ interleaveMin2 s1 s2 =
281{-# INLINE interleaveFstSuffix2 #-}
281{-# INLINE interleaveFstSuffix2 #-}
282interleaveFstSuffix2 :: Monad m => Stream m b -> Stream m b -> Stream m b
282interleaveFstSuffix2 :: Monad m => Stream m b -> Stream m b -> Stream m b
283interleaveFstSuffix2 m1 m2 =
283interleaveFstSuffix2 m1 m2 =
284− fromStreamD $ D.interleaveSuffix (toStreamD m1) (toStreamD m2)
284+ fromStreamD $ D.interleaveFstSuffix (toStreamD m1) (toStreamD m2)
285
285
286-- | Interleaves the outputs of two streams, yielding elements from each stream
286-- | Interleaves the outputs of two streams, yielding elements from each stream
287-- alternately, starting from the first stream and ending at the first stream.
287-- alternately, starting from the first stream and ending at the first stream.
@@ -305,7 +305,7 @@ interleaveFstSuffix2 m1 m2 =
305{-# INLINE interleaveFst2 #-}
305{-# INLINE interleaveFst2 #-}
306interleaveFst2 :: Monad m => Stream m b -> Stream m b -> Stream m b
306interleaveFst2 :: Monad m => Stream m b -> Stream m b -> Stream m b
307interleaveFst2 m1 m2 =
307interleaveFst2 m1 m2 =
308− fromStreamD $ D.interleaveInfix (toStreamD m1) (toStreamD m2)
308+ fromStreamD $ D.interleaveFst (toStreamD m1) (toStreamD m2)
309
309
310------------------------------------------------------------------------------
310------------------------------------------------------------------------------
311-- Scheduling
311-- Scheduling
@@ -449,7 +449,7 @@ unfoldMany u m = fromStreamD $ D.unfoldMany u (toStreamD m)
449{-# INLINE unfoldInterleave #-}
449{-# INLINE unfoldInterleave #-}
450unfoldInterleave ::Monad m => Unfold m a b -> Stream m a -> Stream m b
450unfoldInterleave ::Monad m => Unfold m a b -> Stream m a -> Stream m b
451unfoldInterleave u m =
451unfoldInterleave u m =
452− fromStreamD $ D.unfoldManyInterleave u (toStreamD m)
452+ fromStreamD $ D.unfoldInterleave u (toStreamD m)
453
453
454-- | 'unfoldInterleave' switches to the next stream whenever a value from a
454-- | 'unfoldInterleave' switches to the next stream whenever a value from a
455-- stream is yielded, it does not switch on a 'Skip'. So if a stream keeps
455-- stream is yielded, it does not switch on a 'Skip'. So if a stream keeps
@@ -460,7 +460,7 @@ unfoldInterleave u m =
460{-# INLINE unfoldRoundRobin #-}
460{-# INLINE unfoldRoundRobin #-}
461unfoldRoundRobin ::Monad m => Unfold m a b -> Stream m a -> Stream m b
461unfoldRoundRobin ::Monad m => Unfold m a b -> Stream m a -> Stream m b
462unfoldRoundRobin u m =
462unfoldRoundRobin u m =
463− fromStreamD $ D.unfoldManyRoundRobin u (toStreamD m)
463+ fromStreamD $ D.unfoldRoundRobin u (toStreamD m)
464
464
465------------------------------------------------------------------------------
465------------------------------------------------------------------------------
466-- Combine N Streams - interpose
466-- Combine N Streams - interpose
@@ -478,7 +478,7 @@ unfoldRoundRobin u m =
478interpose :: Monad m
478interpose :: Monad m
479 => c -> Unfold m b c -> Stream m b -> Stream m c
479 => c -> Unfold m b c -> Stream m b -> Stream m c
480interpose x unf str =
480interpose x unf str =
481− fromStreamD $ D.interpose (return x) unf (toStreamD str)
481+ fromStreamD $ D.interpose x unf (toStreamD str)
482
482
483-- interposeSuffix x unf str = gintercalateSuffix unf str UF.identity (repeat x)
483-- interposeSuffix x unf str = gintercalateSuffix unf str UF.identity (repeat x)
484
484
@@ -492,7 +492,7 @@ interpose x unf str =
492interposeSuffix :: Monad m
492interposeSuffix :: Monad m
493 => c -> Unfold m b c -> Stream m b -> Stream m c
493 => c -> Unfold m b c -> Stream m b -> Stream m c
494interposeSuffix x unf str =
494interposeSuffix x unf str =
495− fromStreamD $ D.interposeSuffix (return x) unf (toStreamD str)
495+ fromStreamD $ D.interposeSuffix x unf (toStreamD str)
496
496
497------------------------------------------------------------------------------
497------------------------------------------------------------------------------
498-- Combine N Streams - intercalate
498-- Combine N Streams - intercalate
@@ -563,8 +563,8 @@ gintercalateSuffix unf1 str1 unf2 str2 =
563{-# INLINE intercalateSuffix #-}
563{-# INLINE intercalateSuffix #-}
564intercalateSuffix :: Monad m
564intercalateSuffix :: Monad m
565 => Unfold m b c -> b -> Stream m b -> Stream m c
565 => Unfold m b c -> b -> Stream m b -> Stream m c
566−intercalateSuffix unf seed str = fromStreamD $ D.unfoldMany unf
566+intercalateSuffix unf seed =
567− $ D.intersperseMSuffix (return seed) (toStreamD str)
567+ fromStreamD . D.intercalateSuffix unf seed . toStreamD
568
568
569------------------------------------------------------------------------------
569------------------------------------------------------------------------------
570-- Combine N Streams - concatMap
570-- Combine N Streams - concatMap
@@ -633,7 +633,7 @@ mergeMapWith ::
633 -> Stream m b
633 -> Stream m b
634mergeMapWith par f m =
634mergeMapWith par f m =
635 fromStreamK
635 fromStreamK
636− $ K.concatPairsWith
636+ $ K.mergeMapWith
637 (\s1 s2 -> toStreamK $ fromStreamK s1 `par` fromStreamK s2)
637 (\s1 s2 -> toStreamK $ fromStreamK s1 `par` fromStreamK s2)
638 (toStreamK . f)
638 (toStreamK . f)
639 (toStreamK m)
639 (toStreamK m)
core/src/Streamly/Internal/Data/Stream/Reduce.hs+3−3
@@ -355,7 +355,7 @@ parseMany
355 -> Stream m a
355 -> Stream m a
356 -> Stream m (Either ParseError b)
356 -> Stream m (Either ParseError b)
357parseMany p m =
357parseMany p m =
358− fromStreamD $ D.parseMany (ParserD.fromParserK p) (toStreamD m)
358+ fromStreamD $ D.parseManyD (ParserD.fromParserK p) (toStreamD m)
359
359
360-- | Same as parseMany but for StreamD streams.
360-- | Same as parseMany but for StreamD streams.
361--
361--
@@ -368,7 +368,7 @@ parseManyD
368 -> Stream m a
368 -> Stream m a
369 -> Stream m (Either ParseError b)
369 -> Stream m (Either ParseError b)
370parseManyD p m =
370parseManyD p m =
371− fromStreamD $ D.parseMany p (toStreamD m)
371+ fromStreamD $ D.parseManyD p (toStreamD m)
372
372
373-- | Apply a stream of parsers to an input stream and emit the results in the
373-- | Apply a stream of parsers to an input stream and emit the results in the
374-- output stream.
374-- output stream.
@@ -424,7 +424,7 @@ parseIterate
424 -> Stream m a
424 -> Stream m a
425 -> Stream m (Either ParseError b)
425 -> Stream m (Either ParseError b)
426parseIterate f i m = fromStreamD $
426parseIterate f i m = fromStreamD $
427− D.parseIterate (ParserD.fromParserK . f) i (toStreamD m)
427+ D.parseIterateD (ParserD.fromParserK . f) i (toStreamD m)
428
428
429------------------------------------------------------------------------------
429------------------------------------------------------------------------------
430-- Chunking
430-- Chunking
core/src/Streamly/Internal/Data/Stream/StreamD.hs+4
@@ -25,6 +25,8 @@ module Streamly.Internal.Data.Stream.StreamD
25 , module Streamly.Internal.Data.Stream.StreamD.Transformer
25 , module Streamly.Internal.Data.Stream.StreamD.Transformer
26 , module Streamly.Internal.Data.Stream.StreamD.Nesting
26 , module Streamly.Internal.Data.Stream.StreamD.Nesting
27 , module Streamly.Internal.Data.Stream.StreamD.Transform
27 , module Streamly.Internal.Data.Stream.StreamD.Transform
28+ , module Streamly.Internal.Data.Stream.StreamD.Top
29+ , module Streamly.Internal.Data.Stream.StreamD.Container
28 )
30 )
29where
31where
30
32
@@ -36,3 +38,5 @@ import Streamly.Internal.Data.Stream.StreamD.Lift
36import Streamly.Internal.Data.Stream.StreamD.Transformer
38import Streamly.Internal.Data.Stream.StreamD.Transformer
37import Streamly.Internal.Data.Stream.StreamD.Nesting
39import Streamly.Internal.Data.Stream.StreamD.Nesting
38import Streamly.Internal.Data.Stream.StreamD.Transform
40import Streamly.Internal.Data.Stream.StreamD.Transform
41+import Streamly.Internal.Data.Stream.StreamD.Top
42+import Streamly.Internal.Data.Stream.StreamD.Container
core/src/Streamly/Internal/Data/Stream/Container.hs → core/src/Streamly/Internal/Data/Stream/StreamD/Container.hsrenamed+29−28
@@ -1,5 +1,5 @@
1-- |
1-- |
2−-- Module : Streamly.Internal.Data.Stream.Container
2+-- Module : Streamly.Internal.Data.Stream.StreamD.Container
3-- Copyright : (c) 2019 Composewell Technologies
3-- Copyright : (c) 2019 Composewell Technologies
4-- License : BSD-3-Clause
4-- License : BSD-3-Clause
5-- Maintainer : streamly@composewell.com
5-- Maintainer : streamly@composewell.com
@@ -8,9 +8,7 @@
8--
8--
9-- Stream operations that require transformers or containers like Set or Map.
9-- Stream operations that require transformers or containers like Set or Map.
10
10
11−-- Rename this to Stream.Container?
12−
13−module Streamly.Internal.Data.Stream.Container
11+module Streamly.Internal.Data.Stream.StreamD.Container
14 (
12 (
15 nub
13 nub
16
14
@@ -32,20 +30,19 @@ import Control.Monad.Trans.State.Strict (get, put)
32import Data.Function ((&))
30import Data.Function ((&))
33import Data.Maybe (isJust)
31import Data.Maybe (isJust)
34import Streamly.Internal.Data.Stream.StreamD.Step (Step(..))
32import Streamly.Internal.Data.Stream.StreamD.Step (Step(..))
35−import Streamly.Internal.Data.Stream.Type (Stream)
33+import Streamly.Internal.Data.Stream.StreamD.Type
36−import Streamly.Internal.Data.Stream.Cross (CrossStream(..))
34+ (Stream(..), mkCross, unCross)
37
35
38import qualified Data.Map.Strict as Map
36import qualified Data.Map.Strict as Map
39import qualified Data.Set as Set
37import qualified Data.Set as Set
40import qualified Streamly.Data.Fold as Fold
38import qualified Streamly.Data.Fold as Fold
41import qualified Streamly.Internal.Data.Array.Generic as Array
39import qualified Streamly.Internal.Data.Array.Generic as Array
42import qualified Streamly.Internal.Data.Array.Mut.Type as MA
40import qualified Streamly.Internal.Data.Array.Mut.Type as MA
43−import qualified Streamly.Internal.Data.Stream.Bottom as Stream
41+import qualified Streamly.Internal.Data.Stream.StreamD.Type as Stream
44−import qualified Streamly.Internal.Data.Stream.Expand as Stream
42+import qualified Streamly.Internal.Data.Stream.StreamD.Nesting as Stream
45−import qualified Streamly.Internal.Data.Stream.Generate as Stream
43+import qualified Streamly.Internal.Data.Stream.StreamD.Generate as Stream
46−import qualified Streamly.Internal.Data.Stream.Transform as Stream
44+import qualified Streamly.Internal.Data.Stream.StreamD.Transform as Stream
47−import qualified Streamly.Internal.Data.Stream.StreamD as D
45+import qualified Streamly.Internal.Data.Stream.StreamD.Transformer as Stream
48−import qualified Streamly.Internal.Data.Stream.Transformer as Stream
49
46
50-- $setup
47-- $setup
51-- >>> :m
48-- >>> :m
@@ -55,8 +52,8 @@ import qualified Streamly.Internal.Data.Stream.Transformer as Stream
55-- stream. If we want to limit the memory we can just use "take" to limit the
52-- stream. If we want to limit the memory we can just use "take" to limit the
56-- uniq elements in the stream.
53-- uniq elements in the stream.
57{-# INLINE_NORMAL nub #-}
54{-# INLINE_NORMAL nub #-}
58−nub :: (Monad m, Ord a) => D.Stream m a -> D.Stream m a
55+nub :: (Monad m, Ord a) => Stream m a -> Stream m a
59−nub (D.Stream step1 state1) = D.Stream step (Set.empty, state1)
56+nub (Stream step1 state1) = Stream step (Set.empty, state1)
60
57
61 where
58 where
62
59
@@ -115,6 +112,8 @@ joinInner s1 s2 =
115-- Ordering returning function. The time complexity would then become (m x log
112-- Ordering returning function. The time complexity would then become (m x log
116-- n).
113-- n).
117
114
115+-- XXX Check performance of StreamD vs StreamK
116+
118-- | Like 'joinInner' but emit @(a, Just b)@, and additionally, for those @a@'s
117-- | Like 'joinInner' but emit @(a, Just b)@, and additionally, for those @a@'s
119-- that are not equal to any @b@ emit @(a, Nothing)@.
118-- that are not equal to any @b@ emit @(a, Nothing)@.
120--
119--
@@ -133,25 +132,25 @@ joinInner s1 s2 =
133{-# INLINE joinLeftGeneric #-}
132{-# INLINE joinLeftGeneric #-}
134joinLeftGeneric :: Monad m =>
133joinLeftGeneric :: Monad m =>
135 (a -> b -> Bool) -> Stream m a -> Stream m b -> Stream m (a, Maybe b)
134 (a -> b -> Bool) -> Stream m a -> Stream m b -> Stream m (a, Maybe b)
136−joinLeftGeneric eq s1 s2 = Stream.evalStateT (return False) $ unCrossStream $ do
135+joinLeftGeneric eq s1 s2 = Stream.evalStateT (return False) $ unCross $ do
137− a <- CrossStream (Stream.liftInner s1)
136+ a <- mkCross (Stream.liftInner s1)
138 -- XXX should we use StreamD monad here?
137 -- XXX should we use StreamD monad here?
139 -- XXX Is there a better way to perform some action at the end of a loop
138 -- XXX Is there a better way to perform some action at the end of a loop
140 -- iteration?
139 -- iteration?
141− CrossStream (Stream.fromEffect $ put False)
140+ mkCross (Stream.fromEffect $ put False)
142 let final = Stream.concatEffect $ do
141 let final = Stream.concatEffect $ do
143 r <- get
142 r <- get
144 if r
143 if r
145 then pure Stream.nil
144 then pure Stream.nil
146 else pure (Stream.fromPure Nothing)
145 else pure (Stream.fromPure Nothing)
147− b <- CrossStream (fmap Just (Stream.liftInner s2) <> final)
146+ b <- mkCross (fmap Just (Stream.liftInner s2) `Stream.append` final)
148 case b of
147 case b of
149 Just b1 ->
148 Just b1 ->
150 if a `eq` b1
149 if a `eq` b1
151 then do
150 then do
152− CrossStream (Stream.fromEffect $ put True)
151+ mkCross (Stream.fromEffect $ put True)
153 return (a, Just b1)
152 return (a, Just b1)
154− else CrossStream Stream.nil
153+ else mkCross Stream.nil
155 Nothing -> return (a, Nothing)
154 Nothing -> return (a, Nothing)
156
155
157-- XXX rename to joinLeftOrd?
156-- XXX rename to joinLeftOrd?
@@ -180,6 +179,8 @@ joinLeft s1 s2 =
180
179
181-- XXX We can do this concurrently.
180-- XXX We can do this concurrently.
182
181
182+-- XXX Check performance of StreamD vs StreamK
183+
183-- | Like 'joinLeft' but emits a @(Just a, Just b)@. Like 'joinLeft', for those
184-- | Like 'joinLeft' but emits a @(Just a, Just b)@. Like 'joinLeft', for those
184-- @a@'s that are not equal to any @b@ emit @(Just a, Nothing)@, but
185-- @a@'s that are not equal to any @b@ emit @(Just a, Nothing)@, but
185-- additionally, for those @b@'s that are not equal to any @a@ emit @(Nothing,
186-- additionally, for those @b@'s that are not equal to any @a@ emit @(Nothing,
@@ -206,7 +207,7 @@ joinOuterGeneric eq s1 s =
206 Stream.fold
207 Stream.fold
207 (MA.writeN len)
208 (MA.writeN len)
208 (Stream.fromList (Prelude.replicate len False))
209 (Stream.fromList (Prelude.replicate len False))
209− return $ go inputArr foundArr <> leftOver inputArr foundArr
210+ return $ go inputArr foundArr `Stream.append` leftOver inputArr foundArr
210
211
211 where
212 where
212
213
@@ -222,14 +223,14 @@ joinOuterGeneric eq s1 s =
222 ) stream1 stream2
223 ) stream1 stream2
223 ) & Stream.catMaybes
224 ) & Stream.catMaybes
224
225
225− evalState = Stream.evalStateT (return False) . unCrossStream
226+ evalState = Stream.evalStateT (return False) . unCross
226
227
227 go inputArr foundArr = evalState $ do
228 go inputArr foundArr = evalState $ do
228− a <- CrossStream (Stream.liftInner s1)
229+ a <- mkCross (Stream.liftInner s1)
229 -- XXX should we use StreamD monad here?
230 -- XXX should we use StreamD monad here?
230 -- XXX Is there a better way to perform some action at the end of a loop
231 -- XXX Is there a better way to perform some action at the end of a loop
231 -- iteration?
232 -- iteration?
232− CrossStream (Stream.fromEffect $ put False)
233+ mkCross (Stream.fromEffect $ put False)
233 let final = Stream.concatEffect $ do
234 let final = Stream.concatEffect $ do
234 r <- get
235 r <- get
235 if r
236 if r
@@ -237,17 +238,17 @@ joinOuterGeneric eq s1 s =
237 else pure (Stream.fromPure Nothing)
238 else pure (Stream.fromPure Nothing)
238 (i, b) <-
239 (i, b) <-
239 let stream = Array.read inputArr
240 let stream = Array.read inputArr
240− in CrossStream
241+ in mkCross
241− (Stream.indexed $ fmap Just (Stream.liftInner stream) <> final)
242+ (Stream.indexed $ fmap Just (Stream.liftInner stream) `Stream.append` final)
242
243
243 case b of
244 case b of
244 Just b1 ->
245 Just b1 ->
245 if a `eq` b1
246 if a `eq` b1
246 then do
247 then do
247− CrossStream (Stream.fromEffect $ put True)
248+ mkCross (Stream.fromEffect $ put True)
248 MA.putIndex i foundArr True
249 MA.putIndex i foundArr True
249 return (Just a, Just b1)
250 return (Just a, Just b1)
250− else CrossStream Stream.nil
251+ else mkCross Stream.nil
251 Nothing -> return (Just a, Nothing)
252 Nothing -> return (Just a, Nothing)
252
253
253-- Put the b's that have been paired, in another hash or mutate the hash to set
254-- Put the b's that have been paired, in another hash or mutate the hash to set
core/src/Streamly/Internal/Data/Stream/StreamD/Eliminate.hs+165−12
@@ -17,7 +17,9 @@ module Streamly.Internal.Data.Stream.StreamD.Eliminate
17
17
18 -- -- * Running a 'Parser'
18 -- -- * Running a 'Parser'
19 , parse
19 , parse
20+ , parseD
20 , parseBreak
21 , parseBreak
22+ , parseBreakD
21
23
22 -- * Stream Deconstruction
24 -- * Stream Deconstruction
23 , uncons
25 , uncons
@@ -69,33 +71,50 @@ module Streamly.Internal.Data.Stream.StreamD.Eliminate
69 -- ** Substreams
71 -- ** Substreams
70 -- | These should probably be expressed using parsers.
72 -- | These should probably be expressed using parsers.
71 , isPrefixOf
73 , isPrefixOf
74+ , isInfixOf
75+ , isSuffixOf
76+ , isSuffixOfUnbox
72 , isSubsequenceOf
77 , isSubsequenceOf
73 , stripPrefix
78 , stripPrefix
79+ , stripSuffix
80+ , stripSuffixUnbox
74 )
81 )
75where
82where
76
83
77#include "inline.hs"
84#include "inline.hs"
78
85
79import Control.Exception (assert)
86import Control.Exception (assert)
87+import Control.Monad.IO.Class (MonadIO(..))
88+import Foreign.Storable (Storable)
80import GHC.Exts (SpecConstrAnnotation(..))
89import GHC.Exts (SpecConstrAnnotation(..))
81import GHC.Types (SPEC(..))
90import GHC.Types (SPEC(..))
82import Streamly.Internal.Data.Parser (ParseError(..))
91import Streamly.Internal.Data.Parser (ParseError(..))
83import Streamly.Internal.Data.SVar.Type (defState)
92import Streamly.Internal.Data.SVar.Type (defState)
93+import Streamly.Internal.Data.Unboxed (Unbox)
84
94
85import Streamly.Internal.Data.Maybe.Strict (Maybe'(..))
95import Streamly.Internal.Data.Maybe.Strict (Maybe'(..))
86−#ifdef USE_FOLDS_EVERYWHERE
96+
97+import qualified Streamly.Internal.Data.Array.Type as Array
87import qualified Streamly.Internal.Data.Fold as Fold
98import qualified Streamly.Internal.Data.Fold as Fold
88−#endif
89import qualified Streamly.Internal.Data.Parser as PR
99import qualified Streamly.Internal.Data.Parser as PR
90import qualified Streamly.Internal.Data.Parser.ParserD as PRD
100import qualified Streamly.Internal.Data.Parser.ParserD as PRD
91import qualified Streamly.Internal.Data.Stream.StreamD.Generate as StreamD
101import qualified Streamly.Internal.Data.Stream.StreamD.Generate as StreamD
92import qualified Streamly.Internal.Data.Stream.StreamD.Nesting as Nesting
102import qualified Streamly.Internal.Data.Stream.StreamD.Nesting as Nesting
103+import qualified Streamly.Internal.Data.Stream.StreamD.Transform as StreamD
93
104
94import Prelude hiding
105import Prelude hiding
95 ( all, any, elem, foldr, foldr1, head, last, lookup, mapM, mapM_
106 ( all, any, elem, foldr, foldr1, head, last, lookup, mapM, mapM_
96 , maximum, minimum, notElem, null, splitAt, tail, (!!))
107 , maximum, minimum, notElem, null, splitAt, tail, (!!))
97import Streamly.Internal.Data.Stream.StreamD.Type
108import Streamly.Internal.Data.Stream.StreamD.Type
98
109
110+-- $setup
111+-- >>> :m
112+-- >>> import Streamly.Internal.Data.Stream (Stream)
113+-- >>> import qualified Streamly.Internal.Data.Stream as Stream
114+-- >>> import qualified Streamly.Internal.Data.Parser as Parser
115+-- >>> import qualified Streamly.Internal.Data.Fold as Fold
116+-- >>> import qualified Streamly.Internal.Data.Unfold as Unfold
117+
99------------------------------------------------------------------------------
118------------------------------------------------------------------------------
100-- Elimination by Folds
119-- Elimination by Folds
101------------------------------------------------------------------------------
120------------------------------------------------------------------------------
@@ -138,24 +157,40 @@ splitAt n ls
138newtype List a = List {getList :: [a]}
157newtype List a = List {getList :: [a]}
139
158
140-- | Run a 'Parse' over a stream.
159-- | Run a 'Parse' over a stream.
141−{-# INLINE_NORMAL parse #-}
160+{-# INLINE_NORMAL parseD #-}
142−parse
161+parseD
143 :: Monad m
162 :: Monad m
144 => PRD.Parser a m b
163 => PRD.Parser a m b
145 -> Stream m a
164 -> Stream m a
146 -> m (Either ParseError b)
165 -> m (Either ParseError b)
147−parse parser strm = do
166+parseD parser strm = do
148− (b, _) <- parseBreak parser strm
167+ (b, _) <- parseBreakD parser strm
149 return b
168 return b
150
169
170+-- | Parse a stream using the supplied 'Parser'.
171+--
172+-- Parsers (See "Streamly.Internal.Data.Parser") are more powerful folds that
173+-- add backtracking and error functionality to terminating folds. Unlike folds,
174+-- parsers may not always result in a valid output, they may result in an
175+-- error. For example:
176+--
177+-- >>> Stream.parse (Parser.takeEQ 1 Fold.drain) Stream.nil
178+-- Left (ParseError "takeEQ: Expecting exactly 1 elements, input terminated on 0")
179+--
180+-- Note: @parse p@ is not the same as @head . parseMany p@ on an empty stream.
181+--
182+{-# INLINE [3] parse #-}
183+parse :: Monad m => PR.Parser a m b -> Stream m a -> m (Either ParseError b)
184+parse = parseD . PRD.fromParserK
185+
151-- | Run a 'Parse' over a stream and return rest of the Stream.
186-- | Run a 'Parse' over a stream and return rest of the Stream.
152−{-# INLINE_NORMAL parseBreak #-}
187+{-# INLINE_NORMAL parseBreakD #-}
153−parseBreak
188+parseBreakD
154 :: Monad m
189 :: Monad m
155 => PRD.Parser a m b
190 => PRD.Parser a m b
156 -> Stream m a
191 -> Stream m a
157 -> m (Either ParseError b, Stream m a)
192 -> m (Either ParseError b, Stream m a)
158−parseBreak (PRD.Parser pstep initial extract) stream@(Stream step state) = do
193+parseBreakD (PRD.Parser pstep initial extract) stream@(Stream step state) = do
159 res <- initial
194 res <- initial
160 case res of
195 case res of
161 PRD.IPartial s -> go SPEC state (List []) s
196 PRD.IPartial s -> go SPEC state (List []) s
@@ -308,6 +343,12 @@ parseBreak (PRD.Parser pstep initial extract) stream@(Stream step state) = do
308 PR.Error err ->
343 PR.Error err ->
309 return (Left (ParseError err), StreamD.nil)
344 return (Left (ParseError err), StreamD.nil)
310
345
346+-- | Parse a stream using the supplied 'Parser'.
347+--
348+{-# INLINE parseBreak #-}
349+parseBreak :: Monad m => PR.Parser a m b -> Stream m a -> m (Either ParseError b, Stream m a)
350+parseBreak p = parseBreakD (PRD.fromParserK p)
351+
311------------------------------------------------------------------------------
352------------------------------------------------------------------------------
312-- Specialized Folds
353-- Specialized Folds
313------------------------------------------------------------------------------
354------------------------------------------------------------------------------
@@ -601,8 +642,14 @@ mapM_ m = drain . mapM m
601-- Multi-stream folds
642-- Multi-stream folds
602------------------------------------------------------------------------------
643------------------------------------------------------------------------------
603
644
645+-- | Returns 'True' if the first stream is the same as or a prefix of the
646+-- second. A stream is a prefix of itself.
647+--
648+-- >>> Stream.isPrefixOf (Stream.fromList "hello") (Stream.fromList "hello" :: Stream IO Char)
649+-- True
650+--
604{-# INLINE_NORMAL isPrefixOf #-}
651{-# INLINE_NORMAL isPrefixOf #-}
605−isPrefixOf :: (Eq a, Monad m) => Stream m a -> Stream m a -> m Bool
652+isPrefixOf :: (Monad m, Eq a) => Stream m a -> Stream m a -> m Bool
606isPrefixOf (Stream stepa ta) (Stream stepb tb) = go SPEC Nothing' ta tb
653isPrefixOf (Stream stepa ta) (Stream stepb tb) = go SPEC Nothing' ta tb
607
654
608 where
655 where
@@ -624,8 +671,15 @@ isPrefixOf (Stream stepa ta) (Stream stepb tb) = go SPEC Nothing' ta tb
624 Skip sb' -> go SPEC (Just' x) sa sb'
671 Skip sb' -> go SPEC (Just' x) sa sb'
625 Stop -> return False
672 Stop -> return False
626
673
674+-- | Returns 'True' if all the elements of the first stream occur, in order, in
675+-- the second stream. The elements do not have to occur consecutively. A stream
676+-- is a subsequence of itself.
677+--
678+-- >>> Stream.isSubsequenceOf (Stream.fromList "hlo") (Stream.fromList "hello" :: Stream IO Char)
679+-- True
680+--
627{-# INLINE_NORMAL isSubsequenceOf #-}
681{-# INLINE_NORMAL isSubsequenceOf #-}
628−isSubsequenceOf :: (Eq a, Monad m) => Stream m a -> Stream m a -> m Bool
682+isSubsequenceOf :: (Monad m, Eq a) => Stream m a -> Stream m a -> m Bool
629isSubsequenceOf (Stream stepa ta) (Stream stepb tb) = go SPEC Nothing' ta tb
683isSubsequenceOf (Stream stepa ta) (Stream stepb tb) = go SPEC Nothing' ta tb
630
684
631 where
685 where
@@ -647,9 +701,16 @@ isSubsequenceOf (Stream stepa ta) (Stream stepb tb) = go SPEC Nothing' ta tb
647 Skip sb' -> go SPEC (Just' x) sa sb'
701 Skip sb' -> go SPEC (Just' x) sa sb'
648 Stop -> return False
702 Stop -> return False
649
703
704+-- | @stripPrefix prefix input@ strips the @prefix@ stream from the @input@
705+-- stream if it is a prefix of input. Returns 'Nothing' if the input does not
706+-- start with the given prefix, stripped input otherwise. Returns @Just nil@
707+-- when the prefix is the same as the input stream.
708+--
709+-- Space: @O(1)@
710+--
650{-# INLINE_NORMAL stripPrefix #-}
711{-# INLINE_NORMAL stripPrefix #-}
651stripPrefix
712stripPrefix
652− :: (Eq a, Monad m)
713+ :: (Monad m, Eq a)
653 => Stream m a -> Stream m a -> m (Maybe (Stream m a))
714 => Stream m a -> Stream m a -> m (Maybe (Stream m a))
654stripPrefix (Stream stepa ta) (Stream stepb tb) = go SPEC Nothing' ta tb
715stripPrefix (Stream stepa ta) (Stream stepb tb) = go SPEC Nothing' ta tb
655
716
@@ -671,3 +732,95 @@ stripPrefix (Stream stepa ta) (Stream stepb tb) = go SPEC Nothing' ta tb
671 else return Nothing
732 else return Nothing
672 Skip sb' -> go SPEC (Just' x) sa sb'
733 Skip sb' -> go SPEC (Just' x) sa sb'
673 Stop -> return Nothing
734 Stop -> return Nothing
735+
736+-- | Returns 'True' if the first stream is an infix of the second. A stream is
737+-- considered an infix of itself.
738+--
739+-- >>> s = Stream.fromList "hello" :: Stream IO Char
740+-- >>> Stream.isInfixOf s s
741+-- True
742+--
743+-- Space: @O(n)@ worst case where @n@ is the length of the infix.
744+--
745+-- /Pre-release/
746+--
747+-- /Requires 'Storable' constraint/
748+--
749+{-# INLINE isInfixOf #-}
750+isInfixOf :: (MonadIO m, Eq a, Enum a, Storable a, Unbox a)
751+ => Stream m a -> Stream m a -> m Bool
752+isInfixOf infx stream = do
753+ arr <- fold Array.write infx
754+ -- XXX can use breakOnSeq instead (when available)
755+ r <- null $ StreamD.drop 1 $ Nesting.splitOnSeq arr Fold.drain stream
756+ return (not r)
757+
758+-- Note: isPrefixOf uses the prefix stream only once. In contrast, isSuffixOf
759+-- may use the suffix stream many times. To run in optimal memory we do not
760+-- want to buffer the suffix stream in memory therefore we need an ability to
761+-- clone (or consume it multiple times) the suffix stream without any side
762+-- effects so that multiple potential suffix matches can proceed in parallel
763+-- without buffering the suffix stream. For example, we may create the suffix
764+-- stream from a file handle, however, if we evaluate the stream multiple
765+-- times, once for each match, we will need a different file handle each time
766+-- which may exhaust the file descriptors. Instead, we want to share the same
767+-- underlying file descriptor, use pread on it to generate the stream and clone
768+-- the stream for each match. Therefore the suffix stream should be built in
769+-- such a way that it can be consumed multiple times without any problems.
770+
771+-- XXX Can be implemented with better space/time complexity.
772+-- Space: @O(n)@ worst case where @n@ is the length of the suffix.
773+
774+-- | Returns 'True' if the first stream is a suffix of the second. A stream is
775+-- considered a suffix of itself.
776+--
777+-- >>> Stream.isSuffixOf (Stream.fromList "hello") (Stream.fromList "hello" :: Stream IO Char)
778+-- True
779+--
780+-- Space: @O(n)@, buffers entire input stream and the suffix.
781+--
782+-- /Pre-release/
783+--
784+-- /Suboptimal/ - Help wanted.
785+--
786+{-# INLINE isSuffixOf #-}
787+isSuffixOf :: (Monad m, Eq a) => Stream m a -> Stream m a -> m Bool
788+isSuffixOf suffix stream =
789+ StreamD.reverse suffix `isPrefixOf` StreamD.reverse stream
790+
791+-- | Much faster than 'isSuffixOf'.
792+{-# INLINE isSuffixOfUnbox #-}
793+isSuffixOfUnbox :: (MonadIO m, Eq a, Unbox a) =>
794+ Stream m a -> Stream m a -> m Bool
795+isSuffixOfUnbox suffix stream =
796+ StreamD.reverseUnbox suffix `isPrefixOf` StreamD.reverseUnbox stream
797+
798+-- | Drops the given suffix from a stream. Returns 'Nothing' if the stream does
799+-- not end with the given suffix. Returns @Just nil@ when the suffix is the
800+-- same as the stream.
801+--
802+-- It may be more efficient to convert the stream to an Array and use
803+-- stripSuffix on that especially if the elements have a Storable or Prim
804+-- instance.
805+--
806+-- See also "Streamly.Internal.Data.Stream.Reduce.dropSuffix".
807+--
808+-- Space: @O(n)@, buffers the entire input stream as well as the suffix
809+--
810+-- /Pre-release/
811+{-# INLINE stripSuffix #-}
812+stripSuffix
813+ :: (Monad m, Eq a)
814+ => Stream m a -> Stream m a -> m (Maybe (Stream m a))
815+stripSuffix m1 m2 =
816+ fmap StreamD.reverse
817+ <$> stripPrefix (StreamD.reverse m1) (StreamD.reverse m2)
818+
819+-- | Much faster than 'stripSuffix'.
820+{-# INLINE stripSuffixUnbox #-}
821+stripSuffixUnbox
822+ :: (MonadIO m, Eq a, Unbox a)
823+ => Stream m a -> Stream m a -> m (Maybe (Stream m a))
824+stripSuffixUnbox m1 m2 =
825+ fmap StreamD.reverseUnbox
826+ <$> stripPrefix (StreamD.reverseUnbox m1) (StreamD.reverseUnbox m2)
core/src/Streamly/Internal/Data/Stream/StreamD/Exception.hs+147−35
@@ -11,13 +11,14 @@ module Streamly.Internal.Data.Stream.StreamD.Exception
11 gbracket_
11 gbracket_
12 , gbracket
12 , gbracket
13 , before
13 , before
14− , after_
14+ , afterUnsafe
15− , after
15+ , afterIO
16− , bracket_
16+ , bracketUnsafe
17− , bracket'
17+ , bracketIO3
18+ , bracketIO
18 , onException
19 , onException
19− , finally_
20+ , finallyUnsafe
20− , finally
21+ , finallyIO
21 , ghandle
22 , ghandle
22 , handle
23 , handle
23 )
24 )
@@ -36,6 +37,10 @@ import qualified Control.Monad.Catch as MC
36
37
37import Streamly.Internal.Data.Stream.StreamD.Type
38import Streamly.Internal.Data.Stream.StreamD.Type
38
39
40+-- $setup
41+-- >>> :m
42+-- >>> import qualified Streamly.Internal.Data.Stream as Stream
43+
39data GbracketState s1 s2 v
44data GbracketState s1 s2 v
40 = GBracketInit
45 = GBracketInit
41 | GBracketNormal s1 v
46 | GBracketNormal s1 v
@@ -169,7 +174,12 @@ gbracket bef aft onExc onGC ftry action =
169 Skip s -> return $ Skip (GBracketIOException (Stream step1 s))
174 Skip s -> return $ Skip (GBracketIOException (Stream step1 s))
170 Stop -> return Stop
175 Stop -> return Stop
171
176
172−-- | See 'Streamly.Internal.Data.Stream.before'.
177+-- | Run the action @m b@ before the stream yields its first element.
178+--
179+-- Same as the following but more efficient due to fusion:
180+--
181+-- >>> before action xs = Stream.nilM action <> xs
182+-- >>> before action xs = Stream.concatMap (const xs) (Stream.fromEffect action)
173--
183--
174{-# INLINE_NORMAL before #-}
184{-# INLINE_NORMAL before #-}
175before :: Monad m => m b -> Stream m a -> Stream m a
185before :: Monad m => m b -> Stream m a -> Stream m a
@@ -187,11 +197,22 @@ before action (Stream step state) = Stream step' Nothing
187 Skip s -> return $ Skip (Just s)
197 Skip s -> return $ Skip (Just s)
188 Stop -> return Stop
198 Stop -> return Stop
189
199
190−-- | See 'Streamly.Internal.Data.Stream.after_'.
200+-- | Like 'after', with following differences:
201+--
202+-- * action @m b@ won't run if the stream is garbage collected
203+-- after partial evaluation.
204+-- * Monad @m@ does not require any other constraints.
205+-- * has slightly better performance than 'after'.
206+--
207+-- Same as the following, but with stream fusion:
208+--
209+-- >>> afterUnsafe action xs = xs <> Stream.nilM action
191--
210--
211+-- /Pre-release/
212+--
192−{-# INLINE_NORMAL after_ #-}
213+{-# INLINE_NORMAL afterUnsafe #-}
193−after_ :: Monad m => m b -> Stream m a -> Stream m a
214+afterUnsafe :: Monad m => m b -> Stream m a -> Stream m a
194−after_ action (Stream step state) = Stream step' state
215+afterUnsafe action (Stream step state) = Stream step' state
195
216
196 where
217 where
197
218
@@ -203,12 +224,18 @@ after_ action (Stream step state) = Stream step' state
203 Skip s -> return $ Skip s
224 Skip s -> return $ Skip s
204 Stop -> action >> return Stop
225 Stop -> action >> return Stop
205
226
206−-- | See 'Streamly.Internal.Data.Stream.after'.
227+-- | Run the action @IO b@ whenever the stream is evaluated to completion, or
228+-- if it is garbage collected after a partial lazy evaluation.
229+--
230+-- The semantics of the action @IO b@ are similar to the semantics of cleanup
231+-- action in 'bracketIO'.
207--
232--
233+-- /See also 'afterUnsafe'/
234+--
208−{-# INLINE_NORMAL after #-}
235+{-# INLINE_NORMAL afterIO #-}
209−after :: MonadIO m
236+afterIO :: MonadIO m
210 => IO b -> Stream m a -> Stream m a
237 => IO b -> Stream m a -> Stream m a
211−after action (Stream step state) = Stream step' Nothing
238+afterIO action (Stream step state) = Stream step' Nothing
212
239
213 where
240 where
214
241
@@ -227,8 +254,11 @@ after action (Stream step state) = Stream step' Nothing
227
254
228-- XXX For high performance error checks in busy streams we may need another
255-- XXX For high performance error checks in busy streams we may need another
229-- Error constructor in step.
256-- Error constructor in step.
257+
258+-- | Run the action @m b@ if the stream evaluation is aborted due to an
259+-- exception. The exception is not caught, simply rethrown.
230--
260--
231−-- | See 'Streamly.Internal.Data.Stream.onException'.
261+-- /Inhibits stream fusion/
232--
262--
233{-# INLINE_NORMAL onException #-}
263{-# INLINE_NORMAL onException #-}
234onException :: MonadCatch m => m b -> Stream m a -> Stream m a
264onException :: MonadCatch m => m b -> Stream m a -> Stream m a
@@ -254,29 +284,55 @@ _onException action (Stream step state) = Stream step' state
254 Skip s -> return $ Skip s
284 Skip s -> return $ Skip s
255 Stop -> return Stop
285 Stop -> return Stop
256
286
257−-- | See 'Streamly.Internal.Data.Stream.bracket_'.
287+-- | Like 'bracket' but with following differences:
258--
288--
289+-- * alloc action @m b@ runs with async exceptions enabled
290+-- * cleanup action @b -> m c@ won't run if the stream is garbage collected
291+-- after partial evaluation.
292+-- * has slightly better performance than 'bracketIO'.
293+--
294+-- /Inhibits stream fusion/
295+--
296+-- /Pre-release/
297+--
259−{-# INLINE_NORMAL bracket_ #-}
298+{-# INLINE_NORMAL bracketUnsafe #-}
260−bracket_ :: MonadCatch m
299+bracketUnsafe :: MonadCatch m
261 => m b -> (b -> m c) -> (b -> Stream m a) -> Stream m a
300 => m b -> (b -> m c) -> (b -> Stream m a) -> Stream m a
262−bracket_ bef aft =
301+bracketUnsafe bef aft =
263 gbracket_
302 gbracket_
264 bef
303 bef
265 aft
304 aft
266 (\a (e :: SomeException) _ -> nilM (aft a >> MC.throwM e))
305 (\a (e :: SomeException) _ -> nilM (aft a >> MC.throwM e))
267 (inline MC.try)
306 (inline MC.try)
268
307
269−-- | See 'Streamly.Internal.Data.Stream.bracket'.
308+-- For a use case of this see the "streamly-process" package. It needs to kill
309+-- the process in case of exception or garbage collection, but waits for the
310+-- process to terminate in normal cases.
311+
312+-- | Like 'bracketIO' but can use 3 separate cleanup actions depending on the
313+-- mode of termination:
270--
314--
315+-- 1. When the stream stops normally
316+-- 2. When the stream is garbage collected
317+-- 3. When the stream encounters an exception
318+--
319+-- @bracketIO3 before onStop onGC onException action@ runs @action@ using the
320+-- result of @before@. If the stream stops, @onStop@ action is executed, if the
321+-- stream is abandoned @onGC@ is executed, if the stream encounters an
322+-- exception @onException@ is executed.
323+--
324+-- /Inhibits stream fusion/
325+--
326+-- /Pre-release/
271−{-# INLINE_NORMAL bracket' #-}
327+{-# INLINE_NORMAL bracketIO3 #-}
272−bracket' :: (MonadIO m, MonadCatch m) =>
328+bracketIO3 :: (MonadIO m, MonadCatch m) =>
273 IO b
329 IO b
274 -> (b -> IO c)
330 -> (b -> IO c)
275 -> (b -> IO d)
331 -> (b -> IO d)
276 -> (b -> IO e)
332 -> (b -> IO e)
277 -> (b -> Stream m a)
333 -> (b -> Stream m a)
278 -> Stream m a
334 -> Stream m a
279−bracket' bef aft onExc onGC =
335+bracketIO3 bef aft onExc onGC =
280 gbracket
336 gbracket
281 bef
337 bef
282 aft
338 aft
@@ -284,6 +340,32 @@ bracket' bef aft onExc onGC =
284 onGC
340 onGC
285 (inline MC.try)
341 (inline MC.try)
286
342
343+-- | Run the alloc action @IO b@ with async exceptions disabled but keeping
344+-- blocking operations interruptible (see 'Control.Exception.mask'). Use the
345+-- output @b@ as input to @b -> Stream m a@ to generate an output stream.
346+--
347+-- @b@ is usually a resource under the IO monad, e.g. a file handle, that
348+-- requires a cleanup after use. The cleanup action @b -> IO c@, runs whenever
349+-- the stream ends normally, due to a sync or async exception or if it gets
350+-- garbage collected after a partial lazy evaluation.
351+--
352+-- 'bracketIO' only guarantees that the cleanup action runs, and it runs with
353+-- async exceptions enabled. The action must ensure that it can successfully
354+-- cleanup the resource in the face of sync or async exceptions.
355+--
356+-- When the stream ends normally or on a sync exception, cleanup action runs
357+-- immediately in the current thread context, whereas in other cases it runs in
358+-- the GC context, therefore, cleanup may be delayed until the GC gets to run.
359+--
360+-- /See also: 'bracketUnsafe'/
361+--
362+-- /Inhibits stream fusion/
363+--
364+{-# INLINE bracketIO #-}
365+bracketIO :: (MonadIO m, MonadCatch m)
366+ => IO b -> (b -> IO c) -> (b -> Stream m a) -> Stream m a
367+bracketIO bef aft = bracketIO3 bef aft aft aft
368+
287data BracketState s v = BracketInit | BracketRun s v
369data BracketState s v = BracketInit | BracketRun s v
288
370
289-- | Alternate (custom) implementation of 'bracket'.
371-- | Alternate (custom) implementation of 'bracket'.
@@ -310,22 +392,49 @@ _bracket bef aft bet = Stream step' BracketInit
310 Skip s -> return $ Skip (BracketRun (Stream step s) v)
392 Skip s -> return $ Skip (BracketRun (Stream step s) v)
311 Stop -> aft v >> return Stop
393 Stop -> aft v >> return Stop
312
394
313−-- | See 'Streamly.Internal.Data.Stream.finally_'.
395+-- | Like 'finally' with following differences:
396+--
397+-- * action @m b@ won't run if the stream is garbage collected
398+-- after partial evaluation.
399+-- * has slightly better performance than 'finallyIO'.
314--
400--
315−{-# INLINE finally_ #-}
401+-- /Inhibits stream fusion/
402+--
403+-- /Pre-release/
404+--
405+{-# INLINE finallyUnsafe #-}
316−finally_ :: MonadCatch m => m b -> Stream m a -> Stream m a
406+finallyUnsafe :: MonadCatch m => m b -> Stream m a -> Stream m a
317−finally_ action xs = bracket_ (return ()) (const action) (const xs)
407+finallyUnsafe action xs = bracketUnsafe (return ()) (const action) (const xs)
318
408
319−-- | See 'Streamly.Internal.Data.Stream.finally'.
409+-- | Run the action @IO b@ whenever the stream stream stops normally, aborts
410+-- due to an exception or if it is garbage collected after a partial lazy
411+-- evaluation.
412+--
413+-- The semantics of running the action @IO b@ are similar to the cleanup action
414+-- semantics described in 'bracketIO'.
415+--
416+-- >>> finallyIO release = Stream.bracketIO (return ()) (const release)
320--
417--
321−-- finally action xs = after action $ onException action xs
418+-- /See also 'finallyUnsafe'/
322--
419--
420+-- /Inhibits stream fusion/
421+--
323−{-# INLINE finally #-}
422+{-# INLINE finallyIO #-}
324−finally :: (MonadIO m, MonadCatch m) => IO b -> Stream m a -> Stream m a
423+finallyIO :: (MonadIO m, MonadCatch m) => IO b -> Stream m a -> Stream m a
325−finally action xs = bracket' (return ()) act act act (const xs)
424+finallyIO action xs = bracketIO3 (return ()) act act act (const xs)
326 where act _ = action
425 where act _ = action
327
426
328−-- | See 'Streamly.Internal.Data.Stream.ghandle'.
427+-- | Like 'handle' but the exception handler is also provided with the stream
428+-- that generated the exception as input. The exception handler can thus
429+-- re-evaluate the stream to retry the action that failed. The exception
430+-- handler can again call 'ghandle' on it to retry the action multiple times.
431+--
432+-- This is highly experimental. In a stream of actions we can map the stream
433+-- with a retry combinator to retry each action on failure.
434+--
435+-- /Inhibits stream fusion/
436+--
437+-- /Pre-release/
329--
438--
330{-# INLINE_NORMAL ghandle #-}
439{-# INLINE_NORMAL ghandle #-}
331ghandle :: (MonadCatch m, Exception e)
440ghandle :: (MonadCatch m, Exception e)
@@ -333,7 +442,10 @@ ghandle :: (MonadCatch m, Exception e)
333ghandle f stream =
442ghandle f stream =
334 gbracket_ (return ()) return (const f) (inline MC.try) (const stream)
443 gbracket_ (return ()) return (const f) (inline MC.try) (const stream)
335
444
336−-- | See 'Streamly.Internal.Data.Stream.handle'.
445+-- | When evaluating a stream if an exception occurs, stream evaluation aborts
446+-- and the specified exception handler is run with the exception as argument.
447+--
448+-- /Inhibits stream fusion/
337--
449--
338{-# INLINE_NORMAL handle #-}
450{-# INLINE_NORMAL handle #-}
339handle :: (MonadCatch m, Exception e)
451handle :: (MonadCatch m, Exception e)
core/src/Streamly/Internal/Data/Stream/StreamD/Generate.hs+771−42
@@ -7,17 +7,6 @@
7-- Stability : experimental
7-- Stability : experimental
8-- Portability : GHC
8-- Portability : GHC
9--
9--
10−-- Prefer unfolds ("Streamly.Internal.Data.Unfold") over the combinators in
11−-- this module. They are more powerful and efficient as they can be transformed
12−-- and composed on the input side efficiently and they can fuse in nested
13−-- operations (e.g. unfoldMany). All the combinators in this module can be
14−-- expressed using unfolds with the same efficiency.
15−--
16−-- Operations in this module that are not in "Streamly.Internal.Data.Unfold":
17−-- generate, times, fromPrimIORef.
18−--
19−-- We should plan to replace this module with "Streamly.Internal.Data.Unfold"
20−-- in future.
21
10
22-- A few combinators in this module have been adapted from the vector package
11-- A few combinators in this module have been adapted from the vector package
23-- (c) Roman Leshchinskiy. See the notes in specific combinators.
12-- (c) Roman Leshchinskiy. See the notes in specific combinators.
@@ -46,20 +35,50 @@ module Streamly.Internal.Data.Stream.StreamD.Generate
46 , replicateM
35 , replicateM
47
36
48 -- * Enumeration
37 -- * Enumeration
49− , enumerateFromStepIntegral
38+ -- ** Enumerating 'Num' Types
39+ , enumerateFromStepNum
40+ , enumerateFromNum
41+ , enumerateFromThenNum
42+
43+ -- ** Enumerating 'Bounded' 'Enum' Types
44+ , enumerate
45+ , enumerateTo
46+ , enumerateFromBounded
47+
48+ -- ** Enumerating 'Enum' Types not larger than 'Int'
49+ , enumerateFromToSmall
50+ , enumerateFromThenToSmall
51+ , enumerateFromThenSmallBounded
52+
53+ -- ** Enumerating 'Bounded' 'Integral' Types
50 , enumerateFromIntegral
54 , enumerateFromIntegral
51 , enumerateFromThenIntegral
55 , enumerateFromThenIntegral
56+
57+ -- ** Enumerating 'Integral' Types
52 , enumerateFromToIntegral
58 , enumerateFromToIntegral
53 , enumerateFromThenToIntegral
59 , enumerateFromThenToIntegral
54
60
55− , enumerateFromStepNum
61+ -- ** Enumerating unbounded 'Integral' Types
56− , enumerateFromNum
62+ , enumerateFromStepIntegral
57− , enumerateFromThenNum
63+
64+ -- ** Enumerating 'Fractional' Types
65+ , enumerateFromFractional
58 , enumerateFromToFractional
66 , enumerateFromToFractional
67+ , enumerateFromThenFractional
59 , enumerateFromThenToFractional
68 , enumerateFromThenToFractional
60
69
70+ -- ** Enumerable Type Class
71+ , Enumerable(..)
72+
61 -- * Time Enumeration
73 -- * Time Enumeration
62 , times
74 , times
75+ , timesWith
76+ , absTimes
77+ , absTimesWith
78+ , relTimes
79+ , relTimesWith
80+ , durations
81+ , timeout
63
82
64 -- * From Generators
83 -- * From Generators
65 -- | Generate a monadic stream from a seed.
84 -- | Generate a monadic stream from a seed.
@@ -75,12 +94,15 @@ module Streamly.Internal.Data.Stream.StreamD.Generate
75 -- * From Containers
94 -- * From Containers
76 -- | Transform an input structure into a stream.
95 -- | Transform an input structure into a stream.
77
96
78− -- Note: Direct style stream does not support @fromFoldable@.
79 , fromList
97 , fromList
80 , fromListM
98 , fromListM
99+ , fromFoldable
100+ , fromFoldableM
81
101
82 -- * From Pointers
102 -- * From Pointers
83 , fromPtr
103 , fromPtr
104+ , fromPtrN
105+ , fromByteStr#
84
106
85 -- * Conversions
107 -- * Conversions
86 , fromStreamK
108 , fromStreamK
@@ -92,53 +114,108 @@ where
92#include "ArrayMacros.h"
114#include "ArrayMacros.h"
93
115
94import Control.Monad.IO.Class (MonadIO(..))
116import Control.Monad.IO.Class (MonadIO(..))
117+import Data.Functor.Identity (Identity(..))
95import Foreign.Ptr (Ptr, plusPtr)
118import Foreign.Ptr (Ptr, plusPtr)
96import Foreign.Storable (Storable (peek), sizeOf)
119import Foreign.Storable (Storable (peek), sizeOf)
120+import GHC.Exts (Addr#, Ptr (Ptr))
97import Streamly.Internal.Data.Time.Clock
121import Streamly.Internal.Data.Time.Clock
98 (Clock(Monotonic), asyncClock, readClock)
122 (Clock(Monotonic), asyncClock, readClock)
99import Streamly.Internal.Data.Time.Units
123import Streamly.Internal.Data.Time.Units
100− (toAbsTime, AbsTime, toRelTime64, RelTime64)
124+ (toAbsTime, AbsTime, toRelTime64, RelTime64, addToAbsTime64)
101
125
102#ifdef USE_UNFOLDS_EVERYWHERE
126#ifdef USE_UNFOLDS_EVERYWHERE
103import qualified Streamly.Internal.Data.Unfold as Unfold
127import qualified Streamly.Internal.Data.Unfold as Unfold
104import qualified Streamly.Internal.Data.Unfold.Enumeration as Unfold
128import qualified Streamly.Internal.Data.Unfold.Enumeration as Unfold
105#endif
129#endif
106
130
131+import Data.Fixed
132+import Data.Int
133+import Data.Ratio
134+import Data.Word
135+import Numeric.Natural
107−import Prelude hiding (iterate, repeat, replicate, takeWhile)
136+import Prelude hiding (iterate, repeat, replicate, take, takeWhile)
108import Streamly.Internal.Data.Stream.StreamD.Type
137import Streamly.Internal.Data.Stream.StreamD.Type
109
138
139+-- $setup
140+-- >>> :m
141+-- >>> import Control.Concurrent (threadDelay)
142+-- >>> import Data.Function (fix, (&))
143+-- >>> import Data.Semigroup (cycle1)
144+-- >>> import qualified Streamly.Data.Fold as Fold
145+-- >>> import qualified Streamly.Data.Unfold as Unfold
146+-- >>> import qualified Streamly.Internal.Data.Stream as Stream
147+-- >>> import GHC.Exts (Ptr (Ptr))
148+
110------------------------------------------------------------------------------
149------------------------------------------------------------------------------
111-- Primitives
150-- Primitives
112------------------------------------------------------------------------------
151------------------------------------------------------------------------------
113
152
114−-- | An empty 'Stream'.
153+-- XXX implement in terms of nilM?
154+
155+-- | A stream that terminates without producing any output or side effect.
156+--
157+-- >>> Stream.fold Fold.toList Stream.nil
158+-- []
159+--
115{-# INLINE_NORMAL nil #-}
160{-# INLINE_NORMAL nil #-}
116−nil :: Monad m => Stream m a
161+nil :: Applicative m => Stream m a
117−nil = Stream (\_ _ -> return Stop) ()
162+nil = Stream (\_ _ -> pure Stop) ()
118
163
119-- XXX implement in terms of consM?
164-- XXX implement in terms of consM?
120-- cons x = consM (return x)
165-- cons x = consM (return x)
166+
167+-- | Fuse a pure value at the head of an existing stream::
168+--
169+-- >>> s = 1 `Stream.cons` Stream.fromList [2,3]
170+-- >>> Stream.fold Fold.toList s
171+-- [1,2,3]
172+--
173+-- This function should not be used to dynamically construct a stream. If a
174+-- stream is constructed by successive use of this function it would take
175+-- O(n^2) time to consume the stream.
176+--
177+-- This function should only be used to statically fuse an element with a
178+-- stream. Do not use this recursively or where it cannot be inlined.
179+--
180+-- See "Streamly.Data.Stream.StreamK" for a 'cons' that can be used to
181+-- construct a stream recursively.
182+--
183+-- Definition:
184+--
185+-- >>> cons x xs = return x `Stream.consM` xs
121--
186--
122−-- | Can fuse but has O(n^2) complexity.
123{-# INLINE_NORMAL cons #-}
187{-# INLINE_NORMAL cons #-}
124−cons :: Monad m => a -> Stream m a -> Stream m a
188+cons :: Applicative m => a -> Stream m a -> Stream m a
125cons x (Stream step state) = Stream step1 Nothing
189cons x (Stream step state) = Stream step1 Nothing
126 where
190 where
127 {-# INLINE_LATE step1 #-}
191 {-# INLINE_LATE step1 #-}
128− step1 _ Nothing = return $ Yield x (Just state)
192+ step1 _ Nothing = pure $ Yield x (Just state)
129 step1 gst (Just st) = do
193 step1 gst (Just st) = do
130− r <- step gst st
131− return $
132− case r of
194+ (\case
133 Yield a s -> Yield a (Just s)
195 Yield a s -> Yield a (Just s)
134 Skip s -> Skip (Just s)
196 Skip s -> Skip (Just s)
135− Stop -> Stop
197+ Stop -> Stop) <$> step gst st
136
198
137------------------------------------------------------------------------------
199------------------------------------------------------------------------------
138-- Unfolding
200-- Unfolding
139------------------------------------------------------------------------------
201------------------------------------------------------------------------------
140
202
141-- Adapted from vector package
203-- Adapted from vector package
204+
205+-- | Build a stream by unfolding a /monadic/ step function starting from a
206+-- seed. The step function returns the next element in the stream and the next
207+-- seed value. When it is done it returns 'Nothing' and the stream ends. For
208+-- example,
209+--
210+-- >>> :{
211+-- let f b =
212+-- if b > 2
213+-- then return Nothing
214+-- else return (Just (b, b + 1))
215+-- in Stream.fold Fold.toList $ Stream.unfoldrM f 0
216+-- :}
217+-- [0,1,2]
218+--
142{-# INLINE_NORMAL unfoldrM #-}
219{-# INLINE_NORMAL unfoldrM #-}
143unfoldrM :: Monad m => (s -> m (Maybe (a, s))) -> s -> Stream m a
220unfoldrM :: Monad m => (s -> m (Maybe (a, s))) -> s -> Stream m a
144#ifdef USE_UNFOLDS_EVERYWHERE
221#ifdef USE_UNFOLDS_EVERYWHERE
@@ -154,6 +231,28 @@ unfoldrM next = Stream step
154 Nothing -> Stop
231 Nothing -> Stop
155#endif
232#endif
156
233
234+-- |
235+-- >>> :{
236+-- unfoldr step s =
237+-- case step s of
238+-- Nothing -> Stream.nil
239+-- Just (a, b) -> a `Stream.cons` unfoldr step b
240+-- :}
241+--
242+-- Build a stream by unfolding a /pure/ step function @step@ starting from a
243+-- seed @s@. The step function returns the next element in the stream and the
244+-- next seed value. When it is done it returns 'Nothing' and the stream ends.
245+-- For example,
246+--
247+-- >>> :{
248+-- let f b =
249+-- if b > 2
250+-- then Nothing
251+-- else Just (b, b + 1)
252+-- in Stream.fold Fold.toList $ Stream.unfoldr f 0
253+-- :}
254+-- [0,1,2]
255+--
157{-# INLINE_LATE unfoldr #-}
256{-# INLINE_LATE unfoldr #-}
158unfoldr :: Monad m => (s -> Maybe (a, s)) -> s -> Stream m a
257unfoldr :: Monad m => (s -> Maybe (a, s)) -> s -> Stream m a
159unfoldr f = unfoldrM (return . f)
258unfoldr f = unfoldrM (return . f)
@@ -162,6 +261,20 @@ unfoldr f = unfoldrM (return . f)
162-- From values
261-- From values
163------------------------------------------------------------------------------
262------------------------------------------------------------------------------
164
263
264+-- |
265+-- >>> repeatM = Stream.sequence . Stream.repeat
266+-- >>> repeatM = fix . Stream.consM
267+-- >>> repeatM = cycle1 . Stream.fromEffect
268+--
269+-- Generate a stream by repeatedly executing a monadic action forever.
270+--
271+-- >>> :{
272+-- repeatAction =
273+-- Stream.repeatM (threadDelay 1000000 >> print 1)
274+-- & Stream.take 10
275+-- & Stream.fold Fold.drain
276+-- :}
277+--
165{-# INLINE_NORMAL repeatM #-}
278{-# INLINE_NORMAL repeatM #-}
166repeatM :: Monad m => m a -> Stream m a
279repeatM :: Monad m => m a -> Stream m a
167#ifdef USE_UNFOLDS_EVERYWHERE
280#ifdef USE_UNFOLDS_EVERYWHERE
@@ -170,6 +283,11 @@ repeatM = unfold Unfold.repeatM
170repeatM x = Stream (\_ _ -> x >>= \r -> return $ Yield r ()) ()
283repeatM x = Stream (\_ _ -> x >>= \r -> return $ Yield r ()) ()
171#endif
284#endif
172
285
286+-- |
287+-- Generate an infinite stream by repeating a pure value.
288+--
289+-- >>> repeat x = Stream.repeatM (pure x)
290+--
173{-# INLINE_NORMAL repeat #-}
291{-# INLINE_NORMAL repeat #-}
174repeat :: Monad m => a -> Stream m a
292repeat :: Monad m => a -> Stream m a
175#ifdef USE_UNFOLDS_EVERYWHERE
293#ifdef USE_UNFOLDS_EVERYWHERE
@@ -179,8 +297,13 @@ repeat x = Stream (\_ _ -> return $ Yield x ()) ()
179#endif
297#endif
180
298
181-- Adapted from the vector package
299-- Adapted from the vector package
300+
301+-- |
302+-- >>> replicateM n = Stream.sequence . Stream.replicate n
303+--
304+-- Generate a stream by performing a monadic action @n@ times.
182{-# INLINE_NORMAL replicateM #-}
305{-# INLINE_NORMAL replicateM #-}
183−replicateM :: forall m a. Monad m => Int -> m a -> Stream m a
306+replicateM :: Monad m => Int -> m a -> Stream m a
184#ifdef USE_UNFOLDS_EVERYWHERE
307#ifdef USE_UNFOLDS_EVERYWHERE
185replicateM n p = unfold Unfold.replicateM (n, p)
308replicateM n p = unfold Unfold.replicateM (n, p)
186#else
309#else
@@ -194,6 +317,12 @@ replicateM n p = Stream step n
194 return $ Yield x (i - 1)
317 return $ Yield x (i - 1)
195#endif
318#endif
196
319
320+-- |
321+-- >>> replicate n = Stream.take n . Stream.repeat
322+-- >>> replicate n x = Stream.replicateM n (pure x)
323+--
324+-- Generate a stream of length @n@ by repeating a value @n@ times.
325+--
197{-# INLINE_NORMAL replicate #-}
326{-# INLINE_NORMAL replicate #-}
198replicate :: Monad m => Int -> a -> Stream m a
327replicate :: Monad m => Int -> a -> Stream m a
199replicate n x = replicateM n (return x)
328replicate n x = replicateM n (return x)
@@ -291,8 +420,19 @@ enumerateFromThenToIntegralDn from next to = Stream step EnumInit
291#endif
420#endif
292
421
293-- XXX This can perhaps be simplified and written in terms of
422-- XXX This can perhaps be simplified and written in terms of
294−-- enumeratFromStepIntegral as we have done in unfolds. But anyway we should be
423+-- enumeratFromStepIntegral as we have done in unfolds.
295−-- replacing the stream generation module with unfolds.
424+
425+-- | Enumerate an 'Integral' type in steps up to a given limit.
426+-- @enumerateFromThenToIntegral from then to@ generates a finite stream whose
427+-- first element is @from@, the second element is @then@ and the successive
428+-- elements are in increments of @then - from@ up to @to@.
429+--
430+-- >>> Stream.fold Fold.toList $ Stream.enumerateFromThenToIntegral 0 2 6
431+-- [0,2,4,6]
432+--
433+-- >>> Stream.fold Fold.toList $ Stream.enumerateFromThenToIntegral 0 (-2) (-6)
434+-- [0,-2,-4,-6]
435+--
296{-# INLINE_NORMAL enumerateFromThenToIntegral #-}
436{-# INLINE_NORMAL enumerateFromThenToIntegral #-}
297enumerateFromThenToIntegral
437enumerateFromThenToIntegral
298 :: (Monad m, Integral a)
438 :: (Monad m, Integral a)
@@ -306,6 +446,17 @@ enumerateFromThenToIntegral from next to
306 | otherwise = enumerateFromThenToIntegralDn from next to
446 | otherwise = enumerateFromThenToIntegralDn from next to
307#endif
447#endif
308
448
449+-- | Enumerate an 'Integral' type in steps. @enumerateFromThenIntegral from
450+-- then@ generates a stream whose first element is @from@, the second element
451+-- is @then@ and the successive elements are in increments of @then - from@.
452+-- The stream is bounded by the size of the 'Integral' type.
453+--
454+-- >>> Stream.fold Fold.toList $ Stream.take 4 $ Stream.enumerateFromThenIntegral (0 :: Int) 2
455+-- [0,2,4,6]
456+--
457+-- >>> Stream.fold Fold.toList $ Stream.take 4 $ Stream.enumerateFromThenIntegral (0 :: Int) (-2)
458+-- [0,-2,-4,-6]
459+--
309{-# INLINE_NORMAL enumerateFromThenIntegral #-}
460{-# INLINE_NORMAL enumerateFromThenIntegral #-}
310enumerateFromThenIntegral
461enumerateFromThenIntegral
311 :: (Monad m, Integral a, Bounded a)
462 :: (Monad m, Integral a, Bounded a)
@@ -320,8 +471,18 @@ enumerateFromThenIntegral from next =
320 else enumerateFromThenToIntegralDn from next minBound
471 else enumerateFromThenToIntegralDn from next minBound
321#endif
472#endif
322
473
323−-- | Can be used to enumerate unbounded integrals. This does not check for
474+-- | @enumerateFromStepIntegral from step@ generates an infinite stream whose
475+-- first element is @from@ and the successive elements are in increments of
476+-- @step@.
477+--
478+-- CAUTION: This function is not safe for finite integral types. It does not
324−-- overflow or underflow for bounded integrals.
479+-- check for overflow, underflow or bounds.
480+--
481+-- >>> Stream.fold Fold.toList $ Stream.take 4 $ Stream.enumerateFromStepIntegral 0 2
482+-- [0,2,4,6]
483+--
484+-- >>> Stream.fold Fold.toList $ Stream.take 3 $ Stream.enumerateFromStepIntegral 0 (-2)
485+-- [0,-2,-4]
325--
486--
326{-# INLINE_NORMAL enumerateFromStepIntegral #-}
487{-# INLINE_NORMAL enumerateFromStepIntegral #-}
327enumerateFromStepIntegral :: (Integral a, Monad m) => a -> a -> Stream m a
488enumerateFromStepIntegral :: (Integral a, Monad m) => a -> a -> Stream m a
@@ -336,13 +497,26 @@ enumerateFromStepIntegral from stride =
336 step _ !x = return $ Yield x $! (x + stride)
497 step _ !x = return $ Yield x $! (x + stride)
337#endif
498#endif
338
499
339−-- | Enumerate upwards from @from@ to @to@. We are assuming that "to" is
500+-- | Enumerate an 'Integral' type up to a given limit.
340−-- constrained by the type to be within max/min bounds.
501+-- @enumerateFromToIntegral from to@ generates a finite stream whose first
502+-- element is @from@ and successive elements are in increments of @1@ up to
503+-- @to@.
504+--
505+-- >>> Stream.fold Fold.toList $ Stream.enumerateFromToIntegral 0 4
506+-- [0,1,2,3,4]
507+--
341{-# INLINE enumerateFromToIntegral #-}
508{-# INLINE enumerateFromToIntegral #-}
342enumerateFromToIntegral :: (Monad m, Integral a) => a -> a -> Stream m a
509enumerateFromToIntegral :: (Monad m, Integral a) => a -> a -> Stream m a
343enumerateFromToIntegral from to =
510enumerateFromToIntegral from to =
344 takeWhile (<= to) $ enumerateFromStepIntegral from 1
511 takeWhile (<= to) $ enumerateFromStepIntegral from 1
345
512
513+-- | Enumerate an 'Integral' type. @enumerateFromIntegral from@ generates a
514+-- stream whose first element is @from@ and the successive elements are in
515+-- increments of @1@. The stream is bounded by the size of the 'Integral' type.
516+--
517+-- >>> Stream.fold Fold.toList $ Stream.take 4 $ Stream.enumerateFromIntegral (0 :: Int)
518+-- [0,1,2,3]
519+--
346{-# INLINE enumerateFromIntegral #-}
520{-# INLINE enumerateFromIntegral #-}
347enumerateFromIntegral :: (Monad m, Integral a, Bounded a) => a -> Stream m a
521enumerateFromIntegral :: (Monad m, Integral a, Bounded a) => a -> Stream m a
348enumerateFromIntegral from = enumerateFromToIntegral from maxBound
522enumerateFromIntegral from = enumerateFromToIntegral from maxBound
@@ -351,9 +525,67 @@ enumerateFromIntegral from = enumerateFromToIntegral from maxBound
351-- Enumeration of Fractionals
525-- Enumeration of Fractionals
352------------------------------------------------------------------------------
526------------------------------------------------------------------------------
353
527
354−-- | We cannot write a general function for Num. The only way to write code
528+-- We cannot write a general function for Num. The only way to write code
355-- portable between the two is to use a 'Real' constraint and convert between
529-- portable between the two is to use a 'Real' constraint and convert between
356-- Fractional and Integral using fromRational which is horribly slow.
530-- Fractional and Integral using fromRational which is horribly slow.
531+
532+-- Even though the underlying implementation of enumerateFromFractional and
533+-- enumerateFromThenFractional works for any 'Num' we have restricted these to
534+-- 'Fractional' because these do not perform any bounds check, in contrast to
535+-- integral versions and are therefore not equivalent substitutes for those.
536+
537+-- | Numerically stable enumeration from a 'Fractional' number in steps of size
538+-- @1@. @enumerateFromFractional from@ generates a stream whose first element
539+-- is @from@ and the successive elements are in increments of @1@. No overflow
540+-- or underflow checks are performed.
541+--
542+-- This is the equivalent to 'enumFrom' for 'Fractional' types. For example:
543+--
544+-- >>> Stream.fold Fold.toList $ Stream.take 4 $ Stream.enumerateFromFractional 1.1
545+-- [1.1,2.1,3.1,4.1]
546+--
547+{-# INLINE enumerateFromFractional #-}
548+enumerateFromFractional :: (Monad m, Fractional a) => a -> Stream m a
549+enumerateFromFractional = enumerateFromNum
550+
551+-- | Numerically stable enumeration from a 'Fractional' number in steps.
552+-- @enumerateFromThenFractional from then@ generates a stream whose first
553+-- element is @from@, the second element is @then@ and the successive elements
554+-- are in increments of @then - from@. No overflow or underflow checks are
555+-- performed.
556+--
557+-- This is the equivalent of 'enumFromThen' for 'Fractional' types. For
558+-- example:
559+--
560+-- >>> Stream.fold Fold.toList $ Stream.take 4 $ Stream.enumerateFromThenFractional 1.1 2.1
561+-- [1.1,2.1,3.1,4.1]
562+--
563+-- >>> Stream.fold Fold.toList $ Stream.take 4 $ Stream.enumerateFromThenFractional 1.1 (-2.1)
564+-- [1.1,-2.1,-5.300000000000001,-8.500000000000002]
565+--
566+{-# INLINE enumerateFromThenFractional #-}
567+enumerateFromThenFractional
568+ :: (Monad m, Fractional a)
569+ => a -> a -> Stream m a
570+enumerateFromThenFractional = enumerateFromThenNum
571+
572+-- | Numerically stable enumeration from a 'Fractional' number to a given
573+-- limit. @enumerateFromToFractional from to@ generates a finite stream whose
574+-- first element is @from@ and successive elements are in increments of @1@ up
575+-- to @to@.
576+--
577+-- This is the equivalent of 'enumFromTo' for 'Fractional' types. For
578+-- example:
579+--
580+-- >>> Stream.fold Fold.toList $ Stream.enumerateFromToFractional 1.1 4
581+-- [1.1,2.1,3.1,4.1]
582+--
583+-- >>> Stream.fold Fold.toList $ Stream.enumerateFromToFractional 1.1 4.6
584+-- [1.1,2.1,3.1,4.1,5.1]
585+--
586+-- Notice that the last element is equal to the specified @to@ value after
587+-- rounding to the nearest integer.
588+--
357{-# INLINE_NORMAL enumerateFromToFractional #-}
589{-# INLINE_NORMAL enumerateFromToFractional #-}
358enumerateFromToFractional
590enumerateFromToFractional
359 :: (Monad m, Fractional a, Ord a)
591 :: (Monad m, Fractional a, Ord a)
@@ -361,24 +593,320 @@ enumerateFromToFractional
361enumerateFromToFractional from to =
593enumerateFromToFractional from to =
362 takeWhile (<= to + 1 / 2) $ enumerateFromStepNum from 1
594 takeWhile (<= to + 1 / 2) $ enumerateFromStepNum from 1
363
595
596+-- | Numerically stable enumeration from a 'Fractional' number in steps up to a
597+-- given limit. @enumerateFromThenToFractional from then to@ generates a
598+-- finite stream whose first element is @from@, the second element is @then@
599+-- and the successive elements are in increments of @then - from@ up to @to@.
600+--
601+-- This is the equivalent of 'enumFromThenTo' for 'Fractional' types. For
602+-- example:
603+--
604+-- >>> Stream.fold Fold.toList $ Stream.enumerateFromThenToFractional 0.1 2 6
605+-- [0.1,2.0,3.9,5.799999999999999]
606+--
607+-- >>> Stream.fold Fold.toList $ Stream.enumerateFromThenToFractional 0.1 (-2) (-6)
608+-- [0.1,-2.0,-4.1000000000000005,-6.200000000000001]
609+--
364{-# INLINE_NORMAL enumerateFromThenToFractional #-}
610{-# INLINE_NORMAL enumerateFromThenToFractional #-}
365enumerateFromThenToFractional
611enumerateFromThenToFractional
366 :: (Monad m, Fractional a, Ord a)
612 :: (Monad m, Fractional a, Ord a)
367 => a -> a -> a -> Stream m a
613 => a -> a -> a -> Stream m a
368enumerateFromThenToFractional from next to =
614enumerateFromThenToFractional from next to =
369− takeWhile predicate $ enumerateFromThenNum from next
615+ takeWhile predicate $ enumerateFromThenFractional from next
370 where
616 where
371 mid = (next - from) / 2
617 mid = (next - from) / 2
372 predicate | next >= from = (<= to + mid)
618 predicate | next >= from = (<= to + mid)
373 | otherwise = (>= to + mid)
619 | otherwise = (>= to + mid)
374
620
621+-------------------------------------------------------------------------------
622+-- Enumeration of Enum types not larger than Int
623+-------------------------------------------------------------------------------
624+--
625+-- | 'enumerateFromTo' for 'Enum' types not larger than 'Int'.
626+--
627+{-# INLINE enumerateFromToSmall #-}
628+enumerateFromToSmall :: (Monad m, Enum a) => a -> a -> Stream m a
629+enumerateFromToSmall from to =
630+ fmap toEnum
631+ $ enumerateFromToIntegral (fromEnum from) (fromEnum to)
632+
633+-- | 'enumerateFromThenTo' for 'Enum' types not larger than 'Int'.
634+--
635+{-# INLINE enumerateFromThenToSmall #-}
636+enumerateFromThenToSmall :: (Monad m, Enum a)
637+ => a -> a -> a -> Stream m a
638+enumerateFromThenToSmall from next to =
639+ fmap toEnum
640+ $ enumerateFromThenToIntegral
641+ (fromEnum from) (fromEnum next) (fromEnum to)
642+
643+-- | 'enumerateFromThen' for 'Enum' types not larger than 'Int'.
644+--
645+-- Note: We convert the 'Enum' to 'Int' and enumerate the 'Int'. If a
646+-- type is bounded but does not have a 'Bounded' instance then we can go on
647+-- enumerating it beyond the legal values of the type, resulting in the failure
648+-- of 'toEnum' when converting back to 'Enum'. Therefore we require a 'Bounded'
649+-- instance for this function to be safely used.
650+--
651+{-# INLINE enumerateFromThenSmallBounded #-}
652+enumerateFromThenSmallBounded :: (Monad m, Enumerable a, Bounded a)
653+ => a -> a -> Stream m a
654+enumerateFromThenSmallBounded from next =
655+ if fromEnum next >= fromEnum from
656+ then enumerateFromThenTo from next maxBound
657+ else enumerateFromThenTo from next minBound
658+
659+-------------------------------------------------------------------------------
660+-- Enumerable type class
661+-------------------------------------------------------------------------------
662+--
663+-- NOTE: We would like to rewrite calls to fromList [1..] etc. to stream
664+-- enumerations like this:
665+--
666+-- {-# RULES "fromList enumFrom" [1]
667+-- forall (a :: Int). D.fromList (enumFrom a) = D.enumerateFromIntegral a #-}
668+--
669+-- But this does not work because enumFrom is a class method and GHC rewrites
670+-- it quickly, so we do not get a chance to have our rule fired.
671+
672+-- | Types that can be enumerated as a stream. The operations in this type
673+-- class are equivalent to those in the 'Enum' type class, except that these
674+-- generate a stream instead of a list. Use the functions in
675+-- "Streamly.Internal.Data.Stream.Enumeration" module to define new instances.
676+--
677+class Enum a => Enumerable a where
678+ -- | @enumerateFrom from@ generates a stream starting with the element
679+ -- @from@, enumerating up to 'maxBound' when the type is 'Bounded' or
680+ -- generating an infinite stream when the type is not 'Bounded'.
681+ --
682+ -- >>> Stream.fold Fold.toList $ Stream.take 4 $ Stream.enumerateFrom (0 :: Int)
683+ -- [0,1,2,3]
684+ --
685+ -- For 'Fractional' types, enumeration is numerically stable. However, no
686+ -- overflow or underflow checks are performed.
687+ --
688+ -- >>> Stream.fold Fold.toList $ Stream.take 4 $ Stream.enumerateFrom 1.1
689+ -- [1.1,2.1,3.1,4.1]
690+ --
691+ enumerateFrom :: (Monad m) => a -> Stream m a
692+
693+ -- | Generate a finite stream starting with the element @from@, enumerating
694+ -- the type up to the value @to@. If @to@ is smaller than @from@ then an
695+ -- empty stream is returned.
696+ --
697+ -- >>> Stream.fold Fold.toList $ Stream.enumerateFromTo 0 4
698+ -- [0,1,2,3,4]
699+ --
700+ -- For 'Fractional' types, the last element is equal to the specified @to@
701+ -- value after rounding to the nearest integral value.
702+ --
703+ -- >>> Stream.fold Fold.toList $ Stream.enumerateFromTo 1.1 4
704+ -- [1.1,2.1,3.1,4.1]
705+ --
706+ -- >>> Stream.fold Fold.toList $ Stream.enumerateFromTo 1.1 4.6
707+ -- [1.1,2.1,3.1,4.1,5.1]
708+ --
709+ enumerateFromTo :: (Monad m) => a -> a -> Stream m a
710+
711+ -- | @enumerateFromThen from then@ generates a stream whose first element
712+ -- is @from@, the second element is @then@ and the successive elements are
713+ -- in increments of @then - from@. Enumeration can occur downwards or
714+ -- upwards depending on whether @then@ comes before or after @from@. For
715+ -- 'Bounded' types the stream ends when 'maxBound' is reached, for
716+ -- unbounded types it keeps enumerating infinitely.
717+ --
718+ -- >>> Stream.fold Fold.toList $ Stream.take 4 $ Stream.enumerateFromThen 0 2
719+ -- [0,2,4,6]
720+ --
721+ -- >>> Stream.fold Fold.toList $ Stream.take 4 $ Stream.enumerateFromThen 0 (-2)
722+ -- [0,-2,-4,-6]
723+ --
724+ enumerateFromThen :: (Monad m) => a -> a -> Stream m a
725+
726+ -- | @enumerateFromThenTo from then to@ generates a finite stream whose
727+ -- first element is @from@, the second element is @then@ and the successive
728+ -- elements are in increments of @then - from@ up to @to@. Enumeration can
729+ -- occur downwards or upwards depending on whether @then@ comes before or
730+ -- after @from@.
731+ --
732+ -- >>> Stream.fold Fold.toList $ Stream.enumerateFromThenTo 0 2 6
733+ -- [0,2,4,6]
734+ --
735+ -- >>> Stream.fold Fold.toList $ Stream.enumerateFromThenTo 0 (-2) (-6)
736+ -- [0,-2,-4,-6]
737+ --
738+ enumerateFromThenTo :: (Monad m) => a -> a -> a -> Stream m a
739+
740+-- MAYBE: Sometimes it is more convenient to know the count rather then the
741+-- ending or starting element. For those cases we can define the folllowing
742+-- APIs. All of these will work only for bounded types if we represent the
743+-- count by Int.
744+--
745+-- enumerateN
746+-- enumerateFromN
747+-- enumerateToN
748+-- enumerateFromStep
749+-- enumerateFromStepN
750+
751+-------------------------------------------------------------------------------
752+-- Convenient functions for bounded types
753+-------------------------------------------------------------------------------
754+--
755+-- |
756+-- > enumerate = enumerateFrom minBound
757+--
758+-- Enumerate a 'Bounded' type from its 'minBound' to 'maxBound'
759+--
760+{-# INLINE enumerate #-}
761+enumerate :: (Monad m, Bounded a, Enumerable a) => Stream m a
762+enumerate = enumerateFrom minBound
763+
764+-- |
765+-- >>> enumerateTo = Stream.enumerateFromTo minBound
766+--
767+-- Enumerate a 'Bounded' type from its 'minBound' to specified value.
768+--
769+{-# INLINE enumerateTo #-}
770+enumerateTo :: (Monad m, Bounded a, Enumerable a) => a -> Stream m a
771+enumerateTo = enumerateFromTo minBound
772+
773+-- |
774+-- >>> enumerateFromBounded from = Stream.enumerateFromTo from maxBound
775+--
776+-- 'enumerateFrom' for 'Bounded' 'Enum' types.
777+--
778+{-# INLINE enumerateFromBounded #-}
779+enumerateFromBounded :: (Monad m, Enumerable a, Bounded a)
780+ => a -> Stream m a
781+enumerateFromBounded from = enumerateFromTo from maxBound
782+
783+-------------------------------------------------------------------------------
784+-- Enumerable Instances
785+-------------------------------------------------------------------------------
786+--
787+-- For Enum types smaller than or equal to Int size.
788+#define ENUMERABLE_BOUNDED_SMALL(SMALL_TYPE) \
789+instance Enumerable SMALL_TYPE where { \
790+ {-# INLINE enumerateFrom #-}; \
791+ enumerateFrom = enumerateFromBounded; \
792+ {-# INLINE enumerateFromThen #-}; \
793+ enumerateFromThen = enumerateFromThenSmallBounded; \
794+ {-# INLINE enumerateFromTo #-}; \
795+ enumerateFromTo = enumerateFromToSmall; \
796+ {-# INLINE enumerateFromThenTo #-}; \
797+ enumerateFromThenTo = enumerateFromThenToSmall }
798+
799+ENUMERABLE_BOUNDED_SMALL(())
800+ENUMERABLE_BOUNDED_SMALL(Bool)
801+ENUMERABLE_BOUNDED_SMALL(Ordering)
802+ENUMERABLE_BOUNDED_SMALL(Char)
803+
804+-- For bounded Integral Enum types, may be larger than Int.
805+#define ENUMERABLE_BOUNDED_INTEGRAL(INTEGRAL_TYPE) \
806+instance Enumerable INTEGRAL_TYPE where { \
807+ {-# INLINE enumerateFrom #-}; \
808+ enumerateFrom = enumerateFromIntegral; \
809+ {-# INLINE enumerateFromThen #-}; \
810+ enumerateFromThen = enumerateFromThenIntegral; \
811+ {-# INLINE enumerateFromTo #-}; \
812+ enumerateFromTo = enumerateFromToIntegral; \
813+ {-# INLINE enumerateFromThenTo #-}; \
814+ enumerateFromThenTo = enumerateFromThenToIntegral }
815+
816+ENUMERABLE_BOUNDED_INTEGRAL(Int)
817+ENUMERABLE_BOUNDED_INTEGRAL(Int8)
818+ENUMERABLE_BOUNDED_INTEGRAL(Int16)
819+ENUMERABLE_BOUNDED_INTEGRAL(Int32)
820+ENUMERABLE_BOUNDED_INTEGRAL(Int64)
821+ENUMERABLE_BOUNDED_INTEGRAL(Word)
822+ENUMERABLE_BOUNDED_INTEGRAL(Word8)
823+ENUMERABLE_BOUNDED_INTEGRAL(Word16)
824+ENUMERABLE_BOUNDED_INTEGRAL(Word32)
825+ENUMERABLE_BOUNDED_INTEGRAL(Word64)
826+
827+-- For unbounded Integral Enum types.
828+#define ENUMERABLE_UNBOUNDED_INTEGRAL(INTEGRAL_TYPE) \
829+instance Enumerable INTEGRAL_TYPE where { \
830+ {-# INLINE enumerateFrom #-}; \
831+ enumerateFrom from = enumerateFromStepIntegral from 1; \
832+ {-# INLINE enumerateFromThen #-}; \
833+ enumerateFromThen from next = \
834+ enumerateFromStepIntegral from (next - from); \
835+ {-# INLINE enumerateFromTo #-}; \
836+ enumerateFromTo = enumerateFromToIntegral; \
837+ {-# INLINE enumerateFromThenTo #-}; \
838+ enumerateFromThenTo = enumerateFromThenToIntegral }
839+
840+ENUMERABLE_UNBOUNDED_INTEGRAL(Integer)
841+ENUMERABLE_UNBOUNDED_INTEGRAL(Natural)
842+
843+#define ENUMERABLE_FRACTIONAL(FRACTIONAL_TYPE,CONSTRAINT) \
844+instance (CONSTRAINT) => Enumerable FRACTIONAL_TYPE where { \
845+ {-# INLINE enumerateFrom #-}; \
846+ enumerateFrom = enumerateFromFractional; \
847+ {-# INLINE enumerateFromThen #-}; \
848+ enumerateFromThen = enumerateFromThenFractional; \
849+ {-# INLINE enumerateFromTo #-}; \
850+ enumerateFromTo = enumerateFromToFractional; \
851+ {-# INLINE enumerateFromThenTo #-}; \
852+ enumerateFromThenTo = enumerateFromThenToFractional }
853+
854+ENUMERABLE_FRACTIONAL(Float,)
855+ENUMERABLE_FRACTIONAL(Double,)
856+ENUMERABLE_FRACTIONAL((Fixed a),HasResolution a)
857+ENUMERABLE_FRACTIONAL((Ratio a),Integral a)
858+
859+instance Enumerable a => Enumerable (Identity a) where
860+ {-# INLINE enumerateFrom #-}
861+ enumerateFrom (Identity from) =
862+ fmap Identity $ enumerateFrom from
863+ {-# INLINE enumerateFromThen #-}
864+ enumerateFromThen (Identity from) (Identity next) =
865+ fmap Identity $ enumerateFromThen from next
866+ {-# INLINE enumerateFromTo #-}
867+ enumerateFromTo (Identity from) (Identity to) =
868+ fmap Identity $ enumerateFromTo from to
869+ {-# INLINE enumerateFromThenTo #-}
870+ enumerateFromThenTo (Identity from) (Identity next) (Identity to) =
871+ fmap Identity
872+ $ enumerateFromThenTo from next to
873+
874+-- TODO
875+{-
876+instance Enumerable a => Enumerable (Last a)
877+instance Enumerable a => Enumerable (First a)
878+instance Enumerable a => Enumerable (Max a)
879+instance Enumerable a => Enumerable (Min a)
880+instance Enumerable a => Enumerable (Const a b)
881+instance Enumerable (f a) => Enumerable (Alt f a)
882+instance Enumerable (f a) => Enumerable (Ap f a)
883+-}
375------------------------------------------------------------------------------
884------------------------------------------------------------------------------
376-- Time Enumeration
885-- Time Enumeration
377------------------------------------------------------------------------------
886------------------------------------------------------------------------------
378
887
888+-- | @timesWith g@ returns a stream of time value tuples. The first component
889+-- of the tuple is an absolute time reference (epoch) denoting the start of the
890+-- stream and the second component is a time relative to the reference.
891+--
892+-- The argument @g@ specifies the granularity of the relative time in seconds.
893+-- A lower granularity clock gives higher precision but is more expensive in
894+-- terms of CPU usage. Any granularity lower than 1 ms is treated as 1 ms.
895+--
896+-- >>> import Control.Concurrent (threadDelay)
897+-- >>> f = Fold.drainMapM (\x -> print x >> threadDelay 1000000)
898+-- >>> Stream.fold f $ Stream.take 3 $ Stream.timesWith 0.01
899+-- (AbsTime (TimeSpec {sec = ..., nsec = ...}),RelTime64 (NanoSecond64 ...))
900+-- (AbsTime (TimeSpec {sec = ..., nsec = ...}),RelTime64 (NanoSecond64 ...))
901+-- (AbsTime (TimeSpec {sec = ..., nsec = ...}),RelTime64 (NanoSecond64 ...))
902+--
903+-- Note: This API is not safe on 32-bit machines.
904+--
905+-- /Pre-release/
906+--
379−{-# INLINE_NORMAL times #-}
907+{-# INLINE_NORMAL timesWith #-}
380−times :: MonadIO m => Double -> Stream m (AbsTime, RelTime64)
908+timesWith :: MonadIO m => Double -> Stream m (AbsTime, RelTime64)
381−times g = Stream step Nothing
909+timesWith g = Stream step Nothing
382
910
383 where
911 where
384
912
@@ -395,6 +923,125 @@ times g = Stream step Nothing
395 -- floating precision time
923 -- floating precision time
396 return $ Yield (toAbsTime t0, toRelTime64 (a - t0)) s
924 return $ Yield (toAbsTime t0, toRelTime64 (a - t0)) s
397
925
926+-- | @absTimesWith g@ returns a stream of absolute timestamps using a clock of
927+-- granularity @g@ specified in seconds. A low granularity clock is more
928+-- expensive in terms of CPU usage. Any granularity lower than 1 ms is treated
929+-- as 1 ms.
930+--
931+-- >>> f = Fold.drainMapM print
932+-- >>> Stream.fold f $ Stream.delayPre 1 $ Stream.take 3 $ Stream.absTimesWith 0.01
933+-- AbsTime (TimeSpec {sec = ..., nsec = ...})
934+-- AbsTime (TimeSpec {sec = ..., nsec = ...})
935+-- AbsTime (TimeSpec {sec = ..., nsec = ...})
936+--
937+-- Note: This API is not safe on 32-bit machines.
938+--
939+-- /Pre-release/
940+--
941+{-# INLINE absTimesWith #-}
942+absTimesWith :: MonadIO m => Double -> Stream m AbsTime
943+absTimesWith = fmap (uncurry addToAbsTime64) . timesWith
944+
945+-- | @relTimesWith g@ returns a stream of relative time values starting from 0,
946+-- using a clock of granularity @g@ specified in seconds. A low granularity
947+-- clock is more expensive in terms of CPU usage. Any granularity lower than 1
948+-- ms is treated as 1 ms.
949+--
950+-- >>> f = Fold.drainMapM print
951+-- >>> Stream.fold f $ Stream.delayPre 1 $ Stream.take 3 $ Stream.relTimesWith 0.01
952+-- RelTime64 (NanoSecond64 ...)
953+-- RelTime64 (NanoSecond64 ...)
954+-- RelTime64 (NanoSecond64 ...)
955+--
956+-- Note: This API is not safe on 32-bit machines.
957+--
958+-- /Pre-release/
959+--
960+{-# INLINE relTimesWith #-}
961+relTimesWith :: MonadIO m => Double -> Stream m RelTime64
962+relTimesWith = fmap snd . timesWith
963+
964+-- | @times@ returns a stream of time value tuples with clock of 10 ms
965+-- granularity. The first component of the tuple is an absolute time reference
966+-- (epoch) denoting the start of the stream and the second component is a time
967+-- relative to the reference.
968+--
969+-- >>> f = Fold.drainMapM (\x -> print x >> threadDelay 1000000)
970+-- >>> Stream.fold f $ Stream.take 3 $ Stream.times
971+-- (AbsTime (TimeSpec {sec = ..., nsec = ...}),RelTime64 (NanoSecond64 ...))
972+-- (AbsTime (TimeSpec {sec = ..., nsec = ...}),RelTime64 (NanoSecond64 ...))
973+-- (AbsTime (TimeSpec {sec = ..., nsec = ...}),RelTime64 (NanoSecond64 ...))
974+--
975+-- Note: This API is not safe on 32-bit machines.
976+--
977+-- /Pre-release/
978+--
979+{-# INLINE times #-}
980+times :: MonadIO m => Stream m (AbsTime, RelTime64)
981+times = timesWith 0.01
982+
983+-- | @absTimes@ returns a stream of absolute timestamps using a clock of 10 ms
984+-- granularity.
985+--
986+-- >>> f = Fold.drainMapM print
987+-- >>> Stream.fold f $ Stream.delayPre 1 $ Stream.take 3 $ Stream.absTimes
988+-- AbsTime (TimeSpec {sec = ..., nsec = ...})
989+-- AbsTime (TimeSpec {sec = ..., nsec = ...})
990+-- AbsTime (TimeSpec {sec = ..., nsec = ...})
991+--
992+-- Note: This API is not safe on 32-bit machines.
993+--
994+-- /Pre-release/
995+--
996+{-# INLINE absTimes #-}
997+absTimes :: MonadIO m => Stream m AbsTime
998+absTimes = fmap (uncurry addToAbsTime64) times
999+
1000+-- | @relTimes@ returns a stream of relative time values starting from 0,
1001+-- using a clock of granularity 10 ms.
1002+--
1003+-- >>> f = Fold.drainMapM print
1004+-- >>> Stream.fold f $ Stream.delayPre 1 $ Stream.take 3 $ Stream.relTimes
1005+-- RelTime64 (NanoSecond64 ...)
1006+-- RelTime64 (NanoSecond64 ...)
1007+-- RelTime64 (NanoSecond64 ...)
1008+--
1009+-- Note: This API is not safe on 32-bit machines.
1010+--
1011+-- /Pre-release/
1012+--
1013+{-# INLINE relTimes #-}
1014+relTimes :: MonadIO m => Stream m RelTime64
1015+relTimes = fmap snd times
1016+
1017+-- | @durations g@ returns a stream of relative time values measuring the time
1018+-- elapsed since the immediate predecessor element of the stream was generated.
1019+-- The first element of the stream is always 0. @durations@ uses a clock of
1020+-- granularity @g@ specified in seconds. A low granularity clock is more
1021+-- expensive in terms of CPU usage. The minimum granularity is 1 millisecond.
1022+-- Durations lower than 1 ms will be 0.
1023+--
1024+-- Note: This API is not safe on 32-bit machines.
1025+--
1026+-- /Unimplemented/
1027+--
1028+{-# INLINE durations #-}
1029+durations :: -- Monad m =>
1030+ Double -> t m RelTime64
1031+durations = undefined
1032+
1033+-- | Generate a singleton event at or after the specified absolute time. Note
1034+-- that this is different from a threadDelay, a threadDelay starts from the
1035+-- time when the action is evaluated, whereas if we use AbsTime based timeout
1036+-- it will immediately expire if the action is evaluated too late.
1037+--
1038+-- /Unimplemented/
1039+--
1040+{-# INLINE timeout #-}
1041+timeout :: -- Monad m =>
1042+ AbsTime -> t m ()
1043+timeout = undefined
1044+
398-------------------------------------------------------------------------------
1045-------------------------------------------------------------------------------
399-- From Generators
1046-- From Generators
400-------------------------------------------------------------------------------
1047-------------------------------------------------------------------------------
@@ -435,6 +1082,22 @@ generate n gen = generateM n (return . gen)
435-- Iteration
1082-- Iteration
436-------------------------------------------------------------------------------
1083-------------------------------------------------------------------------------
437
1084
1085+-- |
1086+-- >>> iterateM f m = m >>= \a -> return a `Stream.consM` iterateM f (f a)
1087+--
1088+-- Generate an infinite stream with the first element generated by the action
1089+-- @m@ and each successive element derived by applying the monadic function
1090+-- @f@ on the previous element.
1091+--
1092+-- >>> :{
1093+-- Stream.iterateM (\x -> print x >> return (x + 1)) (return 0)
1094+-- & Stream.take 3
1095+-- & Stream.fold Fold.toList
1096+-- :}
1097+-- 0
1098+-- 1
1099+-- [0,1,2]
1100+--
438{-# INLINE_NORMAL iterateM #-}
1101{-# INLINE_NORMAL iterateM #-}
439iterateM :: Monad m => (a -> m a) -> m a -> Stream m a
1102iterateM :: Monad m => (a -> m a) -> m a -> Stream m a
440#ifdef USE_UNFOLDS_EVERYWHERE
1103#ifdef USE_UNFOLDS_EVERYWHERE
@@ -443,6 +1106,16 @@ iterateM step = unfold (Unfold.iterateM step)
443iterateM step = Stream (\_ st -> st >>= \(!x) -> return $ Yield x (step x))
1106iterateM step = Stream (\_ st -> st >>= \(!x) -> return $ Yield x (step x))
444#endif
1107#endif
445
1108
1109+-- |
1110+-- >>> iterate f x = x `Stream.cons` iterate f x
1111+--
1112+-- Generate an infinite stream with @x@ as the first element and each
1113+-- successive element derived by applying the function @f@ on the previous
1114+-- element.
1115+--
1116+-- >>> Stream.fold Fold.toList $ Stream.take 5 $ Stream.iterate (+1) 1
1117+-- [1,2,3,4,5]
1118+--
446{-# INLINE_NORMAL iterate #-}
1119{-# INLINE_NORMAL iterate #-}
447iterate :: Monad m => (a -> a) -> a -> Stream m a
1120iterate :: Monad m => (a -> a) -> a -> Stream m a
448iterate step st = iterateM (return . step) (return st)
1121iterate step st = iterateM (return . step) (return st)
@@ -464,12 +1137,39 @@ fromListM = Stream step
464 step _ [] = return Stop
1137 step _ [] = return Stop
465#endif
1138#endif
466
1139
1140+-- |
1141+-- >>> fromFoldable = Prelude.foldr Stream.cons Stream.nil
1142+--
1143+-- Construct a stream from a 'Foldable' containing pure values:
1144+--
1145+-- /WARNING: O(n^2), suitable only for a small number of
1146+-- elements in the stream/
1147+--
1148+{-# INLINE fromFoldable #-}
1149+fromFoldable :: (Monad m, Foldable f) => f a -> Stream m a
1150+fromFoldable = Prelude.foldr cons nil
1151+
1152+-- |
1153+-- >>> fromFoldableM = Prelude.foldr Stream.consM Stream.nil
1154+--
1155+-- Construct a stream from a 'Foldable' containing pure values:
1156+--
1157+-- /WARNING: O(n^2), suitable only for a small number of
1158+-- elements in the stream/
1159+--
1160+{-# INLINE fromFoldableM #-}
1161+fromFoldableM :: (Monad m, Foldable f) => f (m a) -> Stream m a
1162+fromFoldableM = Prelude.foldr consM nil
1163+
467-------------------------------------------------------------------------------
1164-------------------------------------------------------------------------------
468-- From pointers
1165-- From pointers
469-------------------------------------------------------------------------------
1166-------------------------------------------------------------------------------
470
1167
471−-- | Read an infinite stream from a pointer, advancing the pointer as needed.
1168+-- | Keep reading 'Storable' elements from 'Ptr' onwards.
1169+--
472−-- The caller is responsible to end the stream safely.
1170+-- /Unsafe:/ The caller is responsible for safe addressing.
1171+--
1172+-- /Pre-release/
473{-# INLINE fromPtr #-}
1173{-# INLINE fromPtr #-}
474fromPtr :: forall m a. (MonadIO m, Storable a) => Ptr a -> Stream m a
1174fromPtr :: forall m a. (MonadIO m, Storable a) => Ptr a -> Stream m a
475fromPtr = Stream step
1175fromPtr = Stream step
@@ -480,3 +1180,32 @@ fromPtr = Stream step
480 step _ p = do
1180 step _ p = do
481 x <- liftIO $ peek p
1181 x <- liftIO $ peek p
482 return $ Yield x (PTR_NEXT(p, a))
1182 return $ Yield x (PTR_NEXT(p, a))
1183+
1184+-- | Take @n@ 'Storable' elements starting from 'Ptr' onwards.
1185+--
1186+-- >>> fromPtrN n = Stream.take n . Stream.fromPtr
1187+--
1188+-- /Unsafe:/ The caller is responsible for safe addressing.
1189+--
1190+-- /Pre-release/
1191+{-# INLINE fromPtrN #-}
1192+fromPtrN :: (MonadIO m, Storable a) => Int -> Ptr a -> Stream m a
1193+fromPtrN n = take n . fromPtr
1194+
1195+-- | Read bytes from an 'Addr#' until a 0 byte is encountered, the 0 byte is
1196+-- not included in the stream.
1197+--
1198+-- >>> fromByteStr# addr = Stream.takeWhile (/= 0) $ Stream.fromPtr $ Ptr addr
1199+--
1200+-- /Unsafe:/ The caller is responsible for safe addressing.
1201+--
1202+-- Note that this is completely safe when reading from Haskell string
1203+-- literals because they are guaranteed to be NULL terminated:
1204+--
1205+-- >>> Stream.fold Fold.toList $ Stream.fromByteStr# "\1\2\3\0"#
1206+-- [1,2,3]
1207+--
1208+{-# INLINE fromByteStr# #-}
1209+fromByteStr# :: MonadIO m => Addr# -> Stream m Word8
1210+fromByteStr# addr =
1211+ takeWhile (/= 0) $ fromPtr $ Ptr addr
core/src/Streamly/Internal/Data/Stream/StreamD/Lift.hs+36−8
@@ -11,8 +11,8 @@
11module Streamly.Internal.Data.Stream.StreamD.Lift
11module Streamly.Internal.Data.Stream.StreamD.Lift
12 (
12 (
13 -- * Generalize Inner Monad
13 -- * Generalize Inner Monad
14− hoist
14+ morphInner
15− , generally -- XXX generalize
15+ , generalizeInner
16
16
17 -- * Transform Inner Monad
17 -- * Transform Inner Monad
18 , liftInnerWith
18 , liftInnerWith
@@ -28,13 +28,26 @@ import Streamly.Internal.Data.SVar.Type (adaptState)
28
28
29import Streamly.Internal.Data.Stream.StreamD.Type
29import Streamly.Internal.Data.Stream.StreamD.Type
30
30
31+-- $setup
32+-- >>> :m
33+-- >>> import Data.Functor.Identity (runIdentity)
34+-- >>> import Streamly.Internal.Data.Stream as Stream
35+
31-------------------------------------------------------------------------------
36-------------------------------------------------------------------------------
32-- Generalize Inner Monad
37-- Generalize Inner Monad
33-------------------------------------------------------------------------------
38-------------------------------------------------------------------------------
34
39
40+-- | Transform the inner monad of a stream using a natural transformation.
41+--
42+-- Example, generalize the inner monad from Identity to any other:
43+--
44+-- >>> generalizeInner = Stream.morphInner (return . runIdentity)
45+--
46+-- Also known as hoist.
47+--
35−{-# INLINE_NORMAL hoist #-}
48+{-# INLINE_NORMAL morphInner #-}
36−hoist :: Monad n => (forall x. m x -> n x) -> Stream m a -> Stream n a
49+morphInner :: Monad n => (forall x. m x -> n x) -> Stream m a -> Stream n a
37−hoist f (Stream step state) = Stream step' state
50+morphInner f (Stream step state) = Stream step' state
38 where
51 where
39 {-# INLINE_LATE step' #-}
52 {-# INLINE_LATE step' #-}
40 step' gst st = do
53 step' gst st = do
@@ -44,14 +57,23 @@ hoist f (Stream step state) = Stream step' state
44 Skip s -> Skip s
57 Skip s -> Skip s
45 Stop -> Stop
58 Stop -> Stop
46
59
47−{-# INLINE generally #-}
60+-- | Generalize the inner monad of the stream from 'Identity' to any monad.
61+--
62+-- Definition:
63+--
64+-- >>> generalizeInner = Stream.morphInner (return . runIdentity)
65+--
66+{-# INLINE generalizeInner #-}
48−generally :: Monad m => Stream Identity a -> Stream m a
67+generalizeInner :: Monad m => Stream Identity a -> Stream m a
49−generally = hoist (return . runIdentity)
68+generalizeInner = morphInner (return . runIdentity)
50
69
51-------------------------------------------------------------------------------
70-------------------------------------------------------------------------------
52-- Transform Inner Monad
71-- Transform Inner Monad
53-------------------------------------------------------------------------------
72-------------------------------------------------------------------------------
54
73
74+-- | Lift the inner monad @m@ of a stream @Stream m a@ to @t m@ using the
75+-- supplied lift function.
76+--
55{-# INLINE_NORMAL liftInnerWith #-}
77{-# INLINE_NORMAL liftInnerWith #-}
56liftInnerWith :: (Monad (t m)) =>
78liftInnerWith :: (Monad (t m)) =>
57 (forall b. m b -> t m b) -> Stream m a -> Stream (t m) a
79 (forall b. m b -> t m b) -> Stream m a -> Stream (t m) a
@@ -67,6 +89,8 @@ liftInnerWith lift (Stream step state) = Stream step1 state
67 Skip s -> Skip s
89 Skip s -> Skip s
68 Stop -> Stop
90 Stop -> Stop
69
91
92+-- | Evaluate the inner monad of a stream using the supplied runner function.
93+--
70{-# INLINE_NORMAL runInnerWith #-}
94{-# INLINE_NORMAL runInnerWith #-}
71runInnerWith :: Monad m =>
95runInnerWith :: Monad m =>
72 (forall b. t m b -> m b) -> Stream (t m) a -> Stream m a
96 (forall b. t m b -> m b) -> Stream (t m) a -> Stream m a
@@ -82,6 +106,10 @@ runInnerWith run (Stream step state) = Stream step1 state
82 Skip s -> Skip s
106 Skip s -> Skip s
83 Stop -> Stop
107 Stop -> Stop
84
108
109+-- | Evaluate the inner monad of a stream using the supplied stateful runner
110+-- function and the initial state. The state returned by an invocation of the
111+-- runner is supplied as input state to the next invocation.
112+--
85{-# INLINE_NORMAL runInnerWithState #-}
113{-# INLINE_NORMAL runInnerWithState #-}
86runInnerWithState :: Monad m =>
114runInnerWithState :: Monad m =>
87 (forall b. s -> t m b -> m (b, s))
115 (forall b. s -> t m b -> m (b, s))
core/src/Streamly/Internal/Data/Stream/StreamD/Nesting.hs+546−89
@@ -41,17 +41,17 @@ module Streamly.Internal.Data.Stream.StreamD.Nesting
41
41
42 -- *** Interleaving
42 -- *** Interleaving
43 -- | Interleave elements from two streams alternately. A special case of
43 -- | Interleave elements from two streams alternately. A special case of
44− -- unfoldManyInterleave.
44+ -- unfoldInterleave.
45 , InterleaveState(..)
45 , InterleaveState(..)
46 , interleave
46 , interleave
47 , interleaveMin
47 , interleaveMin
48− , interleaveSuffix
48+ , interleaveFst
49− , interleaveInfix
49+ , interleaveFstSuffix
50
50
51 -- *** Scheduling
51 -- *** Scheduling
52 -- | Execute streams alternately irrespective of whether they generate
52 -- | Execute streams alternately irrespective of whether they generate
53 -- elements or not. Note 'interleave' would execute a stream until it
53 -- elements or not. Note 'interleave' would execute a stream until it
54− -- yields an element. A special case of unfoldManyRoundRobin.
54+ -- yields an element. A special case of unfoldRoundRobin.
55 , roundRobin -- interleaveFair?/ParallelFair
55 , roundRobin -- interleaveFair?/ParallelFair
56
56
57 -- *** Zipping
57 -- *** Zipping
@@ -63,6 +63,8 @@ module Streamly.Internal.Data.Stream.StreamD.Nesting
63 -- | Interleave elements from two streams based on a condition.
63 -- | Interleave elements from two streams based on a condition.
64 , mergeBy
64 , mergeBy
65 , mergeByM
65 , mergeByM
66+ , mergeMinBy
67+ , mergeFstBy
66
68
67 -- ** Combine N Streams
69 -- ** Combine N Streams
68 -- | Functions generally ending in these shapes:
70 -- | Functions generally ending in these shapes:
@@ -85,20 +87,24 @@ module Streamly.Internal.Data.Stream.StreamD.Nesting
85 -- gintercalate.
87 -- gintercalate.
86 , unfoldMany
88 , unfoldMany
87 , ConcatUnfoldInterleaveState (..)
89 , ConcatUnfoldInterleaveState (..)
88− , unfoldManyInterleave
90+ , unfoldInterleave
89− , unfoldManyRoundRobin
91+ , unfoldRoundRobin
90
92
91 -- *** Interpose
93 -- *** Interpose
92 -- | Like unfoldMany but intersperses an effect between the streams. A
94 -- | Like unfoldMany but intersperses an effect between the streams. A
93 -- special case of gintercalate.
95 -- special case of gintercalate.
94 , interpose
96 , interpose
97+ , interposeM
95 , interposeSuffix
98 , interposeSuffix
99+ , interposeSuffixM
96
100
97 -- *** Intercalate
101 -- *** Intercalate
98 -- | Like unfoldMany but intersperses streams from another source between
102 -- | Like unfoldMany but intersperses streams from another source between
99 -- the streams from the first source.
103 -- the streams from the first source.
100 , gintercalate
104 , gintercalate
101 , gintercalateSuffix
105 , gintercalateSuffix
106+ , intercalate
107+ , intercalateSuffix
102
108
103 -- * Eliminate
109 -- * Eliminate
104 -- | Folding and Parsing chunks of streams to eliminate nested streams.
110 -- | Folding and Parsing chunks of streams to eliminate nested streams.
@@ -113,6 +119,7 @@ module Streamly.Internal.Data.Stream.StreamD.Nesting
113 -- | Apply folds on a stream.
119 -- | Apply folds on a stream.
114 , foldMany
120 , foldMany
115 , refoldMany
121 , refoldMany
122+ , foldSequence
116 , foldIterateM
123 , foldIterateM
117 , refoldIterateM
124 , refoldIterateM
118
125
@@ -123,7 +130,11 @@ module Streamly.Internal.Data.Stream.StreamD.Nesting
123 -- splitting the stream and then folds each such split to single value in
130 -- splitting the stream and then folds each such split to single value in
124 -- the output stream.
131 -- the output stream.
125 , parseMany
132 , parseMany
133+ , parseManyD
134+ , parseSequence
135+ , parseManyTill
126 , parseIterate
136 , parseIterate
137+ , parseIterateD
127
138
128 -- ** Grouping
139 -- ** Grouping
129 -- | Group segments of a stream and fold. Special case of parsing.
140 -- | Group segments of a stream and fold. Special case of parsing.
@@ -138,11 +149,21 @@ module Streamly.Internal.Data.Stream.StreamD.Nesting
138 , splitOnSuffixSeq
149 , splitOnSuffixSeq
139 , sliceOnSuffix
150 , sliceOnSuffix
140
151
152+ -- XXX Implement these as folds or parsers instead.
153+ , splitOnSuffixSeqAny
154+ , splitOnPrefix
155+ , splitOnAny
156+
141 -- * Transform (Nested Containers)
157 -- * Transform (Nested Containers)
142 -- | Opposite to compact in ArrayStream
158 -- | Opposite to compact in ArrayStream
143 , splitInnerBy
159 , splitInnerBy
144 , splitInnerBySuffix
160 , splitInnerBySuffix
145 , intersectBySorted
161 , intersectBySorted
162+
163+ -- * Reduce By Streams
164+ , dropPrefix
165+ , dropInfix
166+ , dropSuffix
146 )
167 )
147where
168where
148
169
@@ -152,7 +173,6 @@ where
152import Control.Exception (assert)
173import Control.Exception (assert)
153import Control.Monad.IO.Class (MonadIO(..))
174import Control.Monad.IO.Class (MonadIO(..))
154import Data.Bits (shiftR, shiftL, (.|.), (.&.))
175import Data.Bits (shiftR, shiftL, (.|.), (.&.))
155−import Data.Functor.Identity ( Identity )
156import Data.Proxy (Proxy(..))
176import Data.Proxy (Proxy(..))
157import Data.Word (Word32)
177import Data.Word (Word32)
158import Foreign.Storable (Storable, peek)
178import Foreign.Storable (Storable, peek)
@@ -175,19 +195,49 @@ import qualified Streamly.Internal.Data.Parser as PR
175import qualified Streamly.Internal.Data.Parser.ParserD as PRD
195import qualified Streamly.Internal.Data.Parser.ParserD as PRD
176import qualified Streamly.Internal.Data.Ring.Unboxed as RB
196import qualified Streamly.Internal.Data.Ring.Unboxed as RB
177
197
198+import Streamly.Internal.Data.Stream.StreamD.Transform
199+ (intersperse, intersperseMSuffix)
178import Streamly.Internal.Data.Stream.StreamD.Type
200import Streamly.Internal.Data.Stream.StreamD.Type
179
201
180import Prelude hiding (concatMap, mapM, zipWith)
202import Prelude hiding (concatMap, mapM, zipWith)
181
203
204+-- $setup
205+-- >>> :m
206+-- >>> import Data.Either (either)
207+-- >>> import Data.IORef
208+-- >>> import Streamly.Internal.Data.Stream (Stream)
209+-- >>> import Prelude hiding (zipWith, concatMap, concat)
210+-- >>> import qualified Streamly.Data.Array as Array
211+-- >>> import qualified Streamly.Internal.Data.Fold as Fold
212+-- >>> import qualified Streamly.Internal.Data.Stream as Stream
213+-- >>> import qualified Streamly.Internal.Data.Unfold as Unfold
214+-- >>> import qualified Streamly.Internal.Data.Parser as Parser
215+-- >>> import qualified Streamly.Internal.FileSystem.Dir as Dir
216+--
217+
182------------------------------------------------------------------------------
218------------------------------------------------------------------------------
183-- Appending
219-- Appending
184------------------------------------------------------------------------------
220------------------------------------------------------------------------------
185
221
186data AppendState s1 s2 = AppendFirst s1 | AppendSecond s2
222data AppendState s1 s2 = AppendFirst s1 | AppendSecond s2
187
223
188−-- Note that this could be much faster compared to the CPS stream. However, as
224+-- | Fuses two streams sequentially, yielding all elements from the first
189−-- the number of streams being composed increases this may become expensive.
225+-- stream, and then all elements from the second stream.
190−-- Need to see where the breaking point is between the two.
226+--
227+-- >>> s1 = Stream.fromList [1,2]
228+-- >>> s2 = Stream.fromList [3,4]
229+-- >>> Stream.fold Fold.toList $ s1 `Stream.append` s2
230+-- [1,2,3,4]
231+--
232+-- This function should not be used to dynamically construct a stream. If a
233+-- stream is constructed by successive use of this function it would take
234+-- quadratic time complexity to consume the stream.
235+--
236+-- This function should only be used to statically fuse a stream with another
237+-- stream. Do not use this recursively or where it cannot be inlined.
238+--
239+-- See "Streamly.Data.Stream.StreamK" for an 'append' that can be used to
240+-- construct a stream recursively.
191--
241--
192{-# INLINE_NORMAL append #-}
242{-# INLINE_NORMAL append #-}
193append :: Monad m => Stream m a -> Stream m a -> Stream m a
243append :: Monad m => Stream m a -> Stream m a -> Stream m a
@@ -218,6 +268,15 @@ append (Stream step1 state1) (Stream step2 state2) =
218data InterleaveState s1 s2 = InterleaveFirst s1 s2 | InterleaveSecond s1 s2
268data InterleaveState s1 s2 = InterleaveFirst s1 s2 | InterleaveSecond s1 s2
219 | InterleaveSecondOnly s2 | InterleaveFirstOnly s1
269 | InterleaveSecondOnly s2 | InterleaveFirstOnly s1
220
270
271+-- | Interleaves two streams, yielding one element from each stream
272+-- alternately. When one stream stops the rest of the other stream is used in
273+-- the output stream.
274+--
275+-- When joining many streams in a left associative manner earlier streams will
276+-- get exponential priority than the ones joining later. Because of exponential
277+-- weighting it can be used with 'concatMapWith' even on a large number of
278+-- streams.
279+--
221{-# INLINE_NORMAL interleave #-}
280{-# INLINE_NORMAL interleave #-}
222interleave :: Monad m => Stream m a -> Stream m a -> Stream m a
281interleave :: Monad m => Stream m a -> Stream m a -> Stream m a
223interleave (Stream step1 state1) (Stream step2 state2) =
282interleave (Stream step1 state1) (Stream step2 state2) =
@@ -254,6 +313,9 @@ interleave (Stream step1 state1) (Stream step2 state2) =
254 Skip s -> Skip (InterleaveSecondOnly s)
313 Skip s -> Skip (InterleaveSecondOnly s)
255 Stop -> Stop
314 Stop -> Stop
256
315
316+-- | Like `interleave` but stops interleaving as soon as any of the two streams
317+-- stops.
318+--
257{-# INLINE_NORMAL interleaveMin #-}
319{-# INLINE_NORMAL interleaveMin #-}
258interleaveMin :: Monad m => Stream m a -> Stream m a -> Stream m a
320interleaveMin :: Monad m => Stream m a -> Stream m a -> Stream m a
259interleaveMin (Stream step1 state1) (Stream step2 state2) =
321interleaveMin (Stream step1 state1) (Stream step2 state2) =
@@ -279,9 +341,28 @@ interleaveMin (Stream step1 state1) (Stream step2 state2) =
279 step _ (InterleaveFirstOnly _) = undefined
341 step _ (InterleaveFirstOnly _) = undefined
280 step _ (InterleaveSecondOnly _) = undefined
342 step _ (InterleaveSecondOnly _) = undefined
281
343
344+-- | Interleaves the outputs of two streams, yielding elements from each stream
345+-- alternately, starting from the first stream. As soon as the first stream
346+-- finishes, the output stops, discarding the remaining part of the second
347+-- stream. In this case, the last element in the resulting stream would be from
348+-- the second stream. If the second stream finishes early then the first stream
349+-- still continues to yield elements until it finishes.
350+--
351+-- >>> :set -XOverloadedStrings
352+-- >>> import Data.Functor.Identity (Identity)
353+-- >>> Stream.interleaveFstSuffix "abc" ",,,," :: Stream Identity Char
354+-- fromList "a,b,c,"
355+-- >>> Stream.interleaveFstSuffix "abc" "," :: Stream Identity Char
356+-- fromList "a,bc"
357+--
358+-- 'interleaveFstSuffix' is a dual of 'interleaveFst'.
359+--
360+-- Do not use dynamically.
361+--
362+-- /Pre-release/
282−{-# INLINE_NORMAL interleaveSuffix #-}
363+{-# INLINE_NORMAL interleaveFstSuffix #-}
283−interleaveSuffix :: Monad m => Stream m a -> Stream m a -> Stream m a
364+interleaveFstSuffix :: Monad m => Stream m a -> Stream m a -> Stream m a
284−interleaveSuffix (Stream step1 state1) (Stream step2 state2) =
365+interleaveFstSuffix (Stream step1 state1) (Stream step2 state2) =
285 Stream step (InterleaveFirst state1 state2)
366 Stream step (InterleaveFirst state1 state2)
286
367
287 where
368 where
@@ -317,9 +398,28 @@ data InterleaveInfixState s1 s2 a
317 | InterleaveInfixFirstYield s1 s2 a
398 | InterleaveInfixFirstYield s1 s2 a
318 | InterleaveInfixFirstOnly s1
399 | InterleaveInfixFirstOnly s1
319
400
401+-- | Interleaves the outputs of two streams, yielding elements from each stream
402+-- alternately, starting from the first stream and ending at the first stream.
403+-- If the second stream is longer than the first, elements from the second
404+-- stream are infixed with elements from the first stream. If the first stream
405+-- is longer then it continues yielding elements even after the second stream
406+-- has finished.
407+--
408+-- >>> :set -XOverloadedStrings
409+-- >>> import Data.Functor.Identity (Identity)
410+-- >>> Stream.interleaveFst "abc" ",,,," :: Stream Identity Char
411+-- fromList "a,b,c"
412+-- >>> Stream.interleaveFst "abc" "," :: Stream Identity Char
413+-- fromList "a,bc"
414+--
415+-- 'interleaveFst' is a dual of 'interleaveFstSuffix'.
416+--
417+-- Do not use dynamically.
418+--
419+-- /Pre-release/
320−{-# INLINE_NORMAL interleaveInfix #-}
420+{-# INLINE_NORMAL interleaveFst #-}
321−interleaveInfix :: Monad m => Stream m a -> Stream m a -> Stream m a
421+interleaveFst :: Monad m => Stream m a -> Stream m a -> Stream m a
322−interleaveInfix (Stream step1 state1) (Stream step2 state2) =
422+interleaveFst (Stream step1 state1) (Stream step2 state2) =
323 Stream step (InterleaveInfixFirst state1 state2)
423 Stream step (InterleaveInfixFirst state1 state2)
324
424
325 where
425 where
@@ -360,6 +460,18 @@ interleaveInfix (Stream step1 state1) (Stream step2 state2) =
360-- Scheduling
460-- Scheduling
361------------------------------------------------------------------------------
461------------------------------------------------------------------------------
362
462
463+-- | Schedule the execution of two streams in a fair round-robin manner,
464+-- executing each stream once, alternately. Execution of a stream may not
465+-- necessarily result in an output, a stream may choose to @Skip@ producing an
466+-- element until later giving the other stream a chance to run. Therefore, this
467+-- combinator fairly interleaves the execution of two streams rather than
468+-- fairly interleaving the output of the two streams. This can be useful in
469+-- co-operative multitasking without using explicit threads. This can be used
470+-- as an alternative to `async`.
471+--
472+-- Do not use dynamically.
473+--
474+-- /Pre-release/
363{-# INLINE_NORMAL roundRobin #-}
475{-# INLINE_NORMAL roundRobin #-}
364roundRobin :: Monad m => Stream m a -> Stream m a -> Stream m a
476roundRobin :: Monad m => Stream m a -> Stream m a -> Stream m a
365roundRobin (Stream step1 state1) (Stream step2 state2) =
477roundRobin (Stream step1 state1) (Stream step2 state2) =
@@ -396,44 +508,38 @@ roundRobin (Stream step1 state1) (Stream step2 state2) =
396 Skip s -> Skip (InterleaveFirstOnly s)
508 Skip s -> Skip (InterleaveFirstOnly s)
397 Stop -> Stop
509 Stop -> Stop
398
510
399−------------------------------------------------------------------------------
400−-- Zipping
401−------------------------------------------------------------------------------
402−
403−{-# INLINE_NORMAL zipWithM #-}
404−zipWithM :: Monad m
405− => (a -> b -> m c) -> Stream m a -> Stream m b -> Stream m c
406−zipWithM f (Stream stepa ta) (Stream stepb tb) = Stream step (ta, tb, Nothing)
407− where
408− {-# INLINE_LATE step #-}
409− step gst (sa, sb, Nothing) = do
410− r <- stepa (adaptState gst) sa
411− return $
412− case r of
413− Yield x sa' -> Skip (sa', sb, Just x)
414− Skip sa' -> Skip (sa', sb, Nothing)
415− Stop -> Stop
416−
417− step gst (sa, sb, Just x) = do
418− r <- stepb (adaptState gst) sb
419− case r of
420− Yield y sb' -> do
421− z <- f x y
422− return $ Yield z (sa, sb', Nothing)
423− Skip sb' -> return $ Skip (sa, sb', Just x)
424− Stop -> return Stop
425−
426−{-# RULES "zipWithM xs xs"
427− forall f xs. zipWithM @Identity f xs xs = mapM (\x -> f x x) xs #-}
428−
429−{-# INLINE zipWith #-}
430−zipWith :: Monad m => (a -> b -> c) -> Stream m a -> Stream m b -> Stream m c
431−zipWith f = zipWithM (\a b -> return (f a b))
432−
433------------------------------------------------------------------------------
511------------------------------------------------------------------------------
434-- Merging
512-- Merging
435------------------------------------------------------------------------------
513------------------------------------------------------------------------------
436
514
515+-- | Like 'mergeBy' but with a monadic comparison function.
516+--
517+-- Merge two streams randomly:
518+--
519+-- @
520+-- > randomly _ _ = randomIO >>= \x -> return $ if x then LT else GT
521+-- > Stream.toList $ Stream.mergeByM randomly (Stream.fromList [1,1,1,1]) (Stream.fromList [2,2,2,2])
522+-- [2,1,2,2,2,1,1,1]
523+-- @
524+--
525+-- Merge two streams in a proportion of 2:1:
526+--
527+-- >>> :{
528+-- do
529+-- let s1 = Stream.fromList [1,1,1,1,1,1]
530+-- s2 = Stream.fromList [2,2,2]
531+-- let proportionately m n = do
532+-- ref <- newIORef $ cycle $ Prelude.concat [Prelude.replicate m LT, Prelude.replicate n GT]
533+-- return $ \_ _ -> do
534+-- r <- readIORef ref
535+-- writeIORef ref $ Prelude.tail r
536+-- return $ Prelude.head r
537+-- f <- proportionately 2 1
538+-- xs <- Stream.fold Fold.toList $ Stream.mergeByM f s1 s2
539+-- print xs
540+-- :}
541+-- [1,1,2,1,1,2,1,1,2]
542+--
437{-# INLINE_NORMAL mergeByM #-}
543{-# INLINE_NORMAL mergeByM #-}
438mergeByM
544mergeByM
439 :: (Monad m)
545 :: (Monad m)
@@ -474,12 +580,43 @@ mergeByM cmp (Stream stepa ta) (Stream stepb tb) =
474
580
475 step _ (Nothing, Nothing, Nothing, Nothing) = return Stop
581 step _ (Nothing, Nothing, Nothing, Nothing) = return Stop
476
582
583+-- | Merge two streams using a comparison function. The head elements of both
584+-- the streams are compared and the smaller of the two elements is emitted, if
585+-- both elements are equal then the element from the first stream is used
586+-- first.
587+--
588+-- If the streams are sorted in ascending order, the resulting stream would
589+-- also remain sorted in ascending order.
590+--
591+-- >>> s1 = Stream.fromList [1,3,5]
592+-- >>> s2 = Stream.fromList [2,4,6,8]
593+-- >>> Stream.fold Fold.toList $ Stream.mergeBy compare s1 s2
594+-- [1,2,3,4,5,6,8]
595+--
477{-# INLINE mergeBy #-}
596{-# INLINE mergeBy #-}
478mergeBy
597mergeBy
479 :: (Monad m)
598 :: (Monad m)
480 => (a -> a -> Ordering) -> Stream m a -> Stream m a -> Stream m a
599 => (a -> a -> Ordering) -> Stream m a -> Stream m a -> Stream m a
481mergeBy cmp = mergeByM (\a b -> return $ cmp a b)
600mergeBy cmp = mergeByM (\a b -> return $ cmp a b)
482
601
602+-- | Like 'mergeByM' but stops merging as soon as any of the two streams stops.
603+--
604+-- /Unimplemented/
605+{-# INLINABLE mergeMinBy #-}
606+mergeMinBy :: -- Monad m =>
607+ (a -> a -> m Ordering) -> Stream m a -> Stream m a -> Stream m a
608+mergeMinBy _f _m1 _m2 = undefined
609+ -- fromStreamD $ D.mergeMinBy f (toStreamD m1) (toStreamD m2)
610+
611+-- | Like 'mergeByM' but stops merging as soon as the first stream stops.
612+--
613+-- /Unimplemented/
614+{-# INLINABLE mergeFstBy #-}
615+mergeFstBy :: -- Monad m =>
616+ (a -> a -> m Ordering) -> Stream m a -> Stream m a -> Stream m a
617+mergeFstBy _f _m1 _m2 = undefined
618+ -- fromStreamK $ D.mergeFstBy f (toStreamD m1) (toStreamD m2)
619+
483-------------------------------------------------------------------------------
620-------------------------------------------------------------------------------
484-- Intersection of sorted streams
621-- Intersection of sorted streams
485-------------------------------------------------------------------------------
622-------------------------------------------------------------------------------
@@ -551,17 +688,28 @@ data ConcatUnfoldInterleaveState o i =
551-- Maybe we can configure the behavior.
688-- Maybe we can configure the behavior.
552--
689--
553-- XXX Instead of using "concatPairsWith wSerial" we can implement an N-way
690-- XXX Instead of using "concatPairsWith wSerial" we can implement an N-way
554−-- interleaving CPS combinator which behaves like unfoldManyInterleave. Instead
691+-- interleaving CPS combinator which behaves like unfoldInterleave. Instead
555-- of pairing up the streams we just need to go yielding one element from each
692-- of pairing up the streams we just need to go yielding one element from each
556-- stream and storing the remaining streams and then keep doing rounds through
693-- stream and storing the remaining streams and then keep doing rounds through
557-- those in a round robin fashion. This would be much like wAsync.
694-- those in a round robin fashion. This would be much like wAsync.
695+
696+-- | This does not pair streams like mergeMapWith, instead, it goes through
697+-- each stream one by one and yields one element from each stream. After it
698+-- goes to the last stream it reverses the traversal to come back to the first
699+-- stream yielding elements from each stream on its way back to the first
700+-- stream and so on.
558--
701--
559−-- See 'Streamly.Internal.Data.Stream.unfoldInterleave' documentation for more
702+-- >>> lists = Stream.fromList [[1,1],[2,2],[3,3],[4,4],[5,5]]
560−-- details.
703+-- >>> interleaved = Stream.unfoldInterleave Unfold.fromList lists
704+-- >>> Stream.fold Fold.toList interleaved
705+-- [1,2,3,4,5,5,4,3,2,1]
561--
706--
707+-- Note that this is order of magnitude more efficient than "mergeMapWith
708+-- interleave" because of fusion.
709+--
562−{-# INLINE_NORMAL unfoldManyInterleave #-}
710+{-# INLINE_NORMAL unfoldInterleave #-}
563−unfoldManyInterleave :: Monad m => Unfold m a b -> Stream m a -> Stream m b
711+unfoldInterleave :: Monad m => Unfold m a b -> Stream m a -> Stream m b
564−unfoldManyInterleave (Unfold istep inject) (Stream ostep ost) =
712+unfoldInterleave (Unfold istep inject) (Stream ostep ost) =
565 Stream step (ConcatUnfoldInterleaveOuter ost [])
713 Stream step (ConcatUnfoldInterleaveOuter ost [])
566
714
567 where
715 where
@@ -612,11 +760,17 @@ unfoldManyInterleave (Unfold istep inject) (Stream ostep ost) =
612--
760--
613-- This could be inefficient if the tasks are too small.
761-- This could be inefficient if the tasks are too small.
614--
762--
615−-- Compared to unfoldManyInterleave this one switches streams on Skips.
763+-- Compared to unfoldInterleave this one switches streams on Skips.
764+
765+-- | 'unfoldInterleave' switches to the next stream whenever a value from a
766+-- stream is yielded, it does not switch on a 'Skip'. So if a stream keeps
767+-- skipping for long time other streams won't get a chance to run.
768+-- 'unfoldRoundRobin' switches on Skip as well. So it basically schedules each
769+-- stream fairly irrespective of whether it produces a value or not.
616--
770--
617−{-# INLINE_NORMAL unfoldManyRoundRobin #-}
771+{-# INLINE_NORMAL unfoldRoundRobin #-}
618−unfoldManyRoundRobin :: Monad m => Unfold m a b -> Stream m a -> Stream m b
772+unfoldRoundRobin :: Monad m => Unfold m a b -> Stream m a -> Stream m b
619−unfoldManyRoundRobin (Unfold istep inject) (Stream ostep ost) =
773+unfoldRoundRobin (Unfold istep inject) (Stream ostep ost) =
620 Stream step (ConcatUnfoldInterleaveOuter ost [])
774 Stream step (ConcatUnfoldInterleaveOuter ost [])
621 where
775 where
622 {-# INLINE_LATE step #-}
776 {-# INLINE_LATE step #-}
@@ -677,11 +831,11 @@ data InterposeSuffixState s1 i1 =
677-- effect only if at least one element has been yielded by the unfolding.
831-- effect only if at least one element has been yielded by the unfolding.
678-- However, that becomes a bit complicated, so we have chosen the former
832-- However, that becomes a bit complicated, so we have chosen the former
679-- behvaior for now.
833-- behvaior for now.
680−{-# INLINE_NORMAL interposeSuffix #-}
834+{-# INLINE_NORMAL interposeSuffixM #-}
681−interposeSuffix
835+interposeSuffixM
682 :: Monad m
836 :: Monad m
683 => m c -> Unfold m b c -> Stream m b -> Stream m c
837 => m c -> Unfold m b c -> Stream m b -> Stream m c
684−interposeSuffix
838+interposeSuffixM
685 action
839 action
686 (Unfold istep1 inject1) (Stream step1 state1) =
840 (Unfold istep1 inject1) (Stream step1 state1) =
687 Stream step (InterposeSuffixFirst state1)
841 Stream step (InterposeSuffixFirst state1)
@@ -719,6 +873,19 @@ interposeSuffix
719 r <- action
873 r <- action
720 return $ Yield r (InterposeSuffixFirst s1)
874 return $ Yield r (InterposeSuffixFirst s1)
721
875
876+-- interposeSuffix x unf str = gintercalateSuffix unf str UF.identity (repeat x)
877+
878+-- | Unfold the elements of a stream, append the given element after each
879+-- unfolded stream and then concat them into a single stream.
880+--
881+-- >>> unlines = Stream.interposeSuffix '\n'
882+--
883+-- /Pre-release/
884+{-# INLINE interposeSuffix #-}
885+interposeSuffix :: Monad m
886+ => c -> Unfold m b c -> Stream m b -> Stream m c
887+interposeSuffix x = interposeSuffixM (return x)
888+
722{-# ANN type InterposeState Fuse #-}
889{-# ANN type InterposeState Fuse #-}
723data InterposeState s1 i1 a =
890data InterposeState s1 i1 a =
724 InterposeFirst s1
891 InterposeFirst s1
@@ -732,9 +899,9 @@ data InterposeState s1 i1 a =
732
899
733-- Note that this only interposes the pure values, we may run many effects to
900-- Note that this only interposes the pure values, we may run many effects to
734-- generate those values as some effects may not generate anything (Skip).
901-- generate those values as some effects may not generate anything (Skip).
735−{-# INLINE_NORMAL interpose #-}
902+{-# INLINE_NORMAL interposeM #-}
736−interpose :: Monad m => m c -> Unfold m b c -> Stream m b -> Stream m c
903+interposeM :: Monad m => m c -> Unfold m b c -> Stream m b -> Stream m c
737−interpose
904+interposeM
738 action
905 action
739 (Unfold istep1 inject1) (Stream step1 state1) =
906 (Unfold istep1 inject1) (Stream step1 state1) =
740 Stream step (InterposeFirst state1)
907 Stream step (InterposeFirst state1)
@@ -801,6 +968,19 @@ interpose
801 return $ Yield v (InterposeFirstInner s1 i1)
968 return $ Yield v (InterposeFirstInner s1 i1)
802 -}
969 -}
803
970
971+-- > interpose x unf str = gintercalate unf str UF.identity (repeat x)
972+
973+-- | Unfold the elements of a stream, intersperse the given element between the
974+-- unfolded streams and then concat them into a single stream.
975+--
976+-- >>> unwords = Stream.interpose ' '
977+--
978+-- /Pre-release/
979+{-# INLINE interpose #-}
980+interpose :: Monad m
981+ => c -> Unfold m b c -> Stream m b -> Stream m c
982+interpose x = interposeM (return x)
983+
804------------------------------------------------------------------------------
984------------------------------------------------------------------------------
805-- Combine N Streams - intercalate
985-- Combine N Streams - intercalate
806------------------------------------------------------------------------------
986------------------------------------------------------------------------------
@@ -815,16 +995,9 @@ data ICUState s1 s2 i1 i2 =
815 | ICUFirstOnlyInner s1 i1
995 | ICUFirstOnlyInner s1 i1
816 | ICUSecondOnlyInner s2 i2
996 | ICUSecondOnlyInner s2 i2
817
997
818−-- | Interleave streams (full streams, not the elements) unfolded from two
998+-- | 'interleaveFstSuffix' followed by unfold and concat.
819−-- input streams and concat. Stop when the first stream stops. If the second
820−-- stream ends before the first one then first stream still keeps running alone
821−-- without any interleaving with the second stream.
822−--
823−-- [a1, a2, ... an] [b1, b2 ...]
824−-- => [streamA1, streamA2, ... streamAn] [streamB1, streamB2, ...]
825−-- => [streamA1, streamB1, streamA2...StreamAn, streamBn]
826−-- => [a11, a12, ...a1j, b11, b12, ...b1k, a21, a22, ...]
827--
999--
1000+-- /Pre-release/
828{-# INLINE_NORMAL gintercalateSuffix #-}
1001{-# INLINE_NORMAL gintercalateSuffix #-}
829gintercalateSuffix
1002gintercalateSuffix
830 :: Monad m
1003 :: Monad m
@@ -901,16 +1074,17 @@ data ICALState s1 s2 i1 i2 a =
901 -- -- | ICALSecondInner s1 s2 i1 i2 a
1074 -- -- | ICALSecondInner s1 s2 i1 i2 a
902 -- -- | ICALFirstResume s1 s2 i1 i2 a
1075 -- -- | ICALFirstResume s1 s2 i1 i2 a
903
1076
904−-- | Interleave streams (full streams, not the elements) unfolded from two
1077+-- XXX we can swap the order of arguments to gintercalate so that the
905−-- input streams and concat. Stop when the first stream stops. If the second
1078+-- definition of unfoldMany becomes simpler? The first stream should be
906−-- stream ends before the first one then first stream still keeps running alone
1079+-- infixed inside the second one. However, if we change the order in
907−-- without any interleaving with the second stream.
1080+-- "interleave" as well similarly, then that will make it a bit unintuitive.
908--
1081--
909−-- [a1, a2, ... an] [b1, b2 ...]
1082+-- > unfoldMany unf str =
910−-- => [streamA1, streamA2, ... streamAn] [streamB1, streamB2, ...]
1083+-- > gintercalate unf str (UF.nilM (\_ -> return ())) (repeat ())
911−-- => [streamA1, streamB1, streamA2...StreamAn, streamBn]
1084+
912−-- => [a11, a12, ...a1j, b11, b12, ...b1k, a21, a22, ...]
1085+-- | 'interleaveFst' followed by unfold and concat.
913--
1086--
1087+-- /Pre-release/
914{-# INLINE_NORMAL gintercalate #-}
1088{-# INLINE_NORMAL gintercalate #-}
915gintercalate
1089gintercalate
916 :: Monad m
1090 :: Monad m
@@ -1017,10 +1191,57 @@ gintercalate
1017 return $ Yield x (ICALFirstInner s1 s2 i1 i2)
1191 return $ Yield x (ICALFirstInner s1 s2 i1 i2)
1018 -}
1192 -}
1019
1193
1194+-- > intercalateSuffix unf seed str = gintercalateSuffix unf str unf (repeatM seed)
1195+
1196+-- | 'intersperseMSuffix' followed by unfold and concat.
1197+--
1198+-- >>> intercalateSuffix u a = Stream.unfoldMany u . Stream.intersperseMSuffix a
1199+-- >>> intersperseMSuffix = Stream.intercalateSuffix Unfold.identity
1200+-- >>> unlines = Stream.intercalateSuffix Unfold.fromList "\n"
1201+--
1202+-- >>> input = Stream.fromList ["abc", "def", "ghi"]
1203+-- >>> Stream.fold Fold.toList $ Stream.intercalateSuffix Unfold.fromList "\n" input
1204+-- "abc\ndef\nghi\n"
1205+--
1206+{-# INLINE intercalateSuffix #-}
1207+intercalateSuffix :: Monad m
1208+ => Unfold m b c -> b -> Stream m b -> Stream m c
1209+intercalateSuffix unf seed = unfoldMany unf . intersperseMSuffix (return seed)
1210+
1211+-- > intercalate unf seed str = gintercalate unf str unf (repeatM seed)
1212+
1213+-- | 'intersperse' followed by unfold and concat.
1214+--
1215+-- >>> intercalate u a = Stream.unfoldMany u . Stream.intersperse a
1216+-- >>> intersperse = Stream.intercalate Unfold.identity
1217+-- >>> unwords = Stream.intercalate Unfold.fromList " "
1218+--
1219+-- >>> input = Stream.fromList ["abc", "def", "ghi"]
1220+-- >>> Stream.fold Fold.toList $ Stream.intercalate Unfold.fromList " " input
1221+-- "abc def ghi"
1222+--
1223+{-# INLINE intercalate #-}
1224+intercalate :: Monad m
1225+ => Unfold m b c -> b -> Stream m b -> Stream m c
1226+intercalate unf seed str = unfoldMany unf $ intersperse seed str
1227+
1020------------------------------------------------------------------------------
1228------------------------------------------------------------------------------
1021-- Folding
1229-- Folding
1022------------------------------------------------------------------------------
1230------------------------------------------------------------------------------
1023
1231
1232+-- | Apply a stream of folds to an input stream and emit the results in the
1233+-- output stream.
1234+--
1235+-- /Unimplemented/
1236+--
1237+{-# INLINE foldSequence #-}
1238+foldSequence
1239+ :: -- Monad m =>
1240+ Stream m (Fold m a b)
1241+ -> Stream m a
1242+ -> Stream m b
1243+foldSequence _f _m = undefined
1244+
1024{-# ANN type FIterState Fuse #-}
1245{-# ANN type FIterState Fuse #-}
1025data FIterState s f m a b
1246data FIterState s f m a b
1026 = FIterInit s f
1247 = FIterInit s f
@@ -1028,6 +1249,21 @@ data FIterState s f m a b
1028 | FIterYield b (FIterState s f m a b)
1249 | FIterYield b (FIterState s f m a b)
1029 | FIterStop
1250 | FIterStop
1030
1251
1252+-- | Iterate a fold generator on a stream. The initial value @b@ is used to
1253+-- generate the first fold, the fold is applied on the stream and the result of
1254+-- the fold is used to generate the next fold and so on.
1255+--
1256+-- >>> import Data.Monoid (Sum(..))
1257+-- >>> f x = return (Fold.take 2 (Fold.sconcat x))
1258+-- >>> s = fmap Sum $ Stream.fromList [1..10]
1259+-- >>> Stream.fold Fold.toList $ fmap getSum $ Stream.foldIterateM f (pure 0) s
1260+-- [3,10,21,36,55,55]
1261+--
1262+-- This is the streaming equivalent of monad like sequenced application of
1263+-- folds where next fold is dependent on the previous fold.
1264+--
1265+-- /Pre-release/
1266+--
1031{-# INLINE_NORMAL foldIterateM #-}
1267{-# INLINE_NORMAL foldIterateM #-}
1032foldIterateM ::
1268foldIterateM ::
1033 Monad m => (b -> m (FL.Fold m a b)) -> m b -> Stream m a -> Stream m b
1269 Monad m => (b -> m (FL.Fold m a b)) -> m b -> Stream m a -> Stream m b
@@ -1150,13 +1386,13 @@ data ParseChunksState x inpBuf st pst =
1150-- XXX return the remaining stream as part of the error.
1386-- XXX return the remaining stream as part of the error.
1151-- XXX This is in fact parseMany1 (a la foldMany1). Do we need a parseMany as
1387-- XXX This is in fact parseMany1 (a la foldMany1). Do we need a parseMany as
1152-- well?
1388-- well?
1153−{-# INLINE_NORMAL parseMany #-}
1389+{-# INLINE_NORMAL parseManyD #-}
1154−parseMany
1390+parseManyD
1155 :: Monad m
1391 :: Monad m
1156 => PRD.Parser a m b
1392 => PRD.Parser a m b
1157 -> Stream m a
1393 -> Stream m a
1158 -> Stream m (Either ParseError b)
1394 -> Stream m (Either ParseError b)
1159−parseMany (PRD.Parser pstep initial extract) (Stream step state) =
1395+parseManyD (PRD.Parser pstep initial extract) (Stream step state) =
1160 Stream stepOuter (ParseChunksInit [] state)
1396 Stream stepOuter (ParseChunksInit [] state)
1161
1397
1162 where
1398 where
@@ -1362,6 +1598,62 @@ parseMany (PRD.Parser pstep initial extract) (Stream step state) =
1362
1598
1363 stepOuter _ (ParseChunksYield a next) = return $ Yield a next
1599 stepOuter _ (ParseChunksYield a next) = return $ Yield a next
1364
1600
1601+-- | Apply a 'Parser' repeatedly on a stream and emit the parsed values in the
1602+-- output stream.
1603+--
1604+-- Example:
1605+--
1606+-- >>> s = Stream.fromList [1..10]
1607+-- >>> parser = Parser.takeBetween 0 2 Fold.sum
1608+-- >>> Stream.fold Fold.toList $ Stream.parseMany parser s
1609+-- [Right 3,Right 7,Right 11,Right 15,Right 19]
1610+--
1611+-- This is the streaming equivalent of the 'Streamly.Data.Parser.many' parse
1612+-- combinator.
1613+--
1614+-- Known Issues: When the parser fails there is no way to get the remaining
1615+-- stream.
1616+--
1617+{-# INLINE parseMany #-}
1618+parseMany
1619+ :: Monad m
1620+ => PR.Parser a m b
1621+ -> Stream m a
1622+ -> Stream m (Either ParseError b)
1623+parseMany p = parseManyD (PRD.fromParserK p)
1624+
1625+-- | Apply a stream of parsers to an input stream and emit the results in the
1626+-- output stream.
1627+--
1628+-- /Unimplemented/
1629+--
1630+{-# INLINE parseSequence #-}
1631+parseSequence
1632+ :: -- Monad m =>
1633+ Stream m (PR.Parser a m b)
1634+ -> Stream m a
1635+ -> Stream m b
1636+parseSequence _f _m = undefined
1637+
1638+-- XXX Change the parser arguments' order
1639+
1640+-- | @parseManyTill collect test stream@ tries the parser @test@ on the input,
1641+-- if @test@ fails it backtracks and tries @collect@, after @collect@ succeeds
1642+-- @test@ is tried again and so on. The parser stops when @test@ succeeds. The
1643+-- output of @test@ is discarded and the output of @collect@ is emitted in the
1644+-- output stream. The parser fails if @collect@ fails.
1645+--
1646+-- /Unimplemented/
1647+--
1648+{-# INLINE parseManyTill #-}
1649+parseManyTill ::
1650+ -- MonadThrow m =>
1651+ PR.Parser a m b
1652+ -> PR.Parser a m x
1653+ -> Stream m a
1654+ -> Stream m b
1655+parseManyTill = undefined
1656+
1365{-# ANN type ConcatParseState Fuse #-}
1657{-# ANN type ConcatParseState Fuse #-}
1366data ConcatParseState c b inpBuf st p m a =
1658data ConcatParseState c b inpBuf st p m a =
1367 ConcatParseInit inpBuf st p
1659 ConcatParseInit inpBuf st p
@@ -1378,14 +1670,14 @@ data ConcatParseState c b inpBuf st p m a =
1378 | ConcatParseYield c (ConcatParseState c b inpBuf st p m a)
1670 | ConcatParseYield c (ConcatParseState c b inpBuf st p m a)
1379
1671
1380-- XXX Review the changes
1672-- XXX Review the changes
1381−{-# INLINE_NORMAL parseIterate #-}
1673+{-# INLINE_NORMAL parseIterateD #-}
1382−parseIterate
1674+parseIterateD
1383 :: Monad m
1675 :: Monad m
1384 => (b -> PRD.Parser a m b)
1676 => (b -> PRD.Parser a m b)
1385 -> b
1677 -> b
1386 -> Stream m a
1678 -> Stream m a
1387 -> Stream m (Either ParseError b)
1679 -> Stream m (Either ParseError b)
1388−parseIterate func seed (Stream step state) =
1680+parseIterateD func seed (Stream step state) =
1389 Stream stepOuter (ConcatParseInit [] state (func seed))
1681 Stream stepOuter (ConcatParseInit [] state (func seed))
1390
1682
1391 where
1683 where
@@ -1577,6 +1869,29 @@ parseIterate func seed (Stream step state) =
1577
1869
1578 stepOuter _ (ConcatParseYield a next) = return $ Yield a next
1870 stepOuter _ (ConcatParseYield a next) = return $ Yield a next
1579
1871
1872+-- | Iterate a parser generating function on a stream. The initial value @b@ is
1873+-- used to generate the first parser, the parser is applied on the stream and
1874+-- the result is used to generate the next parser and so on.
1875+--
1876+-- >>> import Data.Monoid (Sum(..))
1877+-- >>> s = Stream.fromList [1..10]
1878+-- >>> Stream.fold Fold.toList $ fmap getSum $ Stream.catRights $ Stream.parseIterate (\b -> Parser.takeBetween 0 2 (Fold.sconcat b)) (Sum 0) $ fmap Sum s
1879+-- [3,10,21,36,55,55]
1880+--
1881+-- This is the streaming equivalent of monad like sequenced application of
1882+-- parsers where next parser is dependent on the previous parser.
1883+--
1884+-- /Pre-release/
1885+--
1886+{-# INLINE parseIterate #-}
1887+parseIterate
1888+ :: Monad m
1889+ => (b -> PR.Parser a m b)
1890+ -> b
1891+ -> Stream m a
1892+ -> Stream m (Either ParseError b)
1893+parseIterate f = parseIterateD (PRD.fromParserK . f)
1894+
1580------------------------------------------------------------------------------
1895------------------------------------------------------------------------------
1581-- Grouping
1896-- Grouping
1582------------------------------------------------------------------------------
1897------------------------------------------------------------------------------
@@ -2551,6 +2866,109 @@ splitOnSuffixSeq withSep patArr (Fold fstep initial done) (Stream step state) =
2551 let jump c = SplitOnSuffixSeqKRDone (n - 1) c rb rh1
2866 let jump c = SplitOnSuffixSeqKRDone (n - 1) c rb rh1
2552 yieldProceed jump b
2867 yieldProceed jump b
2553
2868
2869+-- Implement this as a fold or a parser instead.
2870+-- This can be implemented easily using Rabin Karp
2871+-- | Split post any one of the given patterns.
2872+--
2873+-- /Unimplemented/
2874+{-# INLINE splitOnSuffixSeqAny #-}
2875+splitOnSuffixSeqAny :: -- (Monad m, Unboxed a, Integral a) =>
2876+ [Array a] -> Fold m a b -> Stream m a -> Stream m b
2877+splitOnSuffixSeqAny _subseq _f _m = undefined
2878+ -- D.fromStreamD $ D.splitPostAny f subseq (D.toStreamD m)
2879+
2880+-- | Split on a prefixed separator element, dropping the separator. The
2881+-- supplied 'Fold' is applied on the split segments.
2882+--
2883+-- @
2884+-- > splitOnPrefix' p xs = Stream.toList $ Stream.splitOnPrefix p (Fold.toList) (Stream.fromList xs)
2885+-- > splitOnPrefix' (== '.') ".a.b"
2886+-- ["a","b"]
2887+-- @
2888+--
2889+-- An empty stream results in an empty output stream:
2890+-- @
2891+-- > splitOnPrefix' (== '.') ""
2892+-- []
2893+-- @
2894+--
2895+-- An empty segment consisting of only a prefix is folded to the default output
2896+-- of the fold:
2897+--
2898+-- @
2899+-- > splitOnPrefix' (== '.') "."
2900+-- [""]
2901+--
2902+-- > splitOnPrefix' (== '.') ".a.b."
2903+-- ["a","b",""]
2904+--
2905+-- > splitOnPrefix' (== '.') ".a..b"
2906+-- ["a","","b"]
2907+--
2908+-- @
2909+--
2910+-- A prefix is optional at the beginning of the stream:
2911+--
2912+-- @
2913+-- > splitOnPrefix' (== '.') "a"
2914+-- ["a"]
2915+--
2916+-- > splitOnPrefix' (== '.') "a.b"
2917+-- ["a","b"]
2918+-- @
2919+--
2920+-- 'splitOnPrefix' is an inverse of 'intercalatePrefix' with a single element:
2921+--
2922+-- > Stream.intercalatePrefix (Stream.fromPure '.') Unfold.fromList . Stream.splitOnPrefix (== '.') Fold.toList === id
2923+--
2924+-- Assuming the input stream does not contain the separator:
2925+--
2926+-- > Stream.splitOnPrefix (== '.') Fold.toList . Stream.intercalatePrefix (Stream.fromPure '.') Unfold.fromList === id
2927+--
2928+-- /Unimplemented/
2929+{-# INLINE splitOnPrefix #-}
2930+splitOnPrefix :: -- (IsStream t, MonadCatch m) =>
2931+ (a -> Bool) -> Fold m a b -> Stream m a -> Stream m b
2932+splitOnPrefix _predicate _f = undefined
2933+ -- parseMany (Parser.sliceBeginBy predicate f)
2934+
2935+-- Int list examples for splitOn:
2936+--
2937+-- >>> splitList [] [1,2,3,3,4]
2938+-- > [[1],[2],[3],[3],[4]]
2939+--
2940+-- >>> splitList [5] [1,2,3,3,4]
2941+-- > [[1,2,3,3,4]]
2942+--
2943+-- >>> splitList [1] [1,2,3,3,4]
2944+-- > [[],[2,3,3,4]]
2945+--
2946+-- >>> splitList [4] [1,2,3,3,4]
2947+-- > [[1,2,3,3],[]]
2948+--
2949+-- >>> splitList [2] [1,2,3,3,4]
2950+-- > [[1],[3,3,4]]
2951+--
2952+-- >>> splitList [3] [1,2,3,3,4]
2953+-- > [[1,2],[],[4]]
2954+--
2955+-- >>> splitList [3,3] [1,2,3,3,4]
2956+-- > [[1,2],[4]]
2957+--
2958+-- >>> splitList [1,2,3,3,4] [1,2,3,3,4]
2959+-- > [[],[]]
2960+
2961+-- This can be implemented easily using Rabin Karp
2962+-- | Split on any one of the given patterns.
2963+--
2964+-- /Unimplemented/
2965+--
2966+{-# INLINE splitOnAny #-}
2967+splitOnAny :: -- (Monad m, Unboxed a, Integral a) =>
2968+ [Array a] -> Fold m a b -> Stream m a -> Stream m b
2969+splitOnAny _subseq _f _m =
2970+ undefined -- D.fromStreamD $ D.splitOnAny f subseq (D.toStreamD m)
2971+
2554------------------------------------------------------------------------------
2972------------------------------------------------------------------------------
2555-- Nested Container Transformation
2973-- Nested Container Transformation
2556------------------------------------------------------------------------------
2974------------------------------------------------------------------------------
@@ -2663,3 +3081,42 @@ splitInnerBySuffix splitter joiner (Stream step1 state1) =
2663
3081
2664 step _ (SplitYielding x next) = return $ Yield x next
3082 step _ (SplitYielding x next) = return $ Yield x next
2665 step _ SplitFinishing = return Stop
3083 step _ SplitFinishing = return Stop
3084+
3085+------------------------------------------------------------------------------
3086+-- Trimming
3087+------------------------------------------------------------------------------
3088+
3089+-- | Drop prefix from the input stream if present.
3090+--
3091+-- Space: @O(1)@
3092+--
3093+-- /Unimplemented/
3094+{-# INLINE dropPrefix #-}
3095+dropPrefix ::
3096+ -- (Monad m, Eq a) =>
3097+ Stream m a -> Stream m a -> Stream m a
3098+dropPrefix = error "Not implemented yet!"
3099+
3100+-- | Drop all matching infix from the input stream if present. Infix stream
3101+-- may be consumed multiple times.
3102+--
3103+-- Space: @O(n)@ where n is the length of the infix.
3104+--
3105+-- /Unimplemented/
3106+{-# INLINE dropInfix #-}
3107+dropInfix ::
3108+ -- (Monad m, Eq a) =>
3109+ Stream m a -> Stream m a -> Stream m a
3110+dropInfix = error "Not implemented yet!"
3111+
3112+-- | Drop suffix from the input stream if present. Suffix stream may be
3113+-- consumed multiple times.
3114+--
3115+-- Space: @O(n)@ where n is the length of the suffix.
3116+--
3117+-- /Unimplemented/
3118+{-# INLINE dropSuffix #-}
3119+dropSuffix ::
3120+ -- (Monad m, Eq a) =>
3121+ Stream m a -> Stream m a -> Stream m a
3122+dropSuffix = error "Not implemented yet!"
core/src/Streamly/Internal/Data/Stream/Top.hs → core/src/Streamly/Internal/Data/Stream/StreamD/Top.hsrenamed+8−45
@@ -1,5 +1,5 @@
1-- |
1-- |
2−-- Module : Streamly.Internal.Data.Stream.Top
2+-- Module : Streamly.Internal.Data.Stream.StreamD.Top
3-- Copyright : (c) 2020 Composewell Technologies
3-- Copyright : (c) 2020 Composewell Technologies
4-- License : BSD-3-Clause
4-- License : BSD-3-Clause
5-- Maintainer : streamly@composewell.com
5-- Maintainer : streamly@composewell.com
@@ -8,16 +8,13 @@
8--
8--
9-- Top level module that can depend on all other lower level Stream modules.
9-- Top level module that can depend on all other lower level Stream modules.
10
10
11−module Streamly.Internal.Data.Stream.Top
11+module Streamly.Internal.Data.Stream.StreamD.Top
12 (
12 (
13 -- * Transformation
13 -- * Transformation
14 -- ** Sampling
14 -- ** Sampling
15 -- | Value agnostic filtering.
15 -- | Value agnostic filtering.
16 strideFromThen
16 strideFromThen
17
17
18− -- ** Reordering
19− , sortBy
20−
21 -- * Nesting
18 -- * Nesting
22 -- ** Set like operations
19 -- ** Set like operations
23 -- | These are not exactly set operations because streams are not
20 -- | These are not exactly set operations because streams are not
@@ -51,18 +48,13 @@ import Control.Monad.IO.Class (MonadIO(..))
51import Data.IORef (newIORef, readIORef, modifyIORef')
48import Data.IORef (newIORef, readIORef, modifyIORef')
52import Streamly.Internal.Data.Fold.Type (Fold)
49import Streamly.Internal.Data.Fold.Type (Fold)
53import Streamly.Internal.Data.Stream.Common ()
50import Streamly.Internal.Data.Stream.Common ()
54−import Streamly.Internal.Data.Stream.Type
51+import Streamly.Internal.Data.Stream.StreamD.Type (Stream, cross)
55− (Stream, fromStreamD, toStreamD, cross)
56
52
57import qualified Data.List as List
53import qualified Data.List as List
58import qualified Streamly.Internal.Data.Fold as Fold
54import qualified Streamly.Internal.Data.Fold as Fold
59−import qualified Streamly.Internal.Data.Parser as Parser
55+import qualified Streamly.Internal.Data.Stream.StreamD.Type as Stream
60−import qualified Streamly.Internal.Data.Stream.Eliminate as Stream
61−import qualified Streamly.Internal.Data.Stream.Generate as Stream
56+import qualified Streamly.Internal.Data.Stream.StreamD.Nesting as Stream
62−import qualified Streamly.Internal.Data.Stream.Expand as Stream
63−import qualified Streamly.Internal.Data.Stream.Reduce as Stream
57+import qualified Streamly.Internal.Data.Stream.StreamD.Transform as Stream
64−import qualified Streamly.Internal.Data.Stream.Transform as Stream
65−import qualified Streamly.Internal.Data.Stream.StreamD as StreamD
66
58
67import Prelude hiding (filter, zipWith, concatMap, concat)
59import Prelude hiding (filter, zipWith, concatMap, concat)
68
60
@@ -91,32 +83,6 @@ strideFromThen offset stride =
91 Stream.with Stream.indexed Stream.filter
83 Stream.with Stream.indexed Stream.filter
92 (\(i, _) -> i >= offset && (i - offset) `mod` stride == 0)
84 (\(i, _) -> i >= offset && (i - offset) `mod` stride == 0)
93
85
94−------------------------------------------------------------------------------
95−-- Reordering
96−------------------------------------------------------------------------------
97−--
98−-- Note: this is not the fastest possible implementation as of now.
99−--
100−-- We could possibly choose different algorithms depending on whether the
101−-- input stream is almost sorted (ascending/descending) or random. We could
102−-- serialize the stream to an array and use quicksort.
103−
104−-- | Sort the input stream using a supplied comparison function.
105−--
106−-- /O(n) space/
107−--
108−{-# INLINE sortBy #-}
109−sortBy :: Monad m => (a -> a -> Ordering) -> Stream m a -> Stream m a
110−-- sortBy f = Stream.concatPairsWith (Stream.mergeBy f) Stream.fromPure
111−sortBy cmp =
112− let p =
113− Parser.groupByRollingEither
114− (\x -> (< GT) . cmp x)
115− Fold.toStreamRev
116− Fold.toStream
117− in Stream.mergeMapWith (Stream.mergeBy cmp) id
118− . Stream.catRights . Stream.parseMany (fmap (either id id) p)
119−
120------------------------------------------------------------------------------
86------------------------------------------------------------------------------
121-- SQL Joins
87-- SQL Joins
122------------------------------------------------------------------------------
88------------------------------------------------------------------------------
@@ -290,10 +256,7 @@ filterInStreamGenericBy eq =
290{-# INLINE filterInStreamAscBy #-}
256{-# INLINE filterInStreamAscBy #-}
291filterInStreamAscBy :: Monad m =>
257filterInStreamAscBy :: Monad m =>
292 (a -> a -> Ordering) -> Stream m a -> Stream m a -> Stream m a
258 (a -> a -> Ordering) -> Stream m a -> Stream m a -> Stream m a
293−filterInStreamAscBy eq s1 s2 =
259+filterInStreamAscBy eq s1 s2 = Stream.intersectBySorted eq s2 s1
294− fromStreamD
295− $ StreamD.intersectBySorted eq (toStreamD s2)
296− $ toStreamD s1
297
260
298-- | Delete all elements of the first stream from the seconds stream. If an
261-- | Delete all elements of the first stream from the seconds stream. If an
299-- element occurs multiple times in the first stream as many occurrences of it
262-- element occurs multiple times in the first stream as many occurrences of it
@@ -380,7 +343,7 @@ unionWithStreamGenericBy eq s1 s2 =
380 $ do
343 $ do
381 xs1 <- liftIO $ readIORef ref
344 xs1 <- liftIO $ readIORef ref
382 return $ Stream.fromList xs1
345 return $ Stream.fromList xs1
383− return $ Stream.mapM f s2 <> s3
346+ return $ Stream.mapM f s2 `Stream.append` s3
384
347
385-- | A more efficient 'unionWithStreamGenericBy' for sorted streams.
348-- | A more efficient 'unionWithStreamGenericBy' for sorted streams.
386--
349--
core/src/Streamly/Internal/Data/Stream/StreamD/Transform.hs+784−53
@@ -27,14 +27,16 @@ module Streamly.Internal.Data.Stream.StreamD.Transform
27 -- * Mapping Effects
27 -- * Mapping Effects
28 , tap
28 , tap
29 , tapOffsetEvery
29 , tapOffsetEvery
30+ , trace
31+ , trace_
30
32
31 -- * Folding
33 -- * Folding
32 , foldrS
34 , foldrS
33 , foldlS
35 , foldlS
34
36
35 -- * Scanning By 'Fold'
37 -- * Scanning By 'Fold'
36− , postscanOnce -- XXX rename to postscan
38+ , postscan
37− , scanOnce -- XXX rename to scan
39+ , scan
38 , scanMany
40 , scanMany
39
41
40 -- * Scanning
42 -- * Scanning
@@ -65,44 +67,67 @@ module Streamly.Internal.Data.Stream.StreamD.Transform
65
67
66 -- * Filtering
68 -- * Filtering
67 -- | Produce a subset of the stream.
69 -- | Produce a subset of the stream.
70+ , with
68 , scanMaybe
71 , scanMaybe
69 , filter
72 , filter
70 , filterM
73 , filterM
71 , deleteBy
74 , deleteBy
75+ , uniqBy
72 , uniq
76 , uniq
77+ , prune
78+ , repeated
73
79
74 -- * Trimming
80 -- * Trimming
75 -- | Produce a subset of the stream trimmed at ends.
81 -- | Produce a subset of the stream trimmed at ends.
76 , take
82 , take
77 , takeWhile
83 , takeWhile
78 , takeWhileM
84 , takeWhileM
85+ , takeWhileLast
86+ , takeWhileAround
79 , drop
87 , drop
80 , dropWhile
88 , dropWhile
81 , dropWhileM
89 , dropWhileM
90+ , dropLast
91+ , dropWhileLast
92+ , dropWhileAround
82
93
83 -- * Inserting Elements
94 -- * Inserting Elements
84 -- | Produce a superset of the stream.
95 -- | Produce a superset of the stream.
85 , insertBy
96 , insertBy
86 , intersperse
97 , intersperse
87 , intersperseM
98 , intersperseM
99+ , intersperseMWith
88 , intersperseMSuffix
100 , intersperseMSuffix
89 , intersperseMSuffixWith
101 , intersperseMSuffixWith
90
102
91 -- * Inserting Side Effects
103 -- * Inserting Side Effects
92 , intersperseM_
104 , intersperseM_
93 , intersperseMSuffix_
105 , intersperseMSuffix_
106+ , intersperseMPrefix_
107+
108+ , delay
109+ , delayPre
110+ , delayPost
94
111
95 -- * Reordering
112 -- * Reordering
96 -- | Produce strictly the same set but reordered.
113 -- | Produce strictly the same set but reordered.
97 , reverse
114 , reverse
98− -- , reverse'
115+ , reverseUnbox
116+ , reassembleBy
99
117
100 -- * Position Indexing
118 -- * Position Indexing
101 , indexed
119 , indexed
102 , indexedR
120 , indexedR
103
121
122+ -- * Time Indexing
123+ , timestampWith
124+ , timestamped
125+ , timeIndexWith
126+ , timeIndexed
127+
104 -- * Searching
128 -- * Searching
105 , findIndices
129 , findIndices
130+ , elemIndices
106 , slicesBy
131 , slicesBy
107
132
108 -- * Rolling map
133 -- * Rolling map
@@ -115,32 +140,73 @@ module Streamly.Internal.Data.Stream.StreamD.Transform
115 , mapMaybe
140 , mapMaybe
116 , mapMaybeM
141 , mapMaybeM
117 , catMaybes
142 , catMaybes
143+
144+ -- * Either Streams
145+ , catLefts
146+ , catRights
147+ , catEithers
118 )
148 )
119where
149where
120
150
121#include "inline.hs"
151#include "inline.hs"
122
152
153+import Control.Concurrent (threadDelay)
123import Control.Monad (void)
154import Control.Monad (void)
155+import Control.Monad.IO.Class (MonadIO (liftIO))
156+import Data.Either (fromLeft, isLeft, isRight, fromRight)
157+import Data.Functor ((<&>))
124import Data.Maybe (fromJust, isJust)
158import Data.Maybe (fromJust, isJust)
125import Fusion.Plugin.Types (Fuse(..))
159import Fusion.Plugin.Types (Fuse(..))
126
160
127import Streamly.Internal.Data.Fold.Type (Fold(..))
161import Streamly.Internal.Data.Fold.Type (Fold(..))
128import Streamly.Internal.Data.Pipe.Type (Pipe(..), PipeState(..))
162import Streamly.Internal.Data.Pipe.Type (Pipe(..), PipeState(..))
129import Streamly.Internal.Data.SVar.Type (adaptState)
163import Streamly.Internal.Data.SVar.Type (adaptState)
164+import Streamly.Internal.Data.Time.Units (AbsTime, RelTime64)
165+import Streamly.Internal.Data.Unboxed (Unbox)
166+import Streamly.Internal.System.IO (defaultChunkSize)
130
167
168+-- import qualified Data.List as List
131−import qualified Streamly.Internal.Data.Fold.Type as FL
169+import qualified Streamly.Internal.Data.Array.Type as A
170+import qualified Streamly.Internal.Data.Fold as FL
132import qualified Streamly.Internal.Data.Pipe.Type as Pipe
171import qualified Streamly.Internal.Data.Pipe.Type as Pipe
172+import qualified Streamly.Internal.Data.Stream.StreamK.Type as K
133
173
134import Prelude hiding
174import Prelude hiding
135 ( drop, dropWhile, filter, map, mapM, reverse
175 ( drop, dropWhile, filter, map, mapM, reverse
136− , scanl, scanl1, sequence, take, takeWhile)
176+ , scanl, scanl1, sequence, take, takeWhile, zipWith)
137
177
178+import Streamly.Internal.Data.Stream.StreamD.Generate
179+ (absTimesWith, relTimesWith)
138import Streamly.Internal.Data.Stream.StreamD.Type
180import Streamly.Internal.Data.Stream.StreamD.Type
139
181
182+--
183+-- $setup
184+-- >>> :m
185+-- >>> import Control.Concurrent (threadDelay)
186+-- >>> import Control.Monad (void)
187+-- >>> import Control.Monad.IO.Class (MonadIO (liftIO))
188+-- >>> import Data.Either (fromLeft, fromRight, isLeft, isRight, either)
189+-- >>> import Data.Function ((&))
190+-- >>> import Data.Maybe (fromJust, isJust)
191+-- >>> import Prelude hiding (filter, drop, dropWhile, take, takeWhile, foldr, map, mapM, sequence, reverse, foldr1 , scanl, scanl1)
192+-- >>> import Streamly.Internal.Data.Stream (Stream)
193+-- >>> import qualified Streamly.Data.Fold as Fold
194+-- >>> import qualified Streamly.Data.Unfold as Unfold
195+-- >>> import qualified Streamly.Internal.Data.Fold as Fold (filtering)
196+-- >>> import qualified Streamly.Internal.Data.Fold.Window as Window
197+-- >>> import qualified Streamly.Internal.Data.Stream as Stream
198+-- >>> import System.IO (stdout, hSetBuffering, BufferMode(LineBuffering))
199+--
200+-- >>> hSetBuffering stdout LineBuffering
201+
140------------------------------------------------------------------------------
202------------------------------------------------------------------------------
141-- Piping
203-- Piping
142------------------------------------------------------------------------------
204------------------------------------------------------------------------------
143
205
206+-- | Use a 'Pipe' to transform a stream.
207+--
208+-- /Pre-release/
209+--
144{-# INLINE_NORMAL transform #-}
210{-# INLINE_NORMAL transform #-}
145transform :: Monad m => Pipe m a b -> Stream m a -> Stream m b
211transform :: Monad m => Pipe m a b -> Stream m a -> Stream m b
146transform (Pipe pstep1 pstep2 pstate) (Stream step state) =
212transform (Pipe pstep1 pstep2 pstate) (Stream step state) =
@@ -197,6 +263,16 @@ foldlS fstep begin (Stream step state) = Stream step' (Left (state, begin))
197-- Transformation by Mapping
263-- Transformation by Mapping
198------------------------------------------------------------------------------
264------------------------------------------------------------------------------
199
265
266+-- |
267+-- >>> sequence = Stream.mapM id
268+--
269+-- Replace the elements of a stream of monadic actions with the outputs of
270+-- those actions.
271+--
272+-- >>> s = Stream.fromList [putStr "a", putStr "b", putStrLn "c"]
273+-- >>> Stream.fold Fold.drain $ Stream.sequence s
274+-- abc
275+--
200{-# INLINE_NORMAL sequence #-}
276{-# INLINE_NORMAL sequence #-}
201sequence :: Monad m => Stream m (m a) -> Stream m a
277sequence :: Monad m => Stream m (m a) -> Stream m a
202sequence (Stream step state) = Stream step' state
278sequence (Stream step state) = Stream step' state
@@ -217,6 +293,25 @@ data TapState fs st a
217 = TapInit | Tapping !fs st | TapDone st
293 = TapInit | Tapping !fs st | TapDone st
218
294
219-- XXX Multiple yield points
295-- XXX Multiple yield points
296+
297+-- | Tap the data flowing through a stream into a 'Fold'. For example, you may
298+-- add a tap to log the contents flowing through the stream. The fold is used
299+-- only for effects, its result is discarded.
300+--
301+-- @
302+-- Fold m a b
303+-- |
304+-- -----stream m a ---------------stream m a-----
305+--
306+-- @
307+--
308+-- >>> s = Stream.enumerateFromTo 1 2
309+-- >>> Stream.fold Fold.drain $ Stream.tap (Fold.drainMapM print) s
310+-- 1
311+-- 2
312+--
313+-- Compare with 'trace'.
314+--
220{-# INLINE tap #-}
315{-# INLINE tap #-}
221tap :: Monad m => Fold m a b -> Stream m a -> Stream m a
316tap :: Monad m => Fold m a b -> Stream m a -> Stream m a
222tap (Fold fstep initial extract) (Stream step state) = Stream step' TapInit
317tap (Fold fstep initial extract) (Stream step state) = Stream step' TapInit
@@ -301,15 +396,62 @@ tapOffsetEvery offset n (Fold fstep initial extract) (Stream step state) =
301 Skip s -> Skip (TapOffDone s)
396 Skip s -> Skip (TapOffDone s)
302 Stop -> Stop
397 Stop -> Stop
303
398
399+-- | Apply a monadic function to each element flowing through the stream and
400+-- discard the results.
401+--
402+-- >>> s = Stream.enumerateFromTo 1 2
403+-- >>> Stream.fold Fold.drain $ Stream.trace print s
404+-- 1
405+-- 2
406+--
407+-- Compare with 'tap'.
408+--
409+{-# INLINE trace #-}
410+trace :: Monad m => (a -> m b) -> Stream m a -> Stream m a
411+trace f = mapM (\x -> void (f x) >> return x)
412+
413+-- | Perform a side effect before yielding each element of the stream and
414+-- discard the results.
415+--
416+-- >>> s = Stream.enumerateFromTo 1 2
417+-- >>> Stream.fold Fold.drain $ Stream.trace_ (print "got here") s
418+-- "got here"
419+-- "got here"
420+--
421+-- Same as 'intersperseMPrefix_' but always serial.
422+--
423+-- See also: 'trace'
424+--
425+-- /Pre-release/
426+{-# INLINE trace_ #-}
427+trace_ :: Monad m => m b -> Stream m a -> Stream m a
428+trace_ eff = mapM (\x -> eff >> return x)
429+
304------------------------------------------------------------------------------
430------------------------------------------------------------------------------
305-- Scanning with a Fold
431-- Scanning with a Fold
306------------------------------------------------------------------------------
432------------------------------------------------------------------------------
307
433
308data ScanState s f = ScanInit s | ScanDo s !f | ScanDone
434data ScanState s f = ScanInit s | ScanDo s !f | ScanDone
309
435
436+-- | Postscan a stream using the given monadic fold.
437+--
438+-- The following example extracts the input stream up to a point where the
439+-- running average of elements is no more than 10:
440+--
441+-- >>> import Data.Maybe (fromJust)
442+-- >>> let avg = Fold.teeWith (/) Fold.sum (fmap fromIntegral Fold.length)
443+-- >>> s = Stream.enumerateFromTo 1.0 100.0
444+-- >>> :{
445+-- Stream.fold Fold.toList
446+-- $ fmap (fromJust . fst)
447+-- $ Stream.takeWhile (\(_,x) -> x <= 10)
448+-- $ Stream.postscan (Fold.tee Fold.latest avg) s
449+-- :}
450+-- [1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0,11.0,12.0,13.0,14.0,15.0,16.0,17.0,18.0,19.0]
451+--
310−{-# INLINE_NORMAL postscanOnce #-}
452+{-# INLINE_NORMAL postscan #-}
311−postscanOnce :: Monad m => FL.Fold m a b -> Stream m a -> Stream m b
453+postscan :: Monad m => FL.Fold m a b -> Stream m a -> Stream m b
312−postscanOnce (FL.Fold fstep initial extract) (Stream sstep state) =
454+postscan (FL.Fold fstep initial extract) (Stream sstep state) =
313 Stream step (ScanInit state)
455 Stream step (ScanInit state)
314
456
315 where
457 where
@@ -364,11 +506,75 @@ scanWith restart (Fold fstep initial extract) (Stream sstep state) =
364 Stop -> return Stop
506 Stop -> return Stop
365 step _ ScanDone = return Stop
507 step _ ScanDone = return Stop
366
508
509+-- XXX It may be useful to have a version of scan where we can keep the
510+-- accumulator independent of the value emitted. So that we do not necessarily
511+-- have to keep a value in the accumulator which we are not using. We can pass
512+-- an extraction function that will take the accumulator and the current value
513+-- of the element and emit the next value in the stream. That will also make it
514+-- possible to modify the accumulator after using it. In fact, the step function
515+-- can return new accumulator and the value to be emitted. The signature would
516+-- be more like mapAccumL.
517+
518+-- | Strict left scan. Scan a stream using the given monadic fold.
519+--
520+-- >>> s = Stream.fromList [1..10]
521+-- >>> Stream.fold Fold.toList $ Stream.takeWhile (< 10) $ Stream.scan Fold.sum s
522+-- [0,1,3,6]
523+--
524+-- See also: 'usingStateT'
525+--
526+
527+-- EXPLANATION:
528+-- >>> scanl' step z = Stream.scan (Fold.foldl' step z)
529+--
530+-- Like 'map', 'scanl'' too is a one to one transformation,
531+-- however it adds an extra element.
532+--
533+-- >>> s = Stream.fromList [1,2,3,4]
534+-- >>> Stream.fold Fold.toList $ scanl' (+) 0 s
535+-- [0,1,3,6,10]
536+--
537+-- >>> Stream.fold Fold.toList $ scanl' (flip (:)) [] s
538+-- [[],[1],[2,1],[3,2,1],[4,3,2,1]]
539+--
540+-- The output of 'scanl'' is the initial value of the accumulator followed by
541+-- all the intermediate steps and the final result of 'foldl''.
542+--
543+-- By streaming the accumulated state after each fold step, we can share the
544+-- state across multiple stages of stream composition. Each stage can modify or
545+-- extend the state, do some processing with it and emit it for the next stage,
546+-- thus modularizing the stream processing. This can be useful in
547+-- stateful or event-driven programming.
548+--
549+-- Consider the following monolithic example, computing the sum and the product
550+-- of the elements in a stream in one go using a @foldl'@:
551+--
552+-- >>> foldl' step z = Stream.fold (Fold.foldl' step z)
553+-- >>> foldl' (\(s, p) x -> (s + x, p * x)) (0,1) s
554+-- (10,24)
555+--
556+-- Using @scanl'@ we can make it modular by computing the sum in the first
557+-- stage and passing it down to the next stage for computing the product:
558+--
559+-- >>> :{
560+-- foldl' (\(_, p) (s, x) -> (s, p * x)) (0,1)
561+-- $ scanl' (\(s, _) x -> (s + x, x)) (0,1)
562+-- $ Stream.fromList [1,2,3,4]
563+-- :}
564+-- (10,24)
565+--
566+-- IMPORTANT: 'scanl'' evaluates the accumulator to WHNF. To avoid building
567+-- lazy expressions inside the accumulator, it is recommended that a strict
568+-- data structure is used for accumulator.
569+--
367−{-# INLINE scanOnce #-}
570+{-# INLINE scan #-}
368−scanOnce :: Monad m
571+scan :: Monad m
369 => FL.Fold m a b -> Stream m a -> Stream m b
572 => FL.Fold m a b -> Stream m a -> Stream m b
370−scanOnce = scanWith False
573+scan = scanWith False
371
574
575+-- | Like 'scan' but restarts scanning afresh when the scanning fold
576+-- terminates.
577+--
372{-# INLINE scanMany #-}
578{-# INLINE scanMany #-}
373scanMany :: Monad m
579scanMany :: Monad m
374 => FL.Fold m a b -> Stream m a -> Stream m b
580 => FL.Fold m a b -> Stream m a -> Stream m b
@@ -557,6 +763,17 @@ scanlM' fstep begin (Stream step state) = Stream step' Nothing
557 Skip s -> return $ Skip (Just (s, acc))
763 Skip s -> return $ Skip (Just (s, acc))
558 Stop -> return Stop
764 Stop -> return Stop
559
765
766+-- | @scanlMAfter' accumulate initial done stream@ is like 'scanlM'' except
767+-- that it provides an additional @done@ function to be applied on the
768+-- accumulator when the stream stops. The result of @done@ is also emitted in
769+-- the stream.
770+--
771+-- This function can be used to allocate a resource in the beginning of the
772+-- scan and release it when the stream ends or to flush the internal state of
773+-- the scan at the end.
774+--
775+-- /Pre-release/
776+--
560{-# INLINE scanlMAfter' #-}
777{-# INLINE scanlMAfter' #-}
561scanlMAfter' :: Monad m
778scanlMAfter' :: Monad m
562 => (b -> a -> m b) -> m b -> (b -> m b) -> Stream m a -> Stream m b
779 => (b -> a -> m b) -> m b -> (b -> m b) -> Stream m a -> Stream m b
@@ -644,7 +861,28 @@ scanl1' f = scanl1M' (\x y -> return (f x y))
644-- Filtering
861-- Filtering
645-------------------------------------------------------------------------------
862-------------------------------------------------------------------------------
646
863
864+-- | Modify a @Stream m a -> Stream m a@ stream transformation that accepts a
865+-- predicate @(a -> b)@ to accept @((s, a) -> b)@ instead, provided a
866+-- transformation @Stream m a -> Stream m (s, a)@. Convenient to filter with
867+-- index or time.
868+--
869+-- >>> filterWithIndex = Stream.with Stream.indexed Stream.filter
870+--
871+-- /Pre-release/
872+{-# INLINE with #-}
873+with :: Monad m =>
874+ (Stream m a -> Stream m (s, a))
875+ -> (((s, a) -> b) -> Stream m (s, a) -> Stream m (s, a))
876+ -> (((s, a) -> b) -> Stream m a -> Stream m a)
877+with f comb g = fmap snd . comb g . f
878+
647-- Adapted from the vector package
879-- Adapted from the vector package
880+
881+-- | Same as 'filter' but with a monadic predicate.
882+--
883+-- >>> f p x = p x >>= \r -> return $ if r then Just x else Nothing
884+-- >>> filterM p = Stream.mapMaybeM (f p)
885+--
648{-# INLINE_NORMAL filterM #-}
886{-# INLINE_NORMAL filterM #-}
649filterM :: Monad m => (a -> m Bool) -> Stream m a -> Stream m a
887filterM :: Monad m => (a -> m Bool) -> Stream m a -> Stream m a
650filterM f (Stream step state) = Stream step' state
888filterM f (Stream step state) = Stream step' state
@@ -661,13 +899,55 @@ filterM f (Stream step state) = Stream step' state
661 Skip s -> return $ Skip s
899 Skip s -> return $ Skip s
662 Stop -> return Stop
900 Stop -> return Stop
663
901
902+-- | Include only those elements that pass a predicate.
903+--
904+-- >>> filter p = Stream.filterM (return . p)
905+-- >>> filter p = Stream.mapMaybe (\x -> if p x then Just x else Nothing)
906+-- >>> filter p = Stream.scanMaybe (Fold.filtering p)
907+--
664{-# INLINE filter #-}
908{-# INLINE filter #-}
665filter :: Monad m => (a -> Bool) -> Stream m a -> Stream m a
909filter :: Monad m => (a -> Bool) -> Stream m a -> Stream m a
666filter f = filterM (return . f)
910filter f = filterM (return . f)
911+-- filter p = scanMaybe (FL.filtering p)
912+
913+-- | Drop repeated elements that are adjacent to each other using the supplied
914+-- comparison function.
915+--
916+-- >>> uniq = Stream.uniqBy (==)
917+--
918+-- To strip duplicate path separators:
919+--
920+-- >>> input = Stream.fromList "//a//b"
921+-- >>> f x y = x == '/' && y == '/'
922+-- >>> Stream.fold Fold.toList $ Stream.uniqBy f input
923+-- "/a/b"
924+--
925+-- Space: @O(1)@
926+--
927+-- /Pre-release/
928+--
929+{-# INLINE uniqBy #-}
930+uniqBy :: Monad m =>
931+ (a -> a -> Bool) -> Stream m a -> Stream m a
932+-- uniqBy eq = scanMaybe (FL.uniqBy eq)
933+uniqBy eq = catMaybes . rollingMap f
934+
935+ where
936+
937+ f pre curr =
938+ case pre of
939+ Nothing -> Just curr
940+ Just x -> if x `eq` curr then Nothing else Just curr
667
941
668-- Adapted from the vector package
942-- Adapted from the vector package
943+
944+-- | Drop repeated elements that are adjacent to each other.
945+--
946+-- >>> uniq = Stream.uniqBy (==)
947+--
669{-# INLINE_NORMAL uniq #-}
948{-# INLINE_NORMAL uniq #-}
670uniq :: (Eq a, Monad m) => Stream m a -> Stream m a
949uniq :: (Eq a, Monad m) => Stream m a -> Stream m a
950+-- uniq = scanMaybe FL.uniq
671uniq (Stream step state) = Stream step' (Nothing, state)
951uniq (Stream step state) = Stream step' (Nothing, state)
672 where
952 where
673 {-# INLINE_LATE step' #-}
953 {-# INLINE_LATE step' #-}
@@ -685,8 +965,16 @@ uniq (Stream step state) = Stream step' (Nothing, state)
685 Skip s -> return $ Skip (Just x, s)
965 Skip s -> return $ Skip (Just x, s)
686 Stop -> return Stop
966 Stop -> return Stop
687
967
968+-- | Deletes the first occurrence of the element in the stream that satisfies
969+-- the given equality predicate.
970+--
971+-- >>> input = Stream.fromList [1,3,3,5]
972+-- >>> Stream.fold Fold.toList $ Stream.deleteBy (==) 3 input
973+-- [1,3,5]
974+--
688{-# INLINE_NORMAL deleteBy #-}
975{-# INLINE_NORMAL deleteBy #-}
689deleteBy :: Monad m => (a -> a -> Bool) -> a -> Stream m a -> Stream m a
976deleteBy :: Monad m => (a -> a -> Bool) -> a -> Stream m a -> Stream m a
977+-- deleteBy cmp x = scanMaybe (FL.deleteBy cmp x)
690deleteBy eq x (Stream step state) = Stream step' (state, False)
978deleteBy eq x (Stream step state) = Stream step' (state, False)
691 where
979 where
692 {-# INLINE_LATE step' #-}
980 {-# INLINE_LATE step' #-}
@@ -705,11 +993,69 @@ deleteBy eq x (Stream step state) = Stream step' (state, False)
705 Skip s -> return $ Skip (s, True)
993 Skip s -> return $ Skip (s, True)
706 Stop -> return Stop
994 Stop -> return Stop
707
995
996+-- | Strip all leading and trailing occurrences of an element passing a
997+-- predicate and make all other consecutive occurrences uniq.
998+--
999+-- >> prune p = Stream.dropWhileAround p $ Stream.uniqBy (x y -> p x && p y)
1000+--
1001+-- @
1002+-- > Stream.prune isSpace (Stream.fromList " hello world! ")
1003+-- "hello world!"
1004+--
1005+-- @
1006+--
1007+-- Space: @O(1)@
1008+--
1009+-- /Unimplemented/
1010+{-# INLINE prune #-}
1011+prune ::
1012+ -- (Monad m, Eq a) =>
1013+ (a -> Bool) -> Stream m a -> Stream m a
1014+prune = error "Not implemented yet!"
1015+
1016+-- Possible implementation:
1017+-- @repeated =
1018+-- Stream.catMaybes . Stream.parseMany (Parser.groupBy (==) Fold.repeated)@
1019+--
1020+-- 'Fold.repeated' should return 'Just' when repeated, and 'Nothing' for a
1021+-- single element.
1022+
1023+-- | Emit only repeated elements, once.
1024+--
1025+-- /Unimplemented/
1026+repeated :: -- (Monad m, Eq a) =>
1027+ Stream m a -> Stream m a
1028+repeated = undefined
1029+
708------------------------------------------------------------------------------
1030------------------------------------------------------------------------------
709-- Trimming
1031-- Trimming
710------------------------------------------------------------------------------
1032------------------------------------------------------------------------------
711
1033
1034+-- | Take all consecutive elements at the end of the stream for which the
1035+-- predicate is true.
1036+--
1037+-- O(n) space, where n is the number elements taken.
1038+--
1039+-- /Unimplemented/
1040+{-# INLINE takeWhileLast #-}
1041+takeWhileLast :: -- Monad m =>
1042+ (a -> Bool) -> Stream m a -> Stream m a
1043+takeWhileLast = undefined -- fromStreamD $ D.takeWhileLast n $ toStreamD m
1044+
1045+-- | Like 'takeWhile' and 'takeWhileLast' combined.
1046+--
1047+-- O(n) space, where n is the number elements taken from the end.
1048+--
1049+-- /Unimplemented/
1050+{-# INLINE takeWhileAround #-}
1051+takeWhileAround :: -- Monad m =>
1052+ (a -> Bool) -> Stream m a -> Stream m a
1053+takeWhileAround = undefined -- fromStreamD $ D.takeWhileAround n $ toStreamD m
1054+
712-- Adapted from the vector package
1055-- Adapted from the vector package
1056+
1057+-- | Discard first 'n' elements from the stream and take the rest.
1058+--
713{-# INLINE_NORMAL drop #-}
1059{-# INLINE_NORMAL drop #-}
714drop :: Monad m => Int -> Stream m a -> Stream m a
1060drop :: Monad m => Int -> Stream m a -> Stream m a
715drop n (Stream step state) = Stream step' (state, Just n)
1061drop n (Stream step state) = Stream step' (state, Just n)
@@ -739,8 +1085,11 @@ data DropWhileState s a
739 | DropWhileYield a s
1085 | DropWhileYield a s
740 | DropWhileNext s
1086 | DropWhileNext s
741
1087
1088+-- | Same as 'dropWhile' but with a monadic predicate.
1089+--
742{-# INLINE_NORMAL dropWhileM #-}
1090{-# INLINE_NORMAL dropWhileM #-}
743dropWhileM :: Monad m => (a -> m Bool) -> Stream m a -> Stream m a
1091dropWhileM :: Monad m => (a -> m Bool) -> Stream m a -> Stream m a
1092+-- dropWhileM p = scanMaybe (FL.droppingWhileM p)
744dropWhileM f (Stream step state) = Stream step' (DropWhileDrop state)
1093dropWhileM f (Stream step state) = Stream step' (DropWhileDrop state)
745 where
1094 where
746 {-# INLINE_LATE step' #-}
1095 {-# INLINE_LATE step' #-}
@@ -764,14 +1113,58 @@ dropWhileM f (Stream step state) = Stream step' (DropWhileDrop state)
764
1113
765 step' _ (DropWhileYield x st) = return $ Yield x (DropWhileNext st)
1114 step' _ (DropWhileYield x st) = return $ Yield x (DropWhileNext st)
766
1115
1116+-- | Drop elements in the stream as long as the predicate succeeds and then
1117+-- take the rest of the stream.
1118+--
767{-# INLINE dropWhile #-}
1119{-# INLINE dropWhile #-}
768dropWhile :: Monad m => (a -> Bool) -> Stream m a -> Stream m a
1120dropWhile :: Monad m => (a -> Bool) -> Stream m a -> Stream m a
1121+-- dropWhile p = scanMaybe (FL.droppingWhile p)
769dropWhile f = dropWhileM (return . f)
1122dropWhile f = dropWhileM (return . f)
770
1123
1124+-- | Drop @n@ elements at the end of the stream.
1125+--
1126+-- O(n) space, where n is the number elements dropped.
1127+--
1128+-- /Unimplemented/
1129+{-# INLINE dropLast #-}
1130+dropLast :: -- Monad m =>
1131+ Int -> Stream m a -> Stream m a
1132+dropLast = undefined -- fromStreamD $ D.dropLast n $ toStreamD m
1133+
1134+-- | Drop all consecutive elements at the end of the stream for which the
1135+-- predicate is true.
1136+--
1137+-- O(n) space, where n is the number elements dropped.
1138+--
1139+-- /Unimplemented/
1140+{-# INLINE dropWhileLast #-}
1141+dropWhileLast :: -- Monad m =>
1142+ (a -> Bool) -> Stream m a -> Stream m a
1143+dropWhileLast = undefined -- fromStreamD $ D.dropWhileLast n $ toStreamD m
1144+
1145+-- | Like 'dropWhile' and 'dropWhileLast' combined.
1146+--
1147+-- O(n) space, where n is the number elements dropped from the end.
1148+--
1149+-- /Unimplemented/
1150+{-# INLINE dropWhileAround #-}
1151+dropWhileAround :: -- Monad m =>
1152+ (a -> Bool) -> Stream m a -> Stream m a
1153+dropWhileAround = undefined -- fromStreamD $ D.dropWhileAround n $ toStreamD m
1154+
771------------------------------------------------------------------------------
1155------------------------------------------------------------------------------
772-- Inserting Elements
1156-- Inserting Elements
773------------------------------------------------------------------------------
1157------------------------------------------------------------------------------
774
1158
1159+-- | @insertBy cmp elem stream@ inserts @elem@ before the first element in
1160+-- @stream@ that is less than @elem@ when compared using @cmp@.
1161+--
1162+-- >>> insertBy cmp x = Stream.mergeBy cmp (Stream.fromPure x)
1163+--
1164+-- >>> input = Stream.fromList [1,3,5]
1165+-- >>> Stream.fold Fold.toList $ Stream.insertBy compare 2 input
1166+-- [1,2,3,5]
1167+--
775{-# INLINE_NORMAL insertBy #-}
1168{-# INLINE_NORMAL insertBy #-}
776insertBy :: Monad m => (a -> a -> Ordering) -> a -> Stream m a -> Stream m a
1169insertBy :: Monad m => (a -> a -> Ordering) -> a -> Stream m a -> Stream m a
777insertBy cmp a (Stream step state) = Stream step' (state, False, Nothing)
1170insertBy cmp a (Stream step state) = Stream step' (state, False, Nothing)
@@ -799,6 +1192,22 @@ data LoopState x s = FirstYield s
799 | InterspersingYield s
1192 | InterspersingYield s
800 | YieldAndCarry x s
1193 | YieldAndCarry x s
801
1194
1195+-- intersperseM = intersperseMWith 1
1196+
1197+-- | Insert an effect and its output before consuming an element of a stream
1198+-- except the first one.
1199+--
1200+-- >>> input = Stream.fromList "hello"
1201+-- >>> Stream.fold Fold.toList $ Stream.trace putChar $ Stream.intersperseM (putChar '.' >> return ',') input
1202+-- h.,e.,l.,l.,o"h,e,l,l,o"
1203+--
1204+-- Be careful about the order of effects. In the above example we used trace
1205+-- after the intersperse, if we use it before the intersperse the output would
1206+-- be he.l.l.o."h,e,l,l,o".
1207+--
1208+-- >>> Stream.fold Fold.toList $ Stream.intersperseM (putChar '.' >> return ',') $ Stream.trace putChar input
1209+-- he.l.l.o."h,e,l,l,o"
1210+--
802{-# INLINE_NORMAL intersperseM #-}
1211{-# INLINE_NORMAL intersperseM #-}
803intersperseM :: Monad m => m a -> Stream m a -> Stream m a
1212intersperseM :: Monad m => m a -> Stream m a -> Stream m a
804intersperseM m (Stream step state) = Stream step' (FirstYield state)
1213intersperseM m (Stream step state) = Stream step' (FirstYield state)
@@ -823,10 +1232,24 @@ intersperseM m (Stream step state) = Stream step' (FirstYield state)
823
1232
824 step' _ (YieldAndCarry x st) = return $ Yield x (InterspersingYield st)
1233 step' _ (YieldAndCarry x st) = return $ Yield x (InterspersingYield st)
825
1234
1235+-- | Insert a pure value between successive elements of a stream.
1236+--
1237+-- >>> input = Stream.fromList "hello"
1238+-- >>> Stream.fold Fold.toList $ Stream.intersperse ',' input
1239+-- "h,e,l,l,o"
1240+--
826{-# INLINE intersperse #-}
1241{-# INLINE intersperse #-}
827intersperse :: Monad m => a -> Stream m a -> Stream m a
1242intersperse :: Monad m => a -> Stream m a -> Stream m a
828intersperse a = intersperseM (return a)
1243intersperse a = intersperseM (return a)
829
1244
1245+-- | Insert a side effect before consuming an element of a stream except the
1246+-- first one.
1247+--
1248+-- >>> input = Stream.fromList "hello"
1249+-- >>> Stream.fold Fold.drain $ Stream.trace putChar $ Stream.intersperseM_ (putChar '.') input
1250+-- h.e.l.l.o
1251+--
1252+-- /Pre-release/
830{-# INLINE_NORMAL intersperseM_ #-}
1253{-# INLINE_NORMAL intersperseM_ #-}
831intersperseM_ :: Monad m => m b -> Stream m a -> Stream m a
1254intersperseM_ :: Monad m => m b -> Stream m a -> Stream m a
832intersperseM_ m (Stream step1 state1) = Stream step (Left (pure (), state1))
1255intersperseM_ m (Stream step1 state1) = Stream step (Left (pure (), state1))
@@ -841,11 +1264,31 @@ intersperseM_ m (Stream step1 state1) = Stream step (Left (pure (), state1))
841
1264
842 step _ (Right st) = return $ Skip $ Left (void m, st)
1265 step _ (Right st) = return $ Skip $ Left (void m, st)
843
1266
1267+-- | Intersperse a monadic action into the input stream after every @n@
1268+-- elements.
1269+--
1270+-- >> input = Stream.fromList "hello"
1271+-- >> Stream.fold Fold.toList $ Stream.intersperseMWith 2 (return ',') input
1272+-- "he,ll,o"
1273+--
1274+-- /Unimplemented/
1275+{-# INLINE intersperseMWith #-}
1276+intersperseMWith :: -- Monad m =>
1277+ Int -> m a -> Stream m a -> Stream m a
1278+intersperseMWith _n _f _xs = undefined
1279+
844data SuffixState s a
1280data SuffixState s a
845 = SuffixElem s
1281 = SuffixElem s
846 | SuffixSuffix s
1282 | SuffixSuffix s
847 | SuffixYield a (SuffixState s a)
1283 | SuffixYield a (SuffixState s a)
848
1284
1285+-- | Insert an effect and its output after consuming an element of a stream.
1286+--
1287+-- >>> input = Stream.fromList "hello"
1288+-- >>> Stream.fold Fold.toList $ Stream.trace putChar $ Stream.intersperseMSuffix (putChar '.' >> return ',') input
1289+-- h.,e.,l.,l.,o.,"h,e,l,l,o,"
1290+--
1291+-- /Pre-release/
849{-# INLINE_NORMAL intersperseMSuffix #-}
1292{-# INLINE_NORMAL intersperseMSuffix #-}
850intersperseMSuffix :: forall m a. Monad m => m a -> Stream m a -> Stream m a
1293intersperseMSuffix :: forall m a. Monad m => m a -> Stream m a -> Stream m a
851intersperseMSuffix action (Stream step state) = Stream step' (SuffixElem state)
1294intersperseMSuffix action (Stream step state) = Stream step' (SuffixElem state)
@@ -863,6 +1306,14 @@ intersperseMSuffix action (Stream step state) = Stream step' (SuffixElem state)
863
1306
864 step' _ (SuffixYield x next) = return $ Yield x next
1307 step' _ (SuffixYield x next) = return $ Yield x next
865
1308
1309+-- | Insert a side effect after consuming an element of a stream.
1310+--
1311+-- >>> input = Stream.fromList "hello"
1312+-- >>> Stream.fold Fold.toList $ Stream.intersperseMSuffix_ (threadDelay 1000000) input
1313+-- "hello"
1314+--
1315+-- /Pre-release/
1316+--
866{-# INLINE_NORMAL intersperseMSuffix_ #-}
1317{-# INLINE_NORMAL intersperseMSuffix_ #-}
867intersperseMSuffix_ :: Monad m => m b -> Stream m a -> Stream m a
1318intersperseMSuffix_ :: Monad m => m b -> Stream m a -> Stream m a
868intersperseMSuffix_ m (Stream step1 state1) = Stream step (Left state1)
1319intersperseMSuffix_ m (Stream step1 state1) = Stream step (Left state1)
@@ -884,7 +1335,15 @@ data SuffixSpanState s a
884 | SuffixSpanLast
1335 | SuffixSpanLast
885 | SuffixSpanStop
1336 | SuffixSpanStop
886
1337
887−-- | intersperse after every n items
1338+-- | Like 'intersperseMSuffix' but intersperses an effectful action into the
1339+-- input stream after every @n@ elements and after the last element.
1340+--
1341+-- >>> input = Stream.fromList "hello"
1342+-- >>> Stream.fold Fold.toList $ Stream.intersperseMSuffixWith 2 (return ',') input
1343+-- "he,ll,o,"
1344+--
1345+-- /Pre-release/
1346+--
888{-# INLINE_NORMAL intersperseMSuffixWith #-}
1347{-# INLINE_NORMAL intersperseMSuffixWith #-}
889intersperseMSuffixWith :: forall m a. Monad m
1348intersperseMSuffixWith :: forall m a. Monad m
890 => Int -> m a -> Stream m a -> Stream m a
1349 => Int -> m a -> Stream m a -> Stream m a
@@ -910,21 +1369,113 @@ intersperseMSuffixWith n action (Stream step state) =
910
1369
911 step' _ SuffixSpanStop = return Stop
1370 step' _ SuffixSpanStop = return Stop
912
1371
1372+-- | Insert a side effect before consuming an element of a stream.
1373+--
1374+-- Definition:
1375+--
1376+-- >>> intersperseMPrefix_ m = Stream.mapM (\x -> void m >> return x)
1377+--
1378+-- >>> input = Stream.fromList "hello"
1379+-- >>> Stream.fold Fold.toList $ Stream.trace putChar $ Stream.intersperseMPrefix_ (putChar '.' >> return ',') input
1380+-- .h.e.l.l.o"hello"
1381+--
1382+-- Same as 'trace_'.
1383+--
1384+-- /Pre-release/
1385+--
1386+{-# INLINE intersperseMPrefix_ #-}
1387+intersperseMPrefix_ :: Monad m => m b -> Stream m a -> Stream m a
1388+intersperseMPrefix_ m = mapM (\x -> void m >> return x)
1389+
1390+------------------------------------------------------------------------------
1391+-- Inserting Time
1392+------------------------------------------------------------------------------
1393+
1394+-- XXX This should be in Prelude, should we export this as a helper function?
1395+
1396+-- | Block the current thread for specified number of seconds.
1397+{-# INLINE sleep #-}
1398+sleep :: MonadIO m => Double -> m ()
1399+sleep n = liftIO $ threadDelay $ round $ n * 1000000
1400+
1401+-- | Introduce a delay of specified seconds between elements of the stream.
1402+--
1403+-- Definition:
1404+--
1405+-- >>> sleep n = liftIO $ threadDelay $ round $ n * 1000000
1406+-- >>> delay = Stream.intersperseM_ . sleep
1407+--
1408+-- Example:
1409+--
1410+-- >>> input = Stream.enumerateFromTo 1 3
1411+-- >>> Stream.fold (Fold.drainMapM print) $ Stream.delay 1 input
1412+-- 1
1413+-- 2
1414+-- 3
1415+--
1416+{-# INLINE delay #-}
1417+delay :: MonadIO m => Double -> Stream m a -> Stream m a
1418+delay = intersperseM_ . sleep
1419+
1420+-- | Introduce a delay of specified seconds after consuming an element of a
1421+-- stream.
1422+--
1423+-- Definition:
1424+--
1425+-- >>> sleep n = liftIO $ threadDelay $ round $ n * 1000000
1426+-- >>> delayPost = Stream.intersperseMSuffix_ . sleep
1427+--
1428+-- Example:
1429+--
1430+-- >>> input = Stream.enumerateFromTo 1 3
1431+-- >>> Stream.fold (Fold.drainMapM print) $ Stream.delayPost 1 input
1432+-- 1
1433+-- 2
1434+-- 3
1435+--
1436+-- /Pre-release/
1437+--
1438+{-# INLINE delayPost #-}
1439+delayPost :: MonadIO m => Double -> Stream m a -> Stream m a
1440+delayPost n = intersperseMSuffix_ $ liftIO $ threadDelay $ round $ n * 1000000
1441+
1442+-- | Introduce a delay of specified seconds before consuming an element of a
1443+-- stream.
1444+--
1445+-- Definition:
1446+--
1447+-- >>> sleep n = liftIO $ threadDelay $ round $ n * 1000000
1448+-- >>> delayPre = Stream.intersperseMPrefix_. sleep
1449+--
1450+-- Example:
1451+--
1452+-- >>> input = Stream.enumerateFromTo 1 3
1453+-- >>> Stream.fold (Fold.drainMapM print) $ Stream.delayPre 1 input
1454+-- 1
1455+-- 2
1456+-- 3
1457+--
1458+-- /Pre-release/
1459+--
1460+{-# INLINE delayPre #-}
1461+delayPre :: MonadIO m => Double -> Stream m a -> Stream m a
1462+delayPre = intersperseMPrefix_. sleep
1463+
913------------------------------------------------------------------------------
1464------------------------------------------------------------------------------
914-- Reordering
1465-- Reordering
915------------------------------------------------------------------------------
1466------------------------------------------------------------------------------
916
1467
917−-- We can implement reverse as:
1468+-- | Returns the elements of the stream in reverse order. The stream must be
1469+-- finite. Note that this necessarily buffers the entire stream in memory.
918--
1470--
919−-- > reverse = foldlS (flip cons) nil
1471+-- Definition:
920--
1472--
921−-- However, this implementation is unusable because of the horrible performance
1473+-- >>> reverse m = Stream.concatEffect $ Stream.fold Fold.toListRev m >>= return . Stream.fromList
922−-- of cons. So we just convert it to a list first and then stream from the
923−-- list.
924--
1474--
925−-- XXX Maybe we can use an Array instead of a list here?
926{-# INLINE_NORMAL reverse #-}
1475{-# INLINE_NORMAL reverse #-}
927reverse :: Monad m => Stream m a -> Stream m a
1476reverse :: Monad m => Stream m a -> Stream m a
1477+reverse m = concatEffect $ fold FL.toListRev m <&> fromList
1478+{-
928reverse m = Stream step Nothing
1479reverse m = Stream step Nothing
929 where
1480 where
930 {-# INLINE_LATE step #-}
1481 {-# INLINE_LATE step #-}
@@ -933,47 +1484,57 @@ reverse m = Stream step Nothing
933 return $ Skip (Just xs)
1484 return $ Skip (Just xs)
934 step _ (Just (x:xs)) = return $ Yield x (Just xs)
1485 step _ (Just (x:xs)) = return $ Yield x (Just xs)
935 step _ (Just []) = return Stop
1486 step _ (Just []) = return Stop
936−
937−-- Much faster reverse for Storables
938−{-
939−{-# INLINE_NORMAL reverse' #-}
940−reverse' :: forall m a. (MonadIO m, Storable a) => Stream m a -> Stream m a
941−-- This commented implementation copies the whole stream into one single array
942−-- and then streams from that array, this has exactly the same performance as
943−-- the chunked code in IsStream.Common.reverse' . Though this could be problematic due to
944−-- unbounded large allocations. However, if we use an idiomatic implementation
945−-- of arraysOf instead of the custom implementation then the chunked code
946−-- becomes worse by 6 times. Need to investigate if that can be improved.
947−import Foreign.ForeignPtr (touchForeignPtr)
948−import Foreign.ForeignPtr.Unsafe (unsafeForeignPtrToPtr)
949−import Foreign.Ptr (Ptr, plusPtr)
950−import Streamly.Internal.Data.Array.Mut.Type (sizeOfElem)
951−reverse' m = Stream step Nothing
952− where
953− {-# INLINE_LATE step #-}
954− step _ Nothing = do
955− arr <- A.fromStreamD m
956− let p = A.arrEnd arr `plusPtr` negate (sizeOfElem (undefined :: a))
957− return $ Skip $ Just (A.aStart arr, p)
958−
959− step _ (Just (start, p)) | p < unsafeForeignPtrToPtr start = return Stop
960−
961− step _ (Just (start, p)) = do
962− let !x = A.unsafeInlineIO $ do
963− r <- peek p
964− touchForeignPtr start
965− return r
966− next = p `plusPtr` negate (sizeOfElem (undefined :: a))
967− return $ Yield x (Just (start, next))
968-}
1487-}
969
1488
1489+-- | Like 'reverse' but several times faster, requires an 'Unbox' instance.
1490+--
1491+-- /O(n) space/
1492+--
1493+-- /Pre-release/
1494+{-# INLINE reverseUnbox #-}
1495+reverseUnbox :: (MonadIO m, Unbox a) => Stream m a -> Stream m a
1496+reverseUnbox =
1497+ A.flattenArraysRev -- unfoldMany A.readRev
1498+ . fromStreamK
1499+ . K.reverse
1500+ . toStreamK
1501+ . A.arraysOf defaultChunkSize
1502+
1503+-- | Buffer until the next element in sequence arrives. The function argument
1504+-- determines the difference in sequence numbers. This could be useful in
1505+-- implementing sequenced streams, for example, TCP reassembly.
1506+--
1507+-- /Unimplemented/
1508+--
1509+{-# INLINE reassembleBy #-}
1510+reassembleBy
1511+ :: -- Monad m =>
1512+ Fold m a b
1513+ -> (a -> a -> Int)
1514+ -> Stream m a
1515+ -> Stream m b
1516+reassembleBy = undefined
1517+
970------------------------------------------------------------------------------
1518------------------------------------------------------------------------------
971-- Position Indexing
1519-- Position Indexing
972------------------------------------------------------------------------------
1520------------------------------------------------------------------------------
973
1521
974-- Adapted from the vector package
1522-- Adapted from the vector package
1523+
1524+-- |
1525+-- >>> f = Fold.foldl' (\(i, _) x -> (i + 1, x)) (-1,undefined)
1526+-- >>> indexed = Stream.postscan f
1527+-- >>> indexed = Stream.zipWith (,) (Stream.enumerateFrom 0)
1528+-- >>> indexedR n = fmap (\(i, a) -> (n - i, a)) . indexed
1529+--
1530+-- Pair each element in a stream with its index, starting from index 0.
1531+--
1532+-- >>> Stream.fold Fold.toList $ Stream.indexed $ Stream.fromList "hello"
1533+-- [(0,'h'),(1,'e'),(2,'l'),(3,'l'),(4,'o')]
1534+--
975{-# INLINE_NORMAL indexed #-}
1535{-# INLINE_NORMAL indexed #-}
976indexed :: Monad m => Stream m a -> Stream m (Int, a)
1536indexed :: Monad m => Stream m a -> Stream m (Int, a)
1537+-- indexed = scanMaybe FL.indexing
977indexed (Stream step state) = Stream step' (state, 0)
1538indexed (Stream step state) = Stream step' (state, 0)
978 where
1539 where
979 {-# INLINE_LATE step' #-}
1540 {-# INLINE_LATE step' #-}
@@ -985,8 +1546,23 @@ indexed (Stream step state) = Stream step' (state, 0)
985 Stop -> return Stop
1546 Stop -> return Stop
986
1547
987-- Adapted from the vector package
1548-- Adapted from the vector package
1549+
1550+-- |
1551+-- >>> f n = Fold.foldl' (\(i, _) x -> (i - 1, x)) (n + 1,undefined)
1552+-- >>> indexedR n = Stream.postscan (f n)
1553+--
1554+-- >>> s n = Stream.enumerateFromThen n (n - 1)
1555+-- >>> indexedR n = Stream.zipWith (,) (s n)
1556+--
1557+-- Pair each element in a stream with its index, starting from the
1558+-- given index @n@ and counting down.
1559+--
1560+-- >>> Stream.fold Fold.toList $ Stream.indexedR 10 $ Stream.fromList "hello"
1561+-- [(10,'h'),(9,'e'),(8,'l'),(7,'l'),(6,'o')]
1562+--
988{-# INLINE_NORMAL indexedR #-}
1563{-# INLINE_NORMAL indexedR #-}
989indexedR :: Monad m => Int -> Stream m a -> Stream m (Int, a)
1564indexedR :: Monad m => Int -> Stream m a -> Stream m (Int, a)
1565+-- indexedR n = scanMaybe (FL.indexingRev n)
990indexedR m (Stream step state) = Stream step' (state, m)
1566indexedR m (Stream step state) = Stream step' (state, m)
991 where
1567 where
992 {-# INLINE_LATE step' #-}
1568 {-# INLINE_LATE step' #-}
@@ -998,10 +1574,77 @@ indexedR m (Stream step state) = Stream step' (state, m)
998 Skip s -> return $ Skip (s, i)
1574 Skip s -> return $ Skip (s, i)
999 Stop -> return Stop
1575 Stop -> return Stop
1000
1576
1577+-------------------------------------------------------------------------------
1578+-- Time Indexing
1579+-------------------------------------------------------------------------------
1580+
1581+-- Note: The timestamp stream must be the second stream in the zip so that the
1582+-- timestamp is generated after generating the stream element and not before.
1583+-- If we do not do that then the following example will generate the same
1584+-- timestamp for first two elements:
1585+--
1586+-- Stream.fold Fold.toList $ Stream.timestamped $ Stream.delay $ Stream.enumerateFromTo 1 3
1587+
1588+-- | Pair each element in a stream with an absolute timestamp, using a clock of
1589+-- specified granularity. The timestamp is generated just before the element
1590+-- is consumed.
1591+--
1592+-- >>> Stream.fold Fold.toList $ Stream.timestampWith 0.01 $ Stream.delay 1 $ Stream.enumerateFromTo 1 3
1593+-- [(AbsTime (TimeSpec {sec = ..., nsec = ...}),1),(AbsTime (TimeSpec {sec = ..., nsec = ...}),2),(AbsTime (TimeSpec {sec = ..., nsec = ...}),3)]
1594+--
1595+-- /Pre-release/
1596+--
1597+{-# INLINE timestampWith #-}
1598+timestampWith :: (MonadIO m)
1599+ => Double -> Stream m a -> Stream m (AbsTime, a)
1600+timestampWith g stream = zipWith (flip (,)) stream (absTimesWith g)
1601+
1602+-- TBD: check performance vs a custom implementation without using zipWith.
1603+--
1604+-- /Pre-release/
1605+--
1606+{-# INLINE timestamped #-}
1607+timestamped :: (MonadIO m)
1608+ => Stream m a -> Stream m (AbsTime, a)
1609+timestamped = timestampWith 0.01
1610+
1611+-- | Pair each element in a stream with relative times starting from 0, using a
1612+-- clock with the specified granularity. The time is measured just before the
1613+-- element is consumed.
1614+--
1615+-- >>> Stream.fold Fold.toList $ Stream.timeIndexWith 0.01 $ Stream.delay 1 $ Stream.enumerateFromTo 1 3
1616+-- [(RelTime64 (NanoSecond64 ...),1),(RelTime64 (NanoSecond64 ...),2),(RelTime64 (NanoSecond64 ...),3)]
1617+--
1618+-- /Pre-release/
1619+--
1620+{-# INLINE timeIndexWith #-}
1621+timeIndexWith :: (MonadIO m)
1622+ => Double -> Stream m a -> Stream m (RelTime64, a)
1623+timeIndexWith g stream = zipWith (flip (,)) stream (relTimesWith g)
1624+
1625+-- | Pair each element in a stream with relative times starting from 0, using a
1626+-- 10 ms granularity clock. The time is measured just before the element is
1627+-- consumed.
1628+--
1629+-- >>> Stream.fold Fold.toList $ Stream.timeIndexed $ Stream.delay 1 $ Stream.enumerateFromTo 1 3
1630+-- [(RelTime64 (NanoSecond64 ...),1),(RelTime64 (NanoSecond64 ...),2),(RelTime64 (NanoSecond64 ...),3)]
1631+--
1632+-- /Pre-release/
1633+--
1634+{-# INLINE timeIndexed #-}
1635+timeIndexed :: (MonadIO m)
1636+ => Stream m a -> Stream m (RelTime64, a)
1637+timeIndexed = timeIndexWith 0.01
1638+
1001------------------------------------------------------------------------------
1639------------------------------------------------------------------------------
1002-- Searching
1640-- Searching
1003------------------------------------------------------------------------------
1641------------------------------------------------------------------------------
1004
1642
1643+-- | Find all the indices where the element in the stream satisfies the given
1644+-- predicate.
1645+--
1646+-- >>> findIndices p = Stream.scanMaybe (Fold.findIndices p)
1647+--
1005{-# INLINE_NORMAL findIndices #-}
1648{-# INLINE_NORMAL findIndices #-}
1006findIndices :: Monad m => (a -> Bool) -> Stream m a -> Stream m Int
1649findIndices :: Monad m => (a -> Bool) -> Stream m a -> Stream m Int
1007findIndices p (Stream step state) = Stream step' (state, 0)
1650findIndices p (Stream step state) = Stream step' (state, 0)
@@ -1014,6 +1657,15 @@ findIndices p (Stream step state) = Stream step' (state, 0)
1014 Skip s -> Skip (s, i)
1657 Skip s -> Skip (s, i)
1015 Stop -> Stop
1658 Stop -> Stop
1016
1659
1660+-- | Find all the indices where the value of the element in the stream is equal
1661+-- to the given value.
1662+--
1663+-- >>> elemIndices a = Stream.findIndices (== a)
1664+--
1665+{-# INLINE elemIndices #-}
1666+elemIndices :: (Monad m, Eq a) => a -> Stream m a -> Stream m Int
1667+elemIndices a = findIndices (== a)
1668+
1017{-# INLINE_NORMAL slicesBy #-}
1669{-# INLINE_NORMAL slicesBy #-}
1018slicesBy :: Monad m => (a -> Bool) -> Stream m a -> Stream m (Int, Int)
1670slicesBy :: Monad m => (a -> Bool) -> Stream m a -> Stream m (Int, Int)
1019slicesBy p (Stream step1 state1) = Stream step (Just (state1, 0, 0))
1671slicesBy p (Stream step1 state1) = Stream step (Just (state1, 0, 0))
@@ -1039,8 +1691,13 @@ slicesBy p (Stream step1 state1) = Stream step (Just (state1, 0, 0))
1039
1691
1040data RollingMapState s a = RollingMapGo s a
1692data RollingMapState s a = RollingMapGo s a
1041
1693
1694+-- | Like 'rollingMap' but with an effectful map function.
1695+--
1696+-- /Pre-release/
1697+--
1042{-# INLINE rollingMapM #-}
1698{-# INLINE rollingMapM #-}
1043rollingMapM :: Monad m => (Maybe a -> a -> m b) -> Stream m a -> Stream m b
1699rollingMapM :: Monad m => (Maybe a -> a -> m b) -> Stream m a -> Stream m b
1700+-- rollingMapM f = scanMaybe (FL.slide2 $ Window.rollingMapM f)
1044rollingMapM f (Stream step1 state1) = Stream step (RollingMapGo state1 Nothing)
1701rollingMapM f (Stream step1 state1) = Stream step (RollingMapGo state1 Nothing)
1045
1702
1046 where
1703 where
@@ -1054,16 +1711,31 @@ rollingMapM f (Stream step1 state1) = Stream step (RollingMapGo state1 Nothing)
1054 Skip s -> return $ Skip $ RollingMapGo s curr
1711 Skip s -> return $ Skip $ RollingMapGo s curr
1055 Stop -> return Stop
1712 Stop -> return Stop
1056
1713
1057−-- | rollingMap is a special case of an incremental sliding fold. It can be
1714+-- rollingMap is a special case of an incremental sliding fold. It can be
1058-- written as:
1715-- written as:
1059--
1716--
1060-- > fld f = slidingWindow 1 (Fold.foldl' (\_ (x,y) -> f y x)
1717-- > fld f = slidingWindow 1 (Fold.foldl' (\_ (x,y) -> f y x)
1061-- > rollingMap f = Stream.postscan (fld f) undefined
1718-- > rollingMap f = Stream.postscan (fld f) undefined
1719+
1720+-- | Apply a function on every two successive elements of a stream. The first
1721+-- argument of the map function is the previous element and the second argument
1722+-- is the current element. When the current element is the first element, the
1723+-- previous element is 'Nothing'.
1724+--
1725+-- /Pre-release/
1062--
1726--
1063{-# INLINE rollingMap #-}
1727{-# INLINE rollingMap #-}
1064rollingMap :: Monad m => (Maybe a -> a -> b) -> Stream m a -> Stream m b
1728rollingMap :: Monad m => (Maybe a -> a -> b) -> Stream m a -> Stream m b
1729+-- rollingMap f = scanMaybe (FL.slide2 $ Window.rollingMap f)
1065rollingMap f = rollingMapM (\x y -> return $ f x y)
1730rollingMap f = rollingMapM (\x y -> return $ f x y)
1066
1731
1732+-- | Like 'rollingMap' but requires at least two elements in the stream,
1733+-- returns an empty stream otherwise.
1734+--
1735+-- This is the stream equivalent of the list idiom @zipWith f xs (tail xs)@.
1736+--
1737+-- /Pre-release/
1738+--
1067{-# INLINE rollingMap2 #-}
1739{-# INLINE rollingMap2 #-}
1068rollingMap2 :: Monad m => (a -> a -> b) -> Stream m a -> Stream m b
1740rollingMap2 :: Monad m => (a -> a -> b) -> Stream m a -> Stream m b
1069rollingMap2 f = catMaybes . rollingMap g
1741rollingMap2 f = catMaybes . rollingMap g
@@ -1078,14 +1750,37 @@ rollingMap2 f = catMaybes . rollingMap g
1078------------------------------------------------------------------------------
1750------------------------------------------------------------------------------
1079
1751
1080-- XXX Will this always fuse properly?
1752-- XXX Will this always fuse properly?
1753+
1754+-- | Map a 'Maybe' returning function to a stream, filter out the 'Nothing'
1755+-- elements, and return a stream of values extracted from 'Just'.
1756+--
1757+-- Equivalent to:
1758+--
1759+-- >>> mapMaybe f = Stream.catMaybes . fmap f
1760+--
1081{-# INLINE_NORMAL mapMaybe #-}
1761{-# INLINE_NORMAL mapMaybe #-}
1082mapMaybe :: Monad m => (a -> Maybe b) -> Stream m a -> Stream m b
1762mapMaybe :: Monad m => (a -> Maybe b) -> Stream m a -> Stream m b
1083mapMaybe f = fmap fromJust . filter isJust . map f
1763mapMaybe f = fmap fromJust . filter isJust . map f
1084
1764
1765+-- | Like 'mapMaybe' but maps a monadic function.
1766+--
1767+-- Equivalent to:
1768+--
1769+-- >>> mapMaybeM f = Stream.catMaybes . Stream.mapM f
1770+--
1771+-- >>> mapM f = Stream.mapMaybeM (\x -> Just <$> f x)
1772+--
1085{-# INLINE_NORMAL mapMaybeM #-}
1773{-# INLINE_NORMAL mapMaybeM #-}
1086mapMaybeM :: Monad m => (a -> m (Maybe b)) -> Stream m a -> Stream m b
1774mapMaybeM :: Monad m => (a -> m (Maybe b)) -> Stream m a -> Stream m b
1087mapMaybeM f = fmap fromJust . filter isJust . mapM f
1775mapMaybeM f = fmap fromJust . filter isJust . mapM f
1088
1776
1777+-- | In a stream of 'Maybe's, discard 'Nothing's and unwrap 'Just's.
1778+--
1779+-- >>> catMaybes = Stream.mapMaybe id
1780+-- >>> catMaybes = fmap fromJust . Stream.filter isJust
1781+--
1782+-- /Pre-release/
1783+--
1089{-# INLINE catMaybes #-}
1784{-# INLINE catMaybes #-}
1090catMaybes :: Monad m => Stream m (Maybe a) -> Stream m a
1785catMaybes :: Monad m => Stream m (Maybe a) -> Stream m a
1091-- catMaybes = fmap fromJust . filter isJust
1786-- catMaybes = fmap fromJust . filter isJust
@@ -1107,7 +1802,43 @@ catMaybes (Stream step state) = Stream step1 state
1107
1802
1108-- | Use a filtering fold on a stream.
1803-- | Use a filtering fold on a stream.
1109--
1804--
1110−-- /Pre-release/
1805+-- >>> scanMaybe f = Stream.catMaybes . Stream.postscan f
1806+--
1111{-# INLINE scanMaybe #-}
1807{-# INLINE scanMaybe #-}
1112scanMaybe :: Monad m => Fold m a (Maybe b) -> Stream m a -> Stream m b
1808scanMaybe :: Monad m => Fold m a (Maybe b) -> Stream m a -> Stream m b
1113−scanMaybe f = catMaybes . postscanOnce f
1809+scanMaybe f = catMaybes . postscan f
1810+
1811+------------------------------------------------------------------------------
1812+-- Either streams
1813+------------------------------------------------------------------------------
1814+
1815+-- | Discard 'Right's and unwrap 'Left's in an 'Either' stream.
1816+--
1817+-- >>> catLefts = fmap (fromLeft undefined) . Stream.filter isLeft
1818+--
1819+-- /Pre-release/
1820+--
1821+{-# INLINE catLefts #-}
1822+catLefts :: Monad m => Stream m (Either a b) -> Stream m a
1823+catLefts = fmap (fromLeft undefined) . filter isLeft
1824+
1825+-- | Discard 'Left's and unwrap 'Right's in an 'Either' stream.
1826+--
1827+-- >>> catRights = fmap (fromRight undefined) . Stream.filter isRight
1828+--
1829+-- /Pre-release/
1830+--
1831+{-# INLINE catRights #-}
1832+catRights :: Monad m => Stream m (Either a b) -> Stream m b
1833+catRights = fmap (fromRight undefined) . filter isRight
1834+
1835+-- | Remove the either wrapper and flatten both lefts and as well as rights in
1836+-- the output stream.
1837+--
1838+-- >>> catEithers = fmap (either id id)
1839+--
1840+-- /Pre-release/
1841+--
1842+{-# INLINE catEithers #-}
1843+catEithers :: Monad m => Stream m (Either a a) -> Stream m a
1844+catEithers = fmap (either id id)
core/src/Streamly/Internal/Data/Stream/StreamD/Transformer.hs+68−2
@@ -16,8 +16,10 @@ module Streamly.Internal.Data.Stream.StreamD.Transformer
16 -- * Transform Inner Monad
16 -- * Transform Inner Monad
17 , liftInner
17 , liftInner
18 , runReaderT
18 , runReaderT
19+ , usingReaderT
19 , evalStateT
20 , evalStateT
20 , runStateT
21 , runStateT
22+ , usingStateT
21 )
23 )
22where
24where
23
25
@@ -34,6 +36,14 @@ import qualified Control.Monad.Trans.State.Strict as State
34
36
35import Streamly.Internal.Data.Stream.StreamD.Type
37import Streamly.Internal.Data.Stream.StreamD.Type
36
38
39+-- $setup
40+-- >>> :m
41+-- >>> import Control.Monad.Trans.Class (lift)
42+-- >>> import Control.Monad.Trans.Identity (runIdentityT)
43+-- >>> import qualified Streamly.Internal.Data.Stream as Stream
44+
45+-- | Lazy left fold to a transformer monad.
46+--
37{-# INLINE_NORMAL foldlT #-}
47{-# INLINE_NORMAL foldlT #-}
38foldlT :: (Monad m, Monad (s m), MonadTrans s)
48foldlT :: (Monad m, Monad (s m), MonadTrans s)
39 => (s m b -> a -> s m b) -> s m b -> Stream m a -> s m b
49 => (s m b -> a -> s m b) -> s m b -> Stream m a -> s m b
@@ -46,9 +56,19 @@ foldlT fstep begin (Stream step state) = go SPEC begin state
46 Skip s -> go SPEC acc s
56 Skip s -> go SPEC acc s
47 Stop -> acc
57 Stop -> acc
48
58
49−-- Right fold to some transformer (T) monad. This can be useful to implement
59+-- | Right fold to a transformer monad. This is the most general right fold
50−-- stateless combinators like map, filtering, insertions, takeWhile, dropWhile.
60+-- function. 'foldrS' is a special case of 'foldrT', however 'foldrS'
61+-- implementation can be more efficient:
62+--
63+-- >>> foldrS = Stream.foldrT
64+--
65+-- >>> step f x xs = lift $ f x (runIdentityT xs)
66+-- >>> foldrM f z s = runIdentityT $ Stream.foldrT (step f) (lift z) s
67+--
68+-- 'foldrT' can be used to translate streamly streams to other transformer
69+-- monads e.g. to a different streaming type.
51--
70--
71+-- /Pre-release/
52{-# INLINE_NORMAL foldrT #-}
72{-# INLINE_NORMAL foldrT #-}
53foldrT :: (Monad m, Monad (t m), MonadTrans t)
73foldrT :: (Monad m, Monad (t m), MonadTrans t)
54 => (a -> t m b -> t m b) -> t m b -> Stream m a -> t m b
74 => (a -> t m b -> t m b) -> t m b -> Stream m a -> t m b
@@ -66,6 +86,9 @@ foldrT f final (Stream step state) = go SPEC state
66-- Transform Inner Monad
86-- Transform Inner Monad
67-------------------------------------------------------------------------------
87-------------------------------------------------------------------------------
68
88
89+-- | Lift the inner monad @m@ of @Stream m a@ to @t m@ where @t@ is a monad
90+-- transformer.
91+--
69{-# INLINE_NORMAL liftInner #-}
92{-# INLINE_NORMAL liftInner #-}
70liftInner :: (Monad m, MonadTrans t, Monad (t m))
93liftInner :: (Monad m, MonadTrans t, Monad (t m))
71 => Stream m a -> Stream (t m) a
94 => Stream m a -> Stream (t m) a
@@ -79,6 +102,12 @@ liftInner (Stream step state) = Stream step' state
79 Skip s -> Skip s
102 Skip s -> Skip s
80 Stop -> Stop
103 Stop -> Stop
81
104
105+------------------------------------------------------------------------------
106+-- Sharing read only state in a stream
107+------------------------------------------------------------------------------
108+
109+-- | Evaluate the inner monad of a stream as 'ReaderT'.
110+--
82{-# INLINE_NORMAL runReaderT #-}
111{-# INLINE_NORMAL runReaderT #-}
83runReaderT :: Monad m => m s -> Stream (ReaderT s m) a -> Stream m a
112runReaderT :: Monad m => m s -> Stream (ReaderT s m) a -> Stream m a
84runReaderT env (Stream step state) = Stream step' (state, env)
113runReaderT env (Stream step state) = Stream step' (state, env)
@@ -92,6 +121,25 @@ runReaderT env (Stream step state) = Stream step' (state, env)
92 Skip s -> Skip (s, return sv)
121 Skip s -> Skip (s, return sv)
93 Stop -> Stop
122 Stop -> Stop
94
123
124+-- | Run a stream transformation using a given environment.
125+--
126+{-# INLINE usingReaderT #-}
127+usingReaderT
128+ :: Monad m
129+ => m r
130+ -> (Stream (ReaderT r m) a -> Stream (ReaderT r m) a)
131+ -> Stream m a
132+ -> Stream m a
133+usingReaderT r f xs = runReaderT r $ f $ liftInner xs
134+
135+------------------------------------------------------------------------------
136+-- Sharing read write state in a stream
137+------------------------------------------------------------------------------
138+
139+-- | Evaluate the inner monad of a stream as 'StateT'.
140+--
141+-- >>> evalStateT s = fmap snd . Stream.runStateT s
142+--
95{-# INLINE_NORMAL evalStateT #-}
143{-# INLINE_NORMAL evalStateT #-}
96evalStateT :: Monad m => m s -> Stream (StateT s m) a -> Stream m a
144evalStateT :: Monad m => m s -> Stream (StateT s m) a -> Stream m a
97evalStateT initial (Stream step state) = Stream step' (state, initial)
145evalStateT initial (Stream step state) = Stream step' (state, initial)
@@ -105,6 +153,9 @@ evalStateT initial (Stream step state) = Stream step' (state, initial)
105 Skip s -> Skip (s, return sv')
153 Skip s -> Skip (s, return sv')
106 Stop -> Stop
154 Stop -> Stop
107
155
156+-- | Evaluate the inner monad of a stream as 'StateT' and emit the resulting
157+-- state and value pair after each step.
158+--
108{-# INLINE_NORMAL runStateT #-}
159{-# INLINE_NORMAL runStateT #-}
109runStateT :: Monad m => m s -> Stream (StateT s m) a -> Stream m (s, a)
160runStateT :: Monad m => m s -> Stream (StateT s m) a -> Stream m (s, a)
110runStateT initial (Stream step state) = Stream step' (state, initial)
161runStateT initial (Stream step state) = Stream step' (state, initial)
@@ -117,3 +168,18 @@ runStateT initial (Stream step state) = Stream step' (state, initial)
117 Yield x s -> Yield (sv', x) (s, return sv')
168 Yield x s -> Yield (sv', x) (s, return sv')
118 Skip s -> Skip (s, return sv')
169 Skip s -> Skip (s, return sv')
119 Stop -> Stop
170 Stop -> Stop
171+
172+-- | Run a stateful (StateT) stream transformation using a given state.
173+--
174+-- >>> usingStateT s f = Stream.evalStateT s . f . Stream.liftInner
175+--
176+-- See also: 'scan'
177+--
178+{-# INLINE usingStateT #-}
179+usingStateT
180+ :: Monad m
181+ => m s
182+ -> (Stream (StateT s m) a -> Stream (StateT s m) a)
183+ -> Stream m a
184+ -> Stream m a
185+usingStateT s f = evalStateT s . f . liftInner
core/src/Streamly/Internal/Data/Stream/StreamD/Type.hs+744−64
@@ -1,4 +1,4 @@
1−#include "inline.hs"
1+{-# LANGUAGE UndecidableInstances #-}
2
2
3-- |
3-- |
4-- Module : Streamly.Internal.Data.Stream.StreamD.Type
4-- Module : Streamly.Internal.Data.Stream.StreamD.Type
@@ -17,127 +17,172 @@ module Streamly.Internal.Data.Stream.StreamD.Type
17 (
17 (
18 -- * The stream type
18 -- * The stream type
19 Step (..)
19 Step (..)
20− -- XXX UnStream is exported to avoid a performance issue in concatMap if we
20+ -- XXX UnStream is exported to avoid a performance issue in some
21− -- use the pattern synonym "Stream".
21+ -- combinators if we use the pattern synonym "Stream".
22 , Stream (Stream, UnStream)
22 , Stream (Stream, UnStream)
23
23
24− -- * Primitives
24+ -- * CrossStream type wrapper
25− , nilM
25+ , CrossStream
26− , consM
26+ , unCross
27− , uncons
27+ , mkCross
28+
29+ -- * Conversion to StreamK
30+ , fromStreamK
31+ , toStreamK
28
32
29 -- * From Unfold
33 -- * From Unfold
30 , unfold
34 , unfold
31
35
36+ -- * Construction
37+ -- ** Primitives
38+ , nilM
39+ , consM
40+
32− -- * From Values
41+ -- ** From Values
33 , fromPure
42 , fromPure
34 , fromEffect
43 , fromEffect
35
44
36− -- * From Containers
45+ -- ** From Containers
37− , fromList
46+ , Streamly.Internal.Data.Stream.StreamD.Type.fromList
38
47
39− -- * Conversions From/To
48+ -- * Elimination
40− , fromStreamK
49+ -- ** Primitives
41− , toStreamK
50+ , uncons
42
51
43− -- * Running a 'Fold'
52+ -- ** Strict Left Folds
44− , fold
53+ , Streamly.Internal.Data.Stream.StreamD.Type.fold
45 , foldBreak
54 , foldBreak
46− , foldContinue
55+ , foldAddLazy
56+ , foldAdd
47 , foldEither
57 , foldEither
48
58
49− -- * Right Folds
59+ , Streamly.Internal.Data.Stream.StreamD.Type.foldl'
50− , foldrM
51− , foldrMx
52− , foldr
53− , foldrS
54−
55− -- * Left Folds
56− , foldl'
57 , foldlM'
60 , foldlM'
58 , foldlx'
61 , foldlx'
59 , foldlMx'
62 , foldlMx'
60
63
61− -- * Special Folds
64+ -- ** Lazy Right Folds
62− , drain
65+ , foldrM
63−
66+ , foldrMx
64− -- * To Containers
67+ , Streamly.Internal.Data.Stream.StreamD.Type.foldr
65− , toList
68+ , foldrS
66
69
67− -- * Multi-stream folds
70+ -- ** Specific Folds
68− , eqBy
71+ , drain
69− , cmpBy
72+ , Streamly.Internal.Data.Stream.StreamD.Type.toList
70
73
71− -- * Transformations
74+ -- * Mapping
72 , map
75 , map
73 , mapM
76 , mapM
77+
78+ -- * Stateful Filters
74 , take
79 , take
75 , takeWhile
80 , takeWhile
76 , takeWhileM
81 , takeWhileM
77 , takeEndBy
82 , takeEndBy
78 , takeEndByM
83 , takeEndByM
79
84
80− -- * Nesting
85+ -- * Combining Two Streams
86+ -- ** Zipping
87+ , zipWithM
88+ , zipWith
89+
90+ -- ** Cross Product
81 , crossApply
91 , crossApply
82 , crossApplyFst
92 , crossApplyFst
83 , crossApplySnd
93 , crossApplySnd
94+ , crossWith
95+ , cross
84
96
97+ -- * Unfold Many
85 , ConcatMapUState (..)
98 , ConcatMapUState (..)
86 , unfoldMany
99 , unfoldMany
87
100
101+ -- * Concat
102+ , concatEffect
88 , concatMap
103 , concatMap
89 , concatMapM
104 , concatMapM
90− , concatEffect
105+ , concat
91
106
92− -- * Expanding trees top down
107+ -- * Unfold Iterate
93 , unfoldIterateDfs
108 , unfoldIterateDfs
94 , unfoldIterateBfs
109 , unfoldIterateBfs
95 , unfoldIterateBfsRev
110 , unfoldIterateBfsRev
96
111
112+ -- * Concat Iterate
97 , concatIterateScan
113 , concatIterateScan
98 , concatIterateDfs
114 , concatIterateDfs
99 , concatIterateBfs
115 , concatIterateBfs
100 , concatIterateBfsRev
116 , concatIterateBfsRev
101
117
118+ -- * Fold Many
102 , FoldMany (..) -- for inspection testing
119 , FoldMany (..) -- for inspection testing
103 , FoldManyPost (..)
120 , FoldManyPost (..)
104 , foldMany
121 , foldMany
105 , foldManyPost
122 , foldManyPost
106 , chunksOf
123 , chunksOf
107−
108 , refoldMany
124 , refoldMany
109
125
110− -- * Folding trees bottom up
126+ -- * Fold Iterate
111 , reduceIterateBfs
127 , reduceIterateBfs
112 , foldIterateBfs
128 , foldIterateBfs
129+
130+ -- * Multi-stream folds
131+ , eqBy
132+ , cmpBy
113 )
133 )
114where
134where
115
135
136+#include "inline.hs"
137+
116import Control.Applicative (liftA2)
138import Control.Applicative (liftA2)
139+import Control.Monad.Catch (MonadThrow, throwM)
140+import Control.Monad.Trans.Class (MonadTrans(lift))
141+import Control.Monad.IO.Class (MonadIO(..))
142+import Data.Foldable (Foldable(foldl'), fold, foldr)
117import Data.Functor (($>))
143import Data.Functor (($>))
118import Data.Functor.Identity (Identity(..))
144import Data.Functor.Identity (Identity(..))
145+import Data.Maybe (fromMaybe)
146+import Data.Semigroup (Endo(..))
119import Fusion.Plugin.Types (Fuse(..))
147import Fusion.Plugin.Types (Fuse(..))
120import GHC.Base (build)
148import GHC.Base (build)
149+import GHC.Exts (IsList(..), IsString(..), oneShot)
121import GHC.Types (SPEC(..))
150import GHC.Types (SPEC(..))
122−import Prelude hiding (map, mapM, foldr, take, concatMap, takeWhile)
151+import Prelude hiding (map, mapM, take, concatMap, takeWhile, zipWith, concat)
152+import Text.Read
153+ ( Lexeme(Ident), lexP, parens, prec, readPrec, readListPrec
154+ , readListPrecDefault)
123
155
156+import Streamly.Internal.BaseCompat ((#.))
124import Streamly.Internal.Data.Fold.Type (Fold(..))
157import Streamly.Internal.Data.Fold.Type (Fold(..))
158+import Streamly.Internal.Data.Maybe.Strict (Maybe'(..), toMaybe)
125import Streamly.Internal.Data.Refold.Type (Refold(..))
159import Streamly.Internal.Data.Refold.Type (Refold(..))
126import Streamly.Internal.Data.Stream.StreamD.Step (Step (..))
160import Streamly.Internal.Data.Stream.StreamD.Step (Step (..))
127import Streamly.Internal.Data.SVar.Type (State, adaptState, defState)
161import Streamly.Internal.Data.SVar.Type (State, adaptState, defState)
128import Streamly.Internal.Data.Unfold.Type (Unfold(..))
162import Streamly.Internal.Data.Unfold.Type (Unfold(..))
129
163
130−import qualified Streamly.Internal.Data.Fold.Type as FL
164+import qualified Streamly.Internal.Data.Fold.Type as FL hiding (foldr)
131import qualified Streamly.Internal.Data.Stream.StreamK.Type as K
165import qualified Streamly.Internal.Data.Stream.StreamK.Type as K
132#ifdef USE_UNFOLDS_EVERYWHERE
166#ifdef USE_UNFOLDS_EVERYWHERE
133import qualified Streamly.Internal.Data.Unfold.Type as Unfold
167import qualified Streamly.Internal.Data.Unfold.Type as Unfold
134#endif
168#endif
135
169
170+-- $setup
171+-- >>> import Streamly.Internal.Data.Stream (CrossStream(..))
172+-- >>> import qualified Streamly.Data.Fold as Fold
173+-- >>> import qualified Streamly.Data.Parser as Parser
174+-- >>> import qualified Streamly.Data.Stream as Stream
175+-- >>> import qualified Streamly.Data.Unfold as Unfold
176+-- >>> import qualified Streamly.Internal.Data.Stream as Stream
177+-- >>> import qualified Streamly.Internal.FileSystem.Dir as Dir
178+-- >>> import qualified Streamly.Internal.Data.Unfold as Unfold
179+
136------------------------------------------------------------------------------
180------------------------------------------------------------------------------
137-- The direct style stream type
181-- The direct style stream type
138------------------------------------------------------------------------------
182------------------------------------------------------------------------------
139
183
140-- gst = global state
184-- gst = global state
185+
141-- | A stream consists of a step function that generates the next step given a
186-- | A stream consists of a step function that generates the next step given a
142-- current state, and the current state.
187-- current state, and the current state.
143data Stream m a =
188data Stream m a =
@@ -160,11 +205,19 @@ pattern Stream step state <- (unShare -> UnStream step state)
160-- Primitives
205-- Primitives
161------------------------------------------------------------------------------
206------------------------------------------------------------------------------
162
207
163−-- | An empty 'Stream' with a side effect.
208+-- | A stream that terminates without producing any output, but produces a side
209+-- effect.
210+--
211+-- >>> Stream.fold Fold.toList (Stream.nilM (print "nil"))
212+-- "nil"
213+-- []
214+--
215+-- /Pre-release/
164{-# INLINE_NORMAL nilM #-}
216{-# INLINE_NORMAL nilM #-}
165nilM :: Applicative m => m b -> Stream m a
217nilM :: Applicative m => m b -> Stream m a
166nilM m = Stream (\_ _ -> m $> Stop) ()
218nilM m = Stream (\_ _ -> m $> Stop) ()
167
219
220+-- | Like 'cons' but fuses an effect instead of a pure value.
168{-# INLINE_NORMAL consM #-}
221{-# INLINE_NORMAL consM #-}
169consM :: Applicative m => m a -> Stream m a -> Stream m a
222consM :: Applicative m => m a -> Stream m a -> Stream m a
170consM m (Stream step state) = Stream step1 Nothing
223consM m (Stream step state) = Stream step1 Nothing
@@ -179,7 +232,35 @@ consM m (Stream step state) = Stream step1 Nothing
179 Skip s -> Skip (Just s)
232 Skip s -> Skip (Just s)
180 Stop -> Stop) <$> step gst st
233 Stop -> Stop) <$> step gst st
181
234
182−-- | Does not fuse, has the same performance as the StreamK version.
235+-- | Decompose a stream into its head and tail. If the stream is empty, returns
236+-- 'Nothing'. If the stream is non-empty, returns @Just (a, ma)@, where @a@ is
237+-- the head of the stream and @ma@ its tail.
238+--
239+-- Properties:
240+--
241+-- >>> Nothing <- Stream.uncons Stream.nil
242+-- >>> Just ("a", t) <- Stream.uncons (Stream.cons "a" Stream.nil)
243+--
244+-- This can be used to consume the stream in an imperative manner one element
245+-- at a time, as it just breaks down the stream into individual elements and we
246+-- can loop over them as we deem fit. For example, this can be used to convert
247+-- a streamly stream into other stream types.
248+--
249+-- All the folds in this module can be expressed in terms of 'uncons', however,
250+-- this is generally less efficient than specific folds because it takes apart
251+-- the stream one element at a time, therefore, does not take adavantage of
252+-- stream fusion.
253+--
254+-- 'foldBreak' is a more general way of consuming a stream piecemeal.
255+--
256+-- >>> :{
257+-- uncons xs = do
258+-- r <- Stream.foldBreak Fold.one xs
259+-- return $ case r of
260+-- (Nothing, _) -> Nothing
261+-- (Just h, t) -> Just (h, t)
262+-- :}
263+--
183{-# INLINE_NORMAL uncons #-}
264{-# INLINE_NORMAL uncons #-}
184uncons :: Monad m => Stream m a -> m (Maybe (a, Stream m a))
265uncons :: Monad m => Stream m a -> m (Maybe (a, Stream m a))
185uncons (UnStream step state) = go SPEC state
266uncons (UnStream step state) = go SPEC state
@@ -197,7 +278,13 @@ uncons (UnStream step state) = go SPEC state
197
278
198data UnfoldState s = UnfoldNothing | UnfoldJust s
279data UnfoldState s = UnfoldNothing | UnfoldJust s
199
280
200−-- | Convert an 'Unfold' into a 'Stream' by supplying it a seed.
281+-- | Convert an 'Unfold' into a stream by supplying it an input seed.
282+--
283+-- >>> s = Stream.unfold Unfold.replicateM (3, putStrLn "hello")
284+-- >>> Stream.fold Fold.drain s
285+-- hello
286+-- hello
287+-- hello
201--
288--
202{-# INLINE_NORMAL unfold #-}
289{-# INLINE_NORMAL unfold #-}
203unfold :: Applicative m => Unfold m a b -> a -> Stream m b
290unfold :: Applicative m => Unfold m a b -> a -> Stream m b
@@ -217,7 +304,12 @@ unfold (Unfold ustep inject) seed = Stream step UnfoldNothing
217-- From Values
304-- From Values
218------------------------------------------------------------------------------
305------------------------------------------------------------------------------
219
306
220−-- | Create a singleton 'Stream' from a pure value.
307+-- | Create a singleton stream from a pure value.
308+--
309+-- >>> fromPure a = a `Stream.cons` Stream.nil
310+-- >>> fromPure = pure
311+-- >>> fromPure = fromEffect . pure
312+--
221{-# INLINE_NORMAL fromPure #-}
313{-# INLINE_NORMAL fromPure #-}
222fromPure :: Applicative m => a -> Stream m a
314fromPure :: Applicative m => a -> Stream m a
223fromPure x = Stream (\_ s -> pure $ step undefined s) True
315fromPure x = Stream (\_ s -> pure $ step undefined s) True
@@ -226,7 +318,14 @@ fromPure x = Stream (\_ s -> pure $ step undefined s) True
226 step _ True = Yield x False
318 step _ True = Yield x False
227 step _ False = Stop
319 step _ False = Stop
228
320
229−-- | Create a singleton 'Stream' from a monadic action.
321+-- | Create a singleton stream from a monadic action.
322+--
323+-- >>> fromEffect m = m `consM` Stream.nil
324+-- >>> fromEffect = Stream.sequence . Stream.fromPure
325+--
326+-- >>> Stream.fold Fold.drain $ Stream.fromEffect (putStrLn "hello")
327+-- hello
328+--
230{-# INLINE_NORMAL fromEffect #-}
329{-# INLINE_NORMAL fromEffect #-}
231fromEffect :: Applicative m => m a -> Stream m a
330fromEffect :: Applicative m => m a -> Stream m a
232fromEffect m = Stream step True
331fromEffect m = Stream step True
@@ -242,7 +341,8 @@ fromEffect m = Stream step True
242------------------------------------------------------------------------------
341------------------------------------------------------------------------------
243
342
244-- Adapted from the vector package.
343-- Adapted from the vector package.
344+
245−-- | Convert a list of pure values to a 'Stream'
345+-- | Construct a stream from a list of pure values.
246{-# INLINE_LATE fromList #-}
346{-# INLINE_LATE fromList #-}
247fromList :: Applicative m => [a] -> Stream m a
347fromList :: Applicative m => [a] -> Stream m a
248#ifdef USE_UNFOLDS_EVERYWHERE
348#ifdef USE_UNFOLDS_EVERYWHERE
@@ -295,12 +395,38 @@ toStreamK (Stream step state) = go state
295-- Running a 'Fold'
395-- Running a 'Fold'
296------------------------------------------------------------------------------
396------------------------------------------------------------------------------
297
397
398+-- >>> fold f = Fold.extractM . Stream.foldAddLazy f
399+-- >>> fold f = Stream.fold Fold.one . Stream.foldManyPost f
400+-- >>> fold f = Fold.extractM <=< Stream.foldAdd f
401+
402+-- | Fold a stream using the supplied left 'Fold' and reducing the resulting
403+-- expression strictly at each step. The behavior is similar to 'foldl''. A
404+-- 'Fold' can terminate early without consuming the full stream. See the
405+-- documentation of individual 'Fold's for termination behavior.
406+--
407+-- Definitions:
408+--
409+-- >>> fold f = fmap fst . Stream.foldBreak f
410+-- >>> fold f = Stream.parse (Parser.fromFold f)
411+--
412+-- Example:
413+--
414+-- >>> Stream.fold Fold.sum (Stream.enumerateFromTo 1 100)
415+-- 5050
416+--
298{-# INLINE_NORMAL fold #-}
417{-# INLINE_NORMAL fold #-}
299fold :: Monad m => Fold m a b -> Stream m a -> m b
418fold :: Monad m => Fold m a b -> Stream m a -> m b
300fold fld strm = do
419fold fld strm = do
301 (b, _) <- foldBreak fld strm
420 (b, _) <- foldBreak fld strm
302 return b
421 return b
303
422
423+-- | Fold resulting in either breaking the stream or continuation of the fold.
424+-- Instead of supplying the input stream in one go we can run the fold multiple
425+-- times, each time supplying the next segment of the input stream. If the fold
426+-- has not yet finished it returns a fold that can be run again otherwise it
427+-- returns the fold result and the residual stream.
428+--
429+-- /Internal/
304{-# INLINE_NORMAL foldEither #-}
430{-# INLINE_NORMAL foldEither #-}
305foldEither :: Monad m =>
431foldEither :: Monad m =>
306 Fold m a b -> Stream m a -> m (Either (Fold m a b) (b, Stream m a))
432 Fold m a b -> Stream m a -> m (Either (Fold m a b) (b, Stream m a))
@@ -324,6 +450,9 @@ foldEither (Fold fstep begin done) (UnStream step state) = do
324 Skip s -> go SPEC fs s
450 Skip s -> go SPEC fs s
325 Stop -> return $! Left (Fold fstep (return $ FL.Partial fs) done)
451 Stop -> return $! Left (Fold fstep (return $ FL.Partial fs) done)
326
452
453+-- | Like 'fold' but also returns the remaining stream. The resulting stream
454+-- would be 'Stream.nil' if the stream finished before the fold.
455+--
327{-# INLINE_NORMAL foldBreak #-}
456{-# INLINE_NORMAL foldBreak #-}
328foldBreak :: Monad m => Fold m a b -> Stream m a -> m (b, Stream m a)
457foldBreak :: Monad m => Fold m a b -> Stream m a -> m (b, Stream m a)
329foldBreak fld strm = do
458foldBreak fld strm = do
@@ -342,9 +471,18 @@ foldBreak fld strm = do
342
471
343 nil = Stream (\_ _ -> return Stop) ()
472 nil = Stream (\_ _ -> return Stop) ()
344
473
474+-- | Append a stream to a fold lazily to build an accumulator incrementally.
475+--
476+-- Example, to continue folding a list of streams on the same sum fold:
477+--
478+-- >>> streams = [Stream.fromList [1..5], Stream.fromList [6..10]]
479+-- >>> f = Prelude.foldl Stream.foldAddLazy Fold.sum streams
480+-- >>> Stream.fold f Stream.nil
481+-- 55
482+--
345−{-# INLINE_NORMAL foldContinue #-}
483+{-# INLINE_NORMAL foldAddLazy #-}
346−foldContinue :: Monad m => Fold m a b -> Stream m a -> Fold m a b
484+foldAddLazy :: Monad m => Fold m a b -> Stream m a -> Fold m a b
347−foldContinue (Fold fstep finitial fextract) (Stream sstep state) =
485+foldAddLazy (Fold fstep finitial fextract) (Stream sstep state) =
348 Fold fstep initial fextract
486 Fold fstep initial fextract
349
487
350 where
488 where
@@ -367,6 +505,15 @@ foldContinue (Fold fstep finitial fextract) (Stream sstep state) =
367 Skip s -> go SPEC fs s
505 Skip s -> go SPEC fs s
368 Stop -> return $ FL.Partial fs
506 Stop -> return $ FL.Partial fs
369
507
508+-- >>> foldAdd f = Stream.foldAddLazy f >=> Fold.reduce
509+
510+-- |
511+-- >>> foldAdd = flip Fold.addStream
512+--
513+foldAdd :: Monad m => Fold m a b -> Stream m a -> m (Fold m a b)
514+foldAdd f =
515+ Streamly.Internal.Data.Stream.StreamD.Type.fold (FL.duplicate f)
516+
370------------------------------------------------------------------------------
517------------------------------------------------------------------------------
371-- Right Folds
518-- Right Folds
372------------------------------------------------------------------------------
519------------------------------------------------------------------------------
@@ -391,6 +538,23 @@ foldContinue (Fold fstep finitial fextract) (Stream sstep state) =
391--
538--
392-- S.foldrM (\x t -> if x then return t else return False) (return True)
539-- S.foldrM (\x t -> if x then return t else return False) (return True)
393-- (S.fromList [False,undefined] :: Stream IO Bool)
540-- (S.fromList [False,undefined] :: Stream IO Bool)
541+
542+-- | Right associative/lazy pull fold. @foldrM build final stream@ constructs
543+-- an output structure using the step function @build@. @build@ is invoked with
544+-- the next input element and the remaining (lazy) tail of the output
545+-- structure. It builds a lazy output expression using the two. When the "tail
546+-- structure" in the output expression is evaluated it calls @build@ again thus
547+-- lazily consuming the input @stream@ until either the output expression built
548+-- by @build@ is free of the "tail" or the input is exhausted in which case
549+-- @final@ is used as the terminating case for the output structure. For more
550+-- details see the description in the previous section.
551+--
552+-- Example, determine if any element is 'odd' in a stream:
553+--
554+-- >>> s = Stream.fromList (2:4:5:undefined)
555+-- >>> step x xs = if odd x then return True else xs
556+-- >>> Stream.foldrM step (return False) s
557+-- True
394--
558--
395{-# INLINE_NORMAL foldrM #-}
559{-# INLINE_NORMAL foldrM #-}
396foldrM :: Monad m => (a -> m b -> m b) -> m b -> Stream m a -> m b
560foldrM :: Monad m => (a -> m b -> m b) -> m b -> Stream m a -> m b
@@ -425,6 +589,18 @@ foldrMx fstep final convert (Stream step state) = convert $ go SPEC state
425-- monads. For example, if "any" is implemented using "foldr" instead of
589-- monads. For example, if "any" is implemented using "foldr" instead of
426-- "foldrM" it performs the same with Identity monad but performs 1000x slower
590-- "foldrM" it performs the same with Identity monad but performs 1000x slower
427-- with IO monad.
591-- with IO monad.
592+
593+-- | Right fold, lazy for lazy monads and pure streams, and strict for strict
594+-- monads.
595+--
596+-- Please avoid using this routine in strict monads like IO unless you need a
597+-- strict right fold. This is provided only for use in lazy monads (e.g.
598+-- Identity) or pure streams. Note that with this signature it is not possible
599+-- to implement a lazy foldr when the monad @m@ is strict. In that case it
600+-- would be strict in its accumulator and therefore would necessarily consume
601+-- all its input.
602+--
603+-- >>> foldr f z = Stream.foldrM (\a b -> f a <$> b) (return z)
428--
604--
429{-# INLINE_NORMAL foldr #-}
605{-# INLINE_NORMAL foldr #-}
430foldr :: Monad m => (a -> b -> b) -> b -> Stream m a -> m b
606foldr :: Monad m => (a -> b -> b) -> b -> Stream m a -> m b
@@ -520,7 +696,7 @@ drain (Stream step state) = go SPEC state
520
696
521{-# INLINE_NORMAL toList #-}
697{-# INLINE_NORMAL toList #-}
522toList :: Monad m => Stream m a -> m [a]
698toList :: Monad m => Stream m a -> m [a]
523−toList = foldr (:) []
699+toList = Streamly.Internal.Data.Stream.StreamD.Type.foldr (:) []
524
700
525-- Use foldr/build fusion to fuse with list consumers
701-- Use foldr/build fusion to fuse with list consumers
526-- This can be useful when using the IsList instance
702-- This can be useful when using the IsList instance
@@ -533,7 +709,7 @@ toListFB c n (Stream step state) = go state
533 Skip s -> go s
709 Skip s -> go s
534 Stop -> n
710 Stop -> n
535
711
536−{-# RULES "toList Identity" toList = toListId #-}
712+{-# RULES "toList Identity" Streamly.Internal.Data.Stream.StreamD.Type.toList = toListId #-}
537{-# INLINE_EARLY toListId #-}
713{-# INLINE_EARLY toListId #-}
538toListId :: Stream Identity a -> Identity [a]
714toListId :: Stream Identity a -> Identity [a]
539toListId s = Identity $ build (\c n -> toListFB c n s)
715toListId s = Identity $ build (\c n -> toListFB c n s)
@@ -543,6 +719,8 @@ toListId s = Identity $ build (\c n -> toListFB c n s)
543------------------------------------------------------------------------------
719------------------------------------------------------------------------------
544
720
545-- Adapted from the vector package.
721-- Adapted from the vector package.
722+
723+-- | Compare two streams for equality
546{-# INLINE_NORMAL eqBy #-}
724{-# INLINE_NORMAL eqBy #-}
547eqBy :: Monad m => (a -> b -> Bool) -> Stream m a -> Stream m b -> m Bool
725eqBy :: Monad m => (a -> b -> Bool) -> Stream m a -> Stream m b -> m Bool
548eqBy eq (Stream step1 t1) (Stream step2 t2) = eq_loop0 SPEC t1 t2
726eqBy eq (Stream step1 t1) (Stream step2 t2) = eq_loop0 SPEC t1 t2
@@ -571,7 +749,8 @@ eqBy eq (Stream step1 t1) (Stream step2 t2) = eq_loop0 SPEC t1 t2
571 Stop -> return True
749 Stop -> return True
572
750
573-- Adapted from the vector package.
751-- Adapted from the vector package.
752+
574−-- | Compare two streams lexicographically
753+-- | Compare two streams lexicographically.
575{-# INLINE_NORMAL cmpBy #-}
754{-# INLINE_NORMAL cmpBy #-}
576cmpBy
755cmpBy
577 :: Monad m
756 :: Monad m
@@ -606,7 +785,17 @@ cmpBy cmp (Stream step1 t1) (Stream step2 t2) = cmp_loop0 SPEC t1 t2
606------------------------------------------------------------------------------
785------------------------------------------------------------------------------
607
786
608-- Adapted from the vector package.
787-- Adapted from the vector package.
609−-- | Map a monadic function over a 'Stream'
788+
789+-- |
790+-- >>> mapM f = Stream.sequence . fmap f
791+--
792+-- Apply a monadic function to each element of the stream and replace it with
793+-- the output of the resulting action.
794+--
795+-- >>> s = Stream.fromList ["a", "b", "c"]
796+-- >>> Stream.fold Fold.drain $ Stream.mapM putStr s
797+-- abc
798+--
610{-# INLINE_NORMAL mapM #-}
799{-# INLINE_NORMAL mapM #-}
611mapM :: Monad m => (a -> m b) -> Stream m a -> Stream m b
800mapM :: Monad m => (a -> m b) -> Stream m a -> Stream m b
612mapM f (Stream step state) = Stream step' state
801mapM f (Stream step state) = Stream step' state
@@ -633,11 +822,149 @@ instance Functor m => Functor (Stream m) where
633 {-# INLINE (<$) #-}
822 {-# INLINE (<$) #-}
634 (<$) = fmap . const
823 (<$) = fmap . const
635
824
825+------------------------------------------------------------------------------
826+-- Lists
827+------------------------------------------------------------------------------
828+
829+-- XXX Show instance is 10x slower compared to read, we can do much better.
830+-- The list show instance itself is really slow.
831+
832+-- XXX The default definitions of "<" in the Ord instance etc. do not perform
833+-- well, because they do not get inlined. Need to add INLINE in Ord class in
834+-- base?
835+
836+instance IsList (Stream Identity a) where
837+ type (Item (Stream Identity a)) = a
838+
839+ {-# INLINE fromList #-}
840+ fromList = Streamly.Internal.Data.Stream.StreamD.Type.fromList
841+
842+ {-# INLINE toList #-}
843+ toList = runIdentity . Streamly.Internal.Data.Stream.StreamD.Type.toList
844+
845+instance Eq a => Eq (Stream Identity a) where
846+ {-# INLINE (==) #-}
847+ (==) xs ys = runIdentity $ eqBy (==) xs ys
848+
849+instance Ord a => Ord (Stream Identity a) where
850+ {-# INLINE compare #-}
851+ compare xs ys = runIdentity $ cmpBy compare xs ys
852+
853+ {-# INLINE (<) #-}
854+ x < y =
855+ case compare x y of
856+ LT -> True
857+ _ -> False
858+
859+ {-# INLINE (<=) #-}
860+ x <= y =
861+ case compare x y of
862+ GT -> False
863+ _ -> True
864+
865+ {-# INLINE (>) #-}
866+ x > y =
867+ case compare x y of
868+ GT -> True
869+ _ -> False
870+
871+ {-# INLINE (>=) #-}
872+ x >= y =
873+ case compare x y of
874+ LT -> False
875+ _ -> True
876+
877+ {-# INLINE max #-}
878+ max x y = if x <= y then y else x
879+
880+ {-# INLINE min #-}
881+ min x y = if x <= y then x else y
882+
883+instance Show a => Show (Stream Identity a) where
884+ showsPrec p dl = showParen (p > 10) $
885+ showString "fromList " . shows (GHC.Exts.toList dl)
886+
887+instance Read a => Read (Stream Identity a) where
888+ readPrec = parens $ prec 10 $ do
889+ Ident "fromList" <- lexP
890+ Streamly.Internal.Data.Stream.StreamD.Type.fromList <$> readPrec
891+
892+ readListPrec = readListPrecDefault
893+
894+instance (a ~ Char) => IsString (Stream Identity a) where
895+ {-# INLINE fromString #-}
896+ fromString = Streamly.Internal.Data.Stream.StreamD.Type.fromList
897+
898+-------------------------------------------------------------------------------
899+-- Foldable
900+-------------------------------------------------------------------------------
901+
902+-- The default Foldable instance has several issues:
903+-- 1) several definitions do not have INLINE on them, so we provide
904+-- re-implementations with INLINE pragmas.
905+-- 2) the definitions of sum/product/maximum/minimum are inefficient as they
906+-- use right folds, they cannot run in constant memory. We provide
907+-- implementations using strict left folds here.
908+
909+-- There is no Traversable instance because, there is no scalable cons for
910+-- StreamD, use toList and fromList instead.
911+
912+instance (Foldable m, Monad m) => Foldable (Stream m) where
913+
914+ {-# INLINE foldMap #-}
915+ foldMap f =
916+ Data.Foldable.fold
917+ . Streamly.Internal.Data.Stream.StreamD.Type.foldr (mappend . f) mempty
918+
919+ {-# INLINE foldr #-}
920+ foldr f z t = appEndo (foldMap (Endo #. f) t) z
921+
922+ {-# INLINE foldl' #-}
923+ foldl' f z0 xs = Data.Foldable.foldr f' id xs z0
924+ where f' x k = oneShot $ \z -> k $! f z x
925+
926+ {-# INLINE length #-}
927+ length = Data.Foldable.foldl' (\n _ -> n + 1) 0
928+
929+ {-# INLINE elem #-}
930+ elem = any . (==)
931+
932+ {-# INLINE maximum #-}
933+ maximum =
934+ fromMaybe (errorWithoutStackTrace "maximum: empty stream")
935+ . toMaybe
936+ . Data.Foldable.foldl' getMax Nothing'
937+
938+ where
939+
940+ getMax Nothing' x = Just' x
941+ getMax (Just' mx) x = Just' $! max mx x
942+
943+ {-# INLINE minimum #-}
944+ minimum =
945+ fromMaybe (errorWithoutStackTrace "minimum: empty stream")
946+ . toMaybe
947+ . Data.Foldable.foldl' getMin Nothing'
948+
949+ where
950+
951+ getMin Nothing' x = Just' x
952+ getMin (Just' mn) x = Just' $! min mn x
953+
954+ {-# INLINE sum #-}
955+ sum = Data.Foldable.foldl' (+) 0
956+
957+ {-# INLINE product #-}
958+ product = Data.Foldable.foldl' (*) 1
959+
636-------------------------------------------------------------------------------
960-------------------------------------------------------------------------------
637-- Filtering
961-- Filtering
638-------------------------------------------------------------------------------
962-------------------------------------------------------------------------------
639
963
640-- Adapted from the vector package.
964-- Adapted from the vector package.
965+
966+-- | Take first 'n' elements from the stream and discard the rest.
967+--
641{-# INLINE_NORMAL take #-}
968{-# INLINE_NORMAL take #-}
642take :: Applicative m => Int -> Stream m a -> Stream m a
969take :: Applicative m => Int -> Stream m a -> Stream m a
643take n (Stream step state) = n `seq` Stream step' (state, 0)
970take n (Stream step state) = n `seq` Stream step' (state, 0)
@@ -653,8 +980,12 @@ take n (Stream step state) = n `seq` Stream step' (state, 0)
653 step' _ (_, _) = pure Stop
980 step' _ (_, _) = pure Stop
654
981
655-- Adapted from the vector package.
982-- Adapted from the vector package.
983+
984+-- | Same as 'takeWhile' but with a monadic predicate.
985+--
656{-# INLINE_NORMAL takeWhileM #-}
986{-# INLINE_NORMAL takeWhileM #-}
657takeWhileM :: Monad m => (a -> m Bool) -> Stream m a -> Stream m a
987takeWhileM :: Monad m => (a -> m Bool) -> Stream m a -> Stream m a
988+-- takeWhileM p = scanMaybe (FL.takingEndByM_ (\x -> not <$> p x))
658takeWhileM f (Stream step state) = Stream step' state
989takeWhileM f (Stream step state) = Stream step' state
659 where
990 where
660 {-# INLINE_LATE step' #-}
991 {-# INLINE_LATE step' #-}
@@ -667,6 +998,8 @@ takeWhileM f (Stream step state) = Stream step' state
667 Skip s -> return $ Skip s
998 Skip s -> return $ Skip s
668 Stop -> return Stop
999 Stop -> return Stop
669
1000
1001+-- | End the stream as soon as the predicate fails on an element.
1002+--
670{-# INLINE takeWhile #-}
1003{-# INLINE takeWhile #-}
671takeWhile :: Monad m => (a -> Bool) -> Stream m a -> Stream m a
1004takeWhile :: Monad m => (a -> Bool) -> Stream m a -> Stream m a
672takeWhile f = takeWhileM (return . f)
1005takeWhile f = takeWhileM (return . f)
@@ -697,10 +1030,64 @@ takeEndByM f (Stream step state) = Stream step' (Just state)
697takeEndBy :: Monad m => (a -> Bool) -> Stream m a -> Stream m a
1030takeEndBy :: Monad m => (a -> Bool) -> Stream m a -> Stream m a
698takeEndBy f = takeEndByM (return . f)
1031takeEndBy f = takeEndByM (return . f)
699
1032
1033+------------------------------------------------------------------------------
1034+-- Zipping
1035+------------------------------------------------------------------------------
1036+
1037+-- | Like 'zipWith' but using a monadic zipping function.
1038+--
1039+{-# INLINE_NORMAL zipWithM #-}
1040+zipWithM :: Monad m
1041+ => (a -> b -> m c) -> Stream m a -> Stream m b -> Stream m c
1042+zipWithM f (Stream stepa ta) (Stream stepb tb) = Stream step (ta, tb, Nothing)
1043+ where
1044+ {-# INLINE_LATE step #-}
1045+ step gst (sa, sb, Nothing) = do
1046+ r <- stepa (adaptState gst) sa
1047+ return $
1048+ case r of
1049+ Yield x sa' -> Skip (sa', sb, Just x)
1050+ Skip sa' -> Skip (sa', sb, Nothing)
1051+ Stop -> Stop
1052+
1053+ step gst (sa, sb, Just x) = do
1054+ r <- stepb (adaptState gst) sb
1055+ case r of
1056+ Yield y sb' -> do
1057+ z <- f x y
1058+ return $ Yield z (sa, sb', Nothing)
1059+ Skip sb' -> return $ Skip (sa, sb', Just x)
1060+ Stop -> return Stop
1061+
1062+{-# RULES "zipWithM xs xs"
1063+ forall f xs. zipWithM @Identity f xs xs = mapM (\x -> f x x) xs #-}
1064+
1065+-- | Stream @a@ is evaluated first, followed by stream @b@, the resulting
1066+-- elements @a@ and @b@ are then zipped using the supplied zip function and the
1067+-- result @c@ is yielded to the consumer.
1068+--
1069+-- If stream @a@ or stream @b@ ends, the zipped stream ends. If stream @b@ ends
1070+-- first, the element @a@ from previous evaluation of stream @a@ is discarded.
1071+--
1072+-- >>> s1 = Stream.fromList [1,2,3]
1073+-- >>> s2 = Stream.fromList [4,5,6]
1074+-- >>> Stream.fold Fold.toList $ Stream.zipWith (+) s1 s2
1075+-- [5,7,9]
1076+--
1077+{-# INLINE zipWith #-}
1078+zipWith :: Monad m => (a -> b -> c) -> Stream m a -> Stream m b -> Stream m c
1079+zipWith f = zipWithM (\a b -> return (f a b))
1080+
700------------------------------------------------------------------------------
1081------------------------------------------------------------------------------
701-- Combine N Streams - concatAp
1082-- Combine N Streams - concatAp
702------------------------------------------------------------------------------
1083------------------------------------------------------------------------------
703
1084
1085+-- | Apply a stream of functions to a stream of values and flatten the results.
1086+--
1087+-- Note that the second stream is evaluated multiple times.
1088+--
1089+-- >>> crossApply = Stream.crossWith id
1090+--
704{-# INLINE_NORMAL crossApply #-}
1091{-# INLINE_NORMAL crossApply #-}
705crossApply :: Functor f => Stream f (a -> b) -> Stream f a -> Stream f b
1092crossApply :: Functor f => Stream f (a -> b) -> Stream f a -> Stream f b
706crossApply (Stream stepa statea) (Stream stepb stateb) =
1093crossApply (Stream stepa statea) (Stream stepb stateb) =
@@ -786,6 +1173,39 @@ instance Applicative f => Applicative (Stream f) where
786 (<*) = crossApplyFst
1173 (<*) = crossApplyFst
787-}
1174-}
788
1175
1176+-- |
1177+-- Definition:
1178+--
1179+-- >>> crossWith f m1 m2 = fmap f m1 `Stream.crossApply` m2
1180+--
1181+-- Note that the second stream is evaluated multiple times.
1182+--
1183+{-# INLINE crossWith #-}
1184+crossWith :: Monad m => (a -> b -> c) -> Stream m a -> Stream m b -> Stream m c
1185+crossWith f m1 m2 = fmap f m1 `crossApply` m2
1186+
1187+-- | Given a @Stream m a@ and @Stream m b@ generate a stream with all possible
1188+-- combinations of the tuple @(a, b)@.
1189+--
1190+-- Definition:
1191+--
1192+-- >>> cross = Stream.crossWith (,)
1193+--
1194+-- The second stream is evaluated multiple times. If that is not desired it can
1195+-- be cached in an 'Data.Array.Array' and then generated from the array before
1196+-- calling this function. Caching may also improve performance if the stream is
1197+-- expensive to evaluate.
1198+--
1199+-- See 'Streamly.Internal.Data.Unfold.cross' for a much faster fused
1200+-- alternative.
1201+--
1202+-- Time: O(m x n)
1203+--
1204+-- /Pre-release/
1205+{-# INLINE cross #-}
1206+cross :: Monad m => Stream m a -> Stream m b -> Stream m (a, b)
1207+cross = crossWith (,)
1208+
789------------------------------------------------------------------------------
1209------------------------------------------------------------------------------
790-- Combine N Streams - unfoldMany
1210-- Combine N Streams - unfoldMany
791------------------------------------------------------------------------------
1211------------------------------------------------------------------------------
@@ -804,6 +1224,10 @@ data ConcatMapUState o i =
804-- optimization via fusion. This can be many times more efficient than
1224-- optimization via fusion. This can be many times more efficient than
805-- 'concatMap'.
1225-- 'concatMap'.
806
1226
1227+-- | Like 'concatMap' but uses an 'Unfold' for stream generation. Unlike
1228+-- 'concatMap' this can fuse the 'Unfold' code with the inner loop and
1229+-- therefore provide many times better performance.
1230+--
807{-# INLINE_NORMAL unfoldMany #-}
1231{-# INLINE_NORMAL unfoldMany #-}
808unfoldMany :: Monad m => Unfold m a b -> Stream m a -> Stream m b
1232unfoldMany :: Monad m => Unfold m a b -> Stream m a -> Stream m b
809unfoldMany (Unfold istep inject) (Stream ostep ost) =
1233unfoldMany (Unfold istep inject) (Stream ostep ost) =
@@ -831,6 +1255,14 @@ unfoldMany (Unfold istep inject) (Stream ostep ost) =
831------------------------------------------------------------------------------
1255------------------------------------------------------------------------------
832
1256
833-- Adapted from the vector package.
1257-- Adapted from the vector package.
1258+
1259+-- | Map a stream producing monadic function on each element of the stream
1260+-- and then flatten the results into a single stream. Since the stream
1261+-- generation function is monadic, unlike 'concatMap', it can produce an
1262+-- effect at the beginning of each iteration of the inner loop.
1263+--
1264+-- See 'unfoldMany' for a fusible alternative.
1265+--
834{-# INLINE_NORMAL concatMapM #-}
1266{-# INLINE_NORMAL concatMapM #-}
835concatMapM :: Monad m => (a -> m (Stream m b)) -> Stream m a -> Stream m b
1267concatMapM :: Monad m => (a -> m (Stream m b)) -> Stream m a -> Stream m b
836concatMapM f (Stream step state) = Stream step' (Left state)
1268concatMapM f (Stream step state) = Stream step' (Left state)
@@ -861,10 +1293,28 @@ concatMapM f (Stream step state) = Stream step' (Left state)
861 return $ Skip (Right (Stream inner_step inner_s, st))
1293 return $ Skip (Right (Stream inner_step inner_s, st))
862 Stop -> return $ Skip (Left st)
1294 Stop -> return $ Skip (Left st)
863
1295
1296+-- | Map a stream producing function on each element of the stream and then
1297+-- flatten the results into a single stream.
1298+--
1299+-- >>> concatMap f = Stream.concatMapM (return . f)
1300+-- >>> concatMap f = Stream.concat . fmap f
1301+-- >>> concatMap f = Stream.unfoldMany (Unfold.lmap f Unfold.fromStream)
1302+--
1303+-- See 'unfoldMany' for a fusible alternative.
1304+--
864{-# INLINE concatMap #-}
1305{-# INLINE concatMap #-}
865concatMap :: Monad m => (a -> Stream m b) -> Stream m a -> Stream m b
1306concatMap :: Monad m => (a -> Stream m b) -> Stream m a -> Stream m b
866concatMap f = concatMapM (return . f)
1307concatMap f = concatMapM (return . f)
867
1308
1309+-- | Flatten a stream of streams to a single stream.
1310+--
1311+-- >>> concat = Stream.concatMap id
1312+--
1313+-- /Pre-release/
1314+{-# INLINE concat #-}
1315+concat :: Monad m => Stream m (Stream m a) -> Stream m a
1316+concat = concatMap id
1317+
868-- XXX The idea behind this rule is to rewrite any calls to "concatMap
1318-- XXX The idea behind this rule is to rewrite any calls to "concatMap
869-- fromArray" automatically to flattenArrays which is much faster. However, we
1319-- fromArray" automatically to flattenArrays which is much faster. However, we
870-- need an INLINE_EARLY on concatMap for this rule to fire. But if we use
1320-- need an INLINE_EARLY on concatMap for this rule to fire. But if we use
@@ -876,10 +1326,16 @@ concatMap f = concatMapM (return . f)
876-- {-# RULES "concatMap Array.toStreamD"
1326-- {-# RULES "concatMap Array.toStreamD"
877-- concatMap Array.toStreamD = Array.flattenArray #-}
1327-- concatMap Array.toStreamD = Array.flattenArray #-}
878
1328
879−-- |
1329+-- >>> concatEffect = Stream.concat . lift -- requires (MonadTrans t)
880−-- Definition:
1330+-- >>> concatEffect = join . lift -- requires (MonadTrans t, Monad (Stream m))
1331+
1332+-- | Given a stream value in the underlying monad, lift and join the underlying
1333+-- monad with the stream monad.
1334+--
1335+-- >>> concatEffect = Stream.concat . Stream.fromEffect
1336+-- >>> concatEffect eff = Stream.concatMapM (\() -> eff) (fromPure ())
881--
1337--
882−-- > concatEffect generator = concatMapM (\() -> generator) (fromPure ())
1338+-- See also: 'concat', 'sequence'
883--
1339--
884{-# INLINE concatEffect #-}
1340{-# INLINE concatEffect #-}
885concatEffect :: Monad m => m (Stream m a) -> Stream m a
1341concatEffect :: Monad m => m (Stream m a) -> Stream m a
@@ -903,6 +1359,13 @@ instance Monad m => Monad (Stream m) where
903-- Traversing a tree top down
1359-- Traversing a tree top down
904------------------------------------------------------------------------------
1360------------------------------------------------------------------------------
905
1361
1362+-- Next stream is to be generated by the return value of the previous stream. A
1363+-- general intuitive way of doing that could be to use an appending monad
1364+-- instance for streams where the result of the previous stream is used to
1365+-- generate the next one. In the first pass we can just emit the values in the
1366+-- stream and keep building a buffered list/stream, once done we can then
1367+-- process the buffered stream.
1368+
906-- | Generate a stream from an initial state, scan and concat the stream,
1369-- | Generate a stream from an initial state, scan and concat the stream,
907-- generate a stream again from the final state of the previous scan and repeat
1370-- generate a stream again from the final state of the previous scan and repeat
908-- the process.
1371-- the process.
@@ -938,9 +1401,11 @@ concatIterateScan scanner generate initial = Stream step (Left initial)
938-- have to store any state. This makes the stored state proportional to the
1401-- have to store any state. This makes the stored state proportional to the
939-- number of non-leaf nodes rather than total number of nodes.
1402-- number of non-leaf nodes rather than total number of nodes.
940
1403
1404+-- | Same as 'concatIterateBfs' except that the traversal of the last
1405+-- element on a level is emitted first and then going backwards up to the first
941−-- | This function may be slightly faster than concatIterateBfs because it
1406+-- element (reversed ordering). This may be slightly faster than
942−-- traverses the elements on a level in reverse order, therefore, does not have
1407+-- 'concatIterateBfs'.
943−-- to reverse the list stroing those.
1408+--
944{-# INLINE_NORMAL concatIterateBfsRev #-}
1409{-# INLINE_NORMAL concatIterateBfsRev #-}
945concatIterateBfsRev :: Monad m =>
1410concatIterateBfsRev :: Monad m =>
946 (a -> Maybe (Stream m a))
1411 (a -> Maybe (Stream m a))
@@ -966,6 +1431,17 @@ concatIterateBfsRev f stream = Stream step (stream, [])
966 (y:ys) -> return $ Skip (y, ys)
1431 (y:ys) -> return $ Skip (y, ys)
967 [] -> return Stop
1432 [] -> return Stop
968
1433
1434+-- | Similar to 'concatIterateDfs' except that it traverses the stream in
1435+-- breadth first style (BFS). First, all the elements in the input stream are
1436+-- emitted, and then their traversals are emitted.
1437+--
1438+-- Example, list a directory tree using BFS:
1439+--
1440+-- >>> f = either (Just . Dir.readEitherPaths) (const Nothing)
1441+-- >>> input = Stream.fromPure (Left ".")
1442+-- >>> ls = Stream.concatIterateBfs f input
1443+--
1444+-- /Pre-release/
969{-# INLINE_NORMAL concatIterateBfs #-}
1445{-# INLINE_NORMAL concatIterateBfs #-}
970concatIterateBfs :: Monad m =>
1446concatIterateBfs :: Monad m =>
971 (a -> Maybe (Stream m a))
1447 (a -> Maybe (Stream m a))
@@ -994,6 +1470,19 @@ concatIterateBfs f stream = Stream step (stream, [], [])
994 (x:xs1) -> return $ Skip (x, xs1, [])
1470 (x:xs1) -> return $ Skip (x, xs1, [])
995 [] -> return Stop
1471 [] -> return Stop
996
1472
1473+-- | Traverse the stream in depth first style (DFS). Map each element in the
1474+-- input stream to a stream and flatten, recursively map the resulting elements
1475+-- as well to a stream and flatten until no more streams are generated.
1476+--
1477+-- Example, list a directory tree using DFS:
1478+--
1479+-- >>> f = either (Just . Dir.readEitherPaths) (const Nothing)
1480+-- >>> input = Stream.fromPure (Left ".")
1481+-- >>> ls = Stream.concatIterateDfs f input
1482+--
1483+-- This is equivalent to using @concatIterateWith StreamK.append@.
1484+--
1485+-- /Pre-release/
997{-# INLINE_NORMAL concatIterateDfs #-}
1486{-# INLINE_NORMAL concatIterateDfs #-}
998concatIterateDfs :: Monad m =>
1487concatIterateDfs :: Monad m =>
999 (a -> Maybe (Stream m a))
1488 (a -> Maybe (Stream m a))
@@ -1024,6 +1513,15 @@ data IterateUnfoldState o i =
1024 IterateUnfoldOuter o
1513 IterateUnfoldOuter o
1025 | IterateUnfoldInner o i [i]
1514 | IterateUnfoldInner o i [i]
1026
1515
1516+-- | Same as @concatIterateDfs@ but more efficient due to stream fusion.
1517+--
1518+-- Example, list a directory tree using DFS:
1519+--
1520+-- >>> f = Unfold.either Dir.eitherReaderPaths Unfold.nil
1521+-- >>> input = Stream.fromPure (Left ".")
1522+-- >>> ls = Stream.unfoldIterateDfs f input
1523+--
1524+-- /Pre-release/
1027{-# INLINE_NORMAL unfoldIterateDfs #-}
1525{-# INLINE_NORMAL unfoldIterateDfs #-}
1028unfoldIterateDfs :: Monad m =>
1526unfoldIterateDfs :: Monad m =>
1029 Unfold m a a
1527 Unfold m a a
@@ -1061,6 +1559,10 @@ data IterateUnfoldBFSRevState o i =
1061 IterateUnfoldBFSRevOuter o [i]
1559 IterateUnfoldBFSRevOuter o [i]
1062 | IterateUnfoldBFSRevInner i [i]
1560 | IterateUnfoldBFSRevInner i [i]
1063
1561
1562+-- | Like 'unfoldIterateBfs' but processes the children in reverse order,
1563+-- therefore, may be slightly faster.
1564+--
1565+-- /Pre-release/
1064{-# INLINE_NORMAL unfoldIterateBfsRev #-}
1566{-# INLINE_NORMAL unfoldIterateBfsRev #-}
1065unfoldIterateBfsRev :: Monad m =>
1567unfoldIterateBfsRev :: Monad m =>
1066 Unfold m a a
1568 Unfold m a a
@@ -1101,6 +1603,9 @@ data IterateUnfoldBFSState o i =
1101 IterateUnfoldBFSOuter o [i]
1603 IterateUnfoldBFSOuter o [i]
1102 | IterateUnfoldBFSInner i [i] [i]
1604 | IterateUnfoldBFSInner i [i] [i]
1103
1605
1606+-- | Like 'unfoldIterateDfs' but uses breadth first style traversal.
1607+--
1608+-- /Pre-release/
1104{-# INLINE_NORMAL unfoldIterateBfs #-}
1609{-# INLINE_NORMAL unfoldIterateBfs #-}
1105unfoldIterateBfs :: Monad m =>
1610unfoldIterateBfs :: Monad m =>
1106 Unfold m a a
1611 Unfold m a a
@@ -1143,9 +1648,10 @@ unfoldIterateBfs (Unfold istep inject) (Stream ostep ost) =
1143-- Folding a tree bottom up
1648-- Folding a tree bottom up
1144------------------------------------------------------------------------------
1649------------------------------------------------------------------------------
1145
1650
1146−-- | Binary BFS style reduce, folds a level entirely, before starting to fold
1651+-- | Binary BFS style reduce, folds a level entirely using the supplied fold
1652+-- function, collecting the outputs as next level of the tree, then repeats the
1147−-- the next level. The last elements of a previously folded level are folded
1653+-- same process on the next level. The last elements of a previously folded
1148−-- first.
1654+-- level are folded first.
1149{-# INLINE_NORMAL reduceIterateBfs #-}
1655{-# INLINE_NORMAL reduceIterateBfs #-}
1150reduceIterateBfs :: Monad m =>
1656reduceIterateBfs :: Monad m =>
1151 (a -> a -> m a) -> Stream m a -> m (Maybe a)
1657 (a -> a -> m a) -> Stream m a -> m (Maybe a)
@@ -1206,7 +1712,35 @@ data FoldManyPost s fs b a
1206 | FoldManyPostYield b (FoldManyPost s fs b a)
1712 | FoldManyPostYield b (FoldManyPost s fs b a)
1207 | FoldManyPostDone
1713 | FoldManyPostDone
1208
1714
1715+-- XXX Need a more intuitive name, and need to reconcile the names
1716+-- foldMany/fold/parse/parseMany/parseManyPost etc.
1717+
1718+-- | Like 'foldMany' but evaluates the fold before the stream, and yields its
1719+-- output even if the stream is empty, therefore, always results in a non-empty
1720+-- output even on an empty stream (default result of the fold).
1721+--
1722+-- Example, empty stream:
1723+--
1724+-- >>> f = Fold.take 2 Fold.sum
1209−-- | 'Streamly.Internal.Data.Stream.foldManyPost'.
1725+-- >>> fmany = Stream.fold Fold.toList . Stream.foldManyPost f
1726+-- >>> fmany $ Stream.fromList []
1727+-- [0]
1728+--
1729+-- Example, last fold empty:
1730+--
1731+-- >>> fmany $ Stream.fromList [1..4]
1732+-- [3,7,0]
1733+--
1734+-- Example, last fold non-empty:
1735+--
1736+-- >>> fmany $ Stream.fromList [1..5]
1737+-- [3,7,5]
1738+--
1739+-- Note that using a closed fold e.g. @Fold.take 0@, would result in an
1740+-- infinite stream without consuming the input.
1741+--
1742+-- /Pre-release/
1743+--
1210{-# INLINE_NORMAL foldManyPost #-}
1744{-# INLINE_NORMAL foldManyPost #-}
1211foldManyPost :: Monad m => Fold m a b -> Stream m a -> Stream m b
1745foldManyPost :: Monad m => Fold m a b -> Stream m a -> Stream m b
1212foldManyPost (Fold fstep initial extract) (Stream step state) =
1746foldManyPost (Fold fstep initial extract) (Stream step state) =
@@ -1252,7 +1786,34 @@ data FoldMany s fs b a
1252
1786
1253-- XXX Nested foldMany does not fuse.
1787-- XXX Nested foldMany does not fuse.
1254
1788
1255−-- | 'Streamly.Internal.Data.Stream.foldMany'.
1789+-- | Apply a 'Fold' repeatedly on a stream and emit the results in the
1790+-- output stream. Unlike 'foldManyPost' it evaluates the fold after the stream,
1791+-- therefore, an empty input stream results in an empty output stream.
1792+--
1793+-- Definition:
1794+--
1795+-- >>> foldMany f = Stream.parseMany (Parser.fromFold f)
1796+--
1797+-- Example, empty stream:
1798+--
1799+-- >>> f = Fold.take 2 Fold.sum
1800+-- >>> fmany = Stream.fold Fold.toList . Stream.foldMany f
1801+-- >>> fmany $ Stream.fromList []
1802+-- []
1803+--
1804+-- Example, last fold empty:
1805+--
1806+-- >>> fmany $ Stream.fromList [1..4]
1807+-- [3,7]
1808+--
1809+-- Example, last fold non-empty:
1810+--
1811+-- >>> fmany $ Stream.fromList [1..5]
1812+-- [3,7,5]
1813+--
1814+-- Note that using a closed fold e.g. @Fold.take 0@, would result in an
1815+-- infinite stream on a non-empty input stream.
1816+--
1256{-# INLINE_NORMAL foldMany #-}
1817{-# INLINE_NORMAL foldMany #-}
1257foldMany :: Monad m => Fold m a b -> Stream m a -> Stream m b
1818foldMany :: Monad m => Fold m a b -> Stream m a -> Stream m b
1258foldMany (Fold fstep initial extract) (Stream step state) =
1819foldMany (Fold fstep initial extract) (Stream step state) =
@@ -1340,3 +1901,122 @@ refoldMany (Refold fstep inject extract) action (Stream step state) =
1340 return $ Skip (FoldManyYield b FoldManyDone)
1901 return $ Skip (FoldManyYield b FoldManyDone)
1341 step' _ (FoldManyYield b next) = return $ Yield b next
1902 step' _ (FoldManyYield b next) = return $ Yield b next
1342 step' _ FoldManyDone = return Stop
1903 step' _ FoldManyDone = return Stop
1904+
1905+------------------------------------------------------------------------------
1906+-- Stream with a cross product style monad instance
1907+------------------------------------------------------------------------------
1908+
1909+-- XXX CrossStream performs better than the CrossStreamK when nesting two
1910+-- loops, however, CrossStreamK seems to be better for more than two nestings,
1911+-- need to do more perf investigation.
1912+
1913+-- | A newtype wrapper for the 'Stream' type with a cross product style monad
1914+-- instance.
1915+--
1916+-- A 'Monad' bind behaves like a @for@ loop:
1917+--
1918+-- >>> :{
1919+-- Stream.fold Fold.toList $ Stream.unCross $ do
1920+-- x <- Stream.mkCross $ Stream.fromList [1,2]
1921+-- -- Perform the following actions for each x in the stream
1922+-- return x
1923+-- :}
1924+-- [1,2]
1925+--
1926+-- Nested monad binds behave like nested @for@ loops:
1927+--
1928+-- >>> :{
1929+-- Stream.fold Fold.toList $ Stream.unCross $ do
1930+-- x <- Stream.mkCross $ Stream.fromList [1,2]
1931+-- y <- Stream.mkCross $ Stream.fromList [3,4]
1932+-- -- Perform the following actions for each x, for each y
1933+-- return (x, y)
1934+-- :}
1935+-- [(1,3),(1,4),(2,3),(2,4)]
1936+--
1937+newtype CrossStream m a = CrossStream {unCrossStream :: Stream m a}
1938+ deriving (Functor, Foldable)
1939+
1940+{-# INLINE mkCross #-}
1941+mkCross :: Stream m a -> CrossStream m a
1942+mkCross = CrossStream
1943+
1944+{-# INLINE unCross #-}
1945+unCross :: CrossStream m a -> Stream m a
1946+unCross = unCrossStream
1947+
1948+-- Pure (Identity monad) stream instances
1949+deriving instance IsList (CrossStream Identity a)
1950+deriving instance (a ~ Char) => IsString (CrossStream Identity a)
1951+deriving instance Eq a => Eq (CrossStream Identity a)
1952+deriving instance Ord a => Ord (CrossStream Identity a)
1953+
1954+-- Do not use automatic derivation for this to show as "fromList" rather than
1955+-- "fromList Identity".
1956+instance Show a => Show (CrossStream Identity a) where
1957+ {-# INLINE show #-}
1958+ show (CrossStream xs) = show xs
1959+
1960+instance Read a => Read (CrossStream Identity a) where
1961+ {-# INLINE readPrec #-}
1962+ readPrec = fmap CrossStream readPrec
1963+
1964+------------------------------------------------------------------------------
1965+-- Applicative
1966+------------------------------------------------------------------------------
1967+
1968+-- Note: we need to define all the typeclass operations because we want to
1969+-- INLINE them.
1970+instance Monad m => Applicative (CrossStream m) where
1971+ {-# INLINE pure #-}
1972+ pure x = CrossStream (fromPure x)
1973+
1974+ {-# INLINE (<*>) #-}
1975+ (CrossStream s1) <*> (CrossStream s2) =
1976+ CrossStream (crossApply s1 s2)
1977+
1978+ {-# INLINE liftA2 #-}
1979+ liftA2 f x = (<*>) (fmap f x)
1980+
1981+ {-# INLINE (*>) #-}
1982+ (CrossStream s1) *> (CrossStream s2) =
1983+ CrossStream (crossApplySnd s1 s2)
1984+
1985+ {-# INLINE (<*) #-}
1986+ (CrossStream s1) <* (CrossStream s2) =
1987+ CrossStream (crossApplyFst s1 s2)
1988+
1989+------------------------------------------------------------------------------
1990+-- Monad
1991+------------------------------------------------------------------------------
1992+
1993+instance Monad m => Monad (CrossStream m) where
1994+ return = pure
1995+
1996+ -- Benchmarks better with StreamD bind and pure:
1997+ -- toList, filterAllout, *>, *<, >> (~2x)
1998+ --
1999+
2000+ -- Benchmarks better with CPS bind and pure:
2001+ -- Prime sieve (25x)
2002+ -- n binds, breakAfterSome, filterAllIn, state transformer (~2x)
2003+ --
2004+ {-# INLINE (>>=) #-}
2005+ (>>=) (CrossStream m) f = CrossStream (concatMap (unCrossStream . f) m)
2006+
2007+ {-# INLINE (>>) #-}
2008+ (>>) = (*>)
2009+
2010+------------------------------------------------------------------------------
2011+-- Transformers
2012+------------------------------------------------------------------------------
2013+
2014+instance (MonadIO m) => MonadIO (CrossStream m) where
2015+ liftIO x = CrossStream (fromEffect $ liftIO x)
2016+
2017+instance MonadTrans CrossStream where
2018+ {-# INLINE lift #-}
2019+ lift x = CrossStream (fromEffect x)
2020+
2021+instance (MonadThrow m) => MonadThrow (CrossStream m) where
2022+ throwM = lift . throwM
core/src/Streamly/Internal/Data/Stream/StreamDK.hs+41−145
@@ -1,156 +1,52 @@
1−#include "inline.hs"
2−
3-- |
1-- |
4-- Module : Streamly.Internal.Data.Stream.StreamDK
2-- Module : Streamly.Internal.Data.Stream.StreamDK
5-- Copyright : (c) 2019 Composewell Technologies
3-- Copyright : (c) 2019 Composewell Technologies
6−-- License : BSD3
4+-- License : BSD-3-Clause
7-- Maintainer : streamly@composewell.com
5-- Maintainer : streamly@composewell.com
8-- Stability : experimental
6-- Stability : experimental
9-- Portability : GHC
7-- Portability : GHC
10--
8--
11−
9+--
10+-- This module has the following problems due to rewrite rules:
11+--
12+-- * Rewrite rules lead to optimization problems, blocking fusion in some
13+-- cases, specifically when combining multiple operations e.g. (filter . drop).
14+-- * Rewrite rules lead to problems when calling a function recursively. For
15+-- example, the StreamD version of foldBreak cannot be used recursively when
16+-- wrapped in rewrite rules because each recursive call adds a roundtrip
17+-- conversion from D to K and back to D. We can use the StreamK versions of
18+-- these though because the rewrite rule gets eliminated in that case.
19+-- * If we have a unified module, we need two different versions of several
20+-- operations e.g. appendK and appendD, both are useful in different cases.
21+--
12module Streamly.Internal.Data.Stream.StreamDK
22module Streamly.Internal.Data.Stream.StreamDK
13− (
14− -- * Stream Type
23+ ( module Streamly.Internal.Data.Stream.Type
15−
24+ , module Streamly.Internal.Data.Stream.Bottom
16− Stream
25+ , module Streamly.Internal.Data.Stream.Eliminate
17− , Step (..)
26+ , module Streamly.Internal.Data.Stream.Exception
18−
27+ , module Streamly.Internal.Data.Stream.Expand
19− -- * Construction
28+ , module Streamly.Internal.Data.Stream.Generate
20− , nil
29+ , module Streamly.Internal.Data.Stream.Lift
21− , cons
30+ , module Streamly.Internal.Data.Stream.Reduce
22− , consM
31+ , module Streamly.Internal.Data.Stream.Transform
23− , unfoldr
32+ , module Streamly.Internal.Data.Stream.Cross
24− , unfoldrM
33+ , module Streamly.Internal.Data.Stream.Zip
25− , replicateM
34+
26−
35+ -- modules having dependencies on libraries other than base
27− -- * Folding
36+ , module Streamly.Internal.Data.Stream.Transformer
28− , uncons
29− , foldrS
30−
31− -- * Specific Folds
32− , drain
33 )
37 )
34where
38where
35
39
36−import Streamly.Internal.Data.Stream.StreamDK.Type (Stream(..), Step(..))
40+import Streamly.Internal.Data.Stream.Bottom
37−
41+import Streamly.Internal.Data.Stream.Cross
38−-------------------------------------------------------------------------------
42+import Streamly.Internal.Data.Stream.Eliminate
39−-- Construction
43+import Streamly.Internal.Data.Stream.Exception
40−-------------------------------------------------------------------------------
44+import Streamly.Internal.Data.Stream.Expand
41−
45+import Streamly.Internal.Data.Stream.Generate
42−nil :: Monad m => Stream m a
46+import Streamly.Internal.Data.Stream.Lift
43−nil = Stream $ return Stop
47+import Streamly.Internal.Data.Stream.Reduce
44−
48+import Streamly.Internal.Data.Stream.Transform
45−{-# INLINE_NORMAL cons #-}
49+import Streamly.Internal.Data.Stream.Type
46−cons :: Monad m => a -> Stream m a -> Stream m a
50+import Streamly.Internal.Data.Stream.Zip
47−cons x xs = Stream $ return $ Yield x xs
51+
48−
52+import Streamly.Internal.Data.Stream.Transformer
49−consM :: Monad m => m a -> Stream m a -> Stream m a
50−consM eff xs = Stream $ eff >>= \x -> return $ Yield x xs
51−
52−unfoldrM :: Monad m => (s -> m (Maybe (a, s))) -> s -> Stream m a
53−unfoldrM next state = Stream (step' state)
54− where
55− step' st = do
56− r <- next st
57− return $ case r of
58− Just (x, s) -> Yield x (Stream (step' s))
59− Nothing -> Stop
60−{-
61−unfoldrM next s0 = buildM $ \yld stp ->
62− let go s = do
63− r <- next s
64− case r of
65− Just (a, b) -> yld a (go b)
66− Nothing -> stp
67− in go s0
68−-}
69−
70−{-# INLINE unfoldr #-}
71−unfoldr :: Monad m => (b -> Maybe (a, b)) -> b -> Stream m a
72−unfoldr next s0 = build $ \yld stp ->
73− let go s =
74− case next s of
75− Just (a, b) -> yld a (go b)
76− Nothing -> stp
77− in go s0
78−
79−replicateM :: Monad m => Int -> a -> Stream m a
80−replicateM n x = Stream (step n)
81− where
82− step i = return $
83− if i <= 0
84− then Stop
85− else Yield x (Stream (step (i - 1)))
86−
87−-------------------------------------------------------------------------------
88−-- Folding
89−-------------------------------------------------------------------------------
90−
91−uncons :: Monad m => Stream m a -> m (Maybe (a, Stream m a))
92−uncons (Stream step) = do
93− r <- step
94− return $ case r of
95− Yield x xs -> Just (x, xs)
96− Stop -> Nothing
97−
98−-- | Lazy right associative fold to a stream.
99−{-# INLINE_NORMAL foldrS #-}
100−foldrS :: Monad m
101− => (a -> Stream m b -> Stream m b)
102− -> Stream m b
103− -> Stream m a
104− -> Stream m b
105−foldrS f streamb = go
106− where
107− go (Stream stepa) = Stream $ do
108− r <- stepa
109− case r of
110− Yield x xs -> let Stream step = f x (go xs) in step
111− Stop -> let Stream step = streamb in step
112−
113−{-# INLINE_LATE foldrM #-}
114−foldrM :: Monad m => (a -> m b -> m b) -> m b -> Stream m a -> m b
115−foldrM fstep acc = go
116− where
117− go (Stream step) = do
118− r <- step
119− case r of
120− Yield x xs -> fstep x (go xs)
121− Stop -> acc
122−
123−{-# INLINE_NORMAL build #-}
124−build :: Monad m
125− => forall a. (forall b. (a -> b -> b) -> b -> b) -> Stream m a
126−build g = g cons nil
127−
128−{-# RULES
129−"foldrM/build" forall k z (g :: forall b. (a -> b -> b) -> b -> b).
130− foldrM k z (build g) = g k z #-}
131−
132−{-
133−-- To fuse foldrM with unfoldrM we need the type m1 to be polymorphic such that
134−-- it is either Monad m or Stream m. So that we can use cons/nil as well as
135−-- monadic construction function as its arguments.
136−--
137−{-# INLINE_NORMAL buildM #-}
138−buildM :: Monad m
139− => forall a. (forall b. (a -> m1 b -> m1 b) -> m1 b -> m1 b) -> Stream m a
140−buildM g = g cons nil
141−-}
142−
143−-------------------------------------------------------------------------------
144−-- Specific folds
145−-------------------------------------------------------------------------------
146−
147−{-# INLINE drain #-}
148−drain :: Monad m => Stream m a -> m ()
149−drain = foldrM (\_ xs -> xs) (return ())
150−{-
151−drain (Stream step) = do
152− r <- step
153− case r of
154− Yield _ next -> drain next
155− Stop -> return ()
156− -}
core/src/Streamly/Internal/Data/Stream/StreamK.hs+207−21
@@ -7,18 +7,56 @@
7-- Stability : experimental
7-- Stability : experimental
8-- Portability : GHC
8-- Portability : GHC
9--
9--
10+-- To run examples in this module:
10--
11--
11−-- Continuation passing style (CPS) stream implementation. The symbol 'K' below
12+-- >>> import qualified Streamly.Data.Fold as Fold
12−-- denotes a function as well as a Kontinuation.
13+-- >>> import qualified Streamly.Data.Stream as Stream
14+-- >>> import qualified Streamly.Data.Stream.StreamK as StreamK
13--
15--
14−-- @
16+-- We will add some more imports in the examples as needed.
15−-- import qualified Streamly.Internal.Data.Stream.StreamK as K
17+--
16−-- @
18+-- For effectful streams we will use the following IO action:
19+--
20+-- >>> effect n = print n >> return n
21+--
22+-- = Overview
23+--
24+-- Continuation passing style (CPS) stream implementation. The 'K' in 'StreamK'
25+-- stands for Kontinuation.
26+--
27+-- StreamK can be constructed like lists, except that they use 'nil' instead of
28+-- '[]' and 'cons' instead of ':'.
29+--
30+-- `cons` adds a pure value at the head of the stream:
31+--
32+-- >>> import Streamly.Data.Stream.StreamK (StreamK, cons, consM, nil)
33+-- >>> stream = 1 `cons` 2 `cons` nil :: StreamK IO Int
34+--
35+-- Convert 'StreamK' to 'Stream' to use functions from the
36+-- "Streamly.Data.Stream" module:
37+--
38+-- >>> Stream.fold Fold.toList $ StreamK.toStream stream -- IO [Int]
39+-- [1,2]
40+--
41+-- `consM` adds an effect at the head of the stream:
42+--
43+-- >>> stream = effect 1 `consM` effect 2 `consM` nil
44+-- >>> Stream.fold Fold.toList $ StreamK.toStream stream
45+-- 1
46+-- 2
47+-- [1,2]
17--
48--
18module Streamly.Internal.Data.Stream.StreamK
49module Streamly.Internal.Data.Stream.StreamK
19 (
50 (
20 -- * The stream type
51 -- * The stream type
21− Stream(..)
52+ Stream(..) -- XXX stop exporting this
53+ , StreamK
54+ , fromStream
55+ , toStream
56+
57+ , CrossStreamK
58+ , unCross
59+ , mkCross
22
60
23 -- * Construction Primitives
61 -- * Construction Primitives
24 , mkStream
62 , mkStream
@@ -78,7 +116,9 @@ module Streamly.Internal.Data.Stream.StreamK
78 , fold
116 , fold
79 , foldBreak
117 , foldBreak
80 , foldEither
118 , foldEither
119+ , foldConcat
81 , parseBreak
120 , parseBreak
121+ , parse
82
122
83 -- ** Specialized Folds
123 -- ** Specialized Folds
84 , drain
124 , drain
@@ -135,6 +175,7 @@ module Streamly.Internal.Data.Stream.StreamK
135
175
136 -- ** Reordering
176 -- ** Reordering
137 , reverse
177 , reverse
178+ , sortBy
138
179
139 -- ** Map and Filter
180 -- ** Map and Filter
140 , mapMaybe
181 , mapMaybe
@@ -152,18 +193,25 @@ module Streamly.Internal.Data.Stream.StreamK
152 , crossApply
193 , crossApply
153 , crossApplySnd
194 , crossApplySnd
154 , crossApplyFst
195 , crossApplyFst
196+ , crossWith
155
197
156 , concatMapWith
198 , concatMapWith
157 , concatMap
199 , concatMap
158 , concatEffect
200 , concatEffect
159 , bindWith
201 , bindWith
160− , concatPairsWith
202+ , concatIterateWith
203+ , concatIterateLeftsWith
204+ , concatIterateScanWith
205+
206+ , mergeMapWith
207+ , mergeIterateWith
161
208
162 -- ** Transformation comprehensions
209 -- ** Transformation comprehensions
163 , the
210 , the
164
211
165 -- * Semigroup Style Composition
212 -- * Semigroup Style Composition
166− , serial
213+ , append
214+ , interleave
167
215
168 -- * Utilities
216 -- * Utilities
169 , consM
217 , consM
@@ -175,11 +223,15 @@ where
175#include "assert.hs"
223#include "assert.hs"
176
224
177import Control.Monad (void, join)
225import Control.Monad (void, join)
226+import GHC.Types (SPEC(..))
178import Streamly.Internal.Data.Fold.Type (Fold(..))
227import Streamly.Internal.Data.Fold.Type (Fold(..))
228+import Streamly.Internal.Data.Producer.Type (Producer(..))
179import Streamly.Internal.Data.SVar.Type (adaptState, defState)
229import Streamly.Internal.Data.SVar.Type (adaptState, defState)
180
230
181import qualified Streamly.Internal.Data.Fold.Type as FL
231import qualified Streamly.Internal.Data.Fold.Type as FL
232+import qualified Streamly.Internal.Data.Parser as Parser
182import qualified Streamly.Internal.Data.Parser.ParserD.Type as PR
233import qualified Streamly.Internal.Data.Parser.ParserD.Type as PR
234+import qualified Streamly.Internal.Data.Stream.StreamD as Stream
183import qualified Prelude
235import qualified Prelude
184
236
185import Prelude
237import Prelude
@@ -193,14 +245,25 @@ import Streamly.Internal.Data.Parser.ParserD (ParseError(..))
193
245
194-- $setup
246-- $setup
195-- >>> :m
247-- >>> :m
248+-- >>> import qualified Streamly.Data.Fold as Fold
249+-- >>> import qualified Streamly.Data.Parser as Parser
250+-- >>> import qualified Streamly.Data.Stream as Stream
251+-- >>> import qualified Streamly.Data.Stream.StreamK as StreamK
252+-- >>> import qualified Streamly.Internal.Data.Stream.StreamK as StreamK
253+--
254+
255+{-# INLINE fromStream #-}
256+fromStream :: Monad m => Stream.Stream m a -> StreamK m a
257+fromStream = Stream.toStreamK
258+
259+{-# INLINE toStream #-}
260+toStream :: Applicative m => StreamK m a -> Stream.Stream m a
261+toStream = Stream.fromStreamK
196
262
197-------------------------------------------------------------------------------
263-------------------------------------------------------------------------------
198-- Generation
264-- Generation
199-------------------------------------------------------------------------------
265-------------------------------------------------------------------------------
200
266
201−{-# INLINE unfoldrM #-}
202−unfoldrM :: Monad m => (b -> m (Maybe (a, b))) -> b -> Stream m a
203−unfoldrM = unfoldrMWith consM
204{-
267{-
205-- Generalization of concurrent streams/SVar via unfoldr.
268-- Generalization of concurrent streams/SVar via unfoldr.
206--
269--
@@ -265,11 +328,6 @@ fromList = fromFoldable
265-- Elimination by Folding
328-- Elimination by Folding
266-------------------------------------------------------------------------------
329-------------------------------------------------------------------------------
267
330
268−-- | Lazy right associative fold.
269−{-# INLINE foldr #-}
270−foldr :: Monad m => (a -> b -> b) -> b -> Stream m a -> m b
271−foldr step acc = foldrM (\x xs -> xs >>= \b -> return (step x b)) (return acc)
272−
273{-# INLINE foldr1 #-}
331{-# INLINE foldr1 #-}
274foldr1 :: Monad m => (a -> a -> a) -> Stream m a -> m (Maybe a)
332foldr1 :: Monad m => (a -> a -> a) -> Stream m a -> m (Maybe a)
275foldr1 step m = do
333foldr1 step m = do
@@ -297,6 +355,21 @@ foldlMx' step begin done = go begin
297 yieldk a r = acc >>= \b -> step b a >>= \x -> go (return x) r
355 yieldk a r = acc >>= \b -> step b a >>= \x -> go (return x) r
298 in foldStream defState yieldk single stop m1
356 in foldStream defState yieldk single stop m1
299
357
358+-- | Fold a stream using the supplied left 'Fold' and reducing the resulting
359+-- expression strictly at each step. The behavior is similar to 'foldl''. A
360+-- 'Fold' can terminate early without consuming the full stream. See the
361+-- documentation of individual 'Fold's for termination behavior.
362+--
363+-- Definitions:
364+--
365+-- >>> fold f = fmap fst . StreamK.foldBreak f
366+-- >>> fold f = StreamK.parse (Parser.fromFold f)
367+--
368+-- Example:
369+--
370+-- >>> StreamK.fold Fold.sum $ StreamK.fromStream $ Stream.enumerateFromTo 1 100
371+-- 5050
372+--
300{-# INLINABLE fold #-}
373{-# INLINABLE fold #-}
301fold :: Monad m => FL.Fold m a b -> Stream m a -> m b
374fold :: Monad m => FL.Fold m a b -> Stream m a -> m b
302fold (FL.Fold step begin done) m = do
375fold (FL.Fold step begin done) m = do
@@ -318,6 +391,13 @@ fold (FL.Fold step begin done) m = do
318 FL.Done b1 -> return b1
391 FL.Done b1 -> return b1
319 in foldStream defState yieldk single stop m1
392 in foldStream defState yieldk single stop m1
320
393
394+-- | Fold resulting in either breaking the stream or continuation of the fold.
395+-- Instead of supplying the input stream in one go we can run the fold multiple
396+-- times, each time supplying the next segment of the input stream. If the fold
397+-- has not yet finished it returns a fold that can be run again otherwise it
398+-- returns the fold result and the residual stream.
399+--
400+-- /Internal/
321{-# INLINE foldEither #-}
401{-# INLINE foldEither #-}
322foldEither :: Monad m =>
402foldEither :: Monad m =>
323 Fold m a b -> Stream m a -> m (Either (Fold m a b) (b, Stream m a))
403 Fold m a b -> Stream m a -> m (Either (Fold m a b) (b, Stream m a))
@@ -344,6 +424,9 @@ foldEither (FL.Fold step begin done) m = do
344 FL.Done b1 -> return $ Right (b1, r)
424 FL.Done b1 -> return $ Right (b1, r)
345 in foldStream defState yieldk single stop m1
425 in foldStream defState yieldk single stop m1
346
426
427+-- | Like 'fold' but also returns the remaining stream. The resulting stream
428+-- would be 'StreamK.nil' if the stream finished before the fold.
429+--
347{-# INLINE foldBreak #-}
430{-# INLINE foldBreak #-}
348foldBreak :: Monad m => Fold m a b -> Stream m a -> m (b, Stream m a)
431foldBreak :: Monad m => Fold m a b -> Stream m a -> m (b, Stream m a)
349foldBreak fld strm = do
432foldBreak fld strm = do
@@ -358,6 +441,68 @@ foldBreak fld strm = do
358 b <- extract s
441 b <- extract s
359 return (b, nil)
442 return (b, nil)
360
443
444+-- XXX Array folds can be implemented using this.
445+-- foldContainers? Specialized to foldArrays.
446+
447+-- | Generate streams from individual elements of a stream and fold the
448+-- concatenation of those streams using the supplied fold. Return the result of
449+-- the fold and residual stream.
450+--
451+-- For example, this can be used to efficiently fold an Array Word8 stream
452+-- using Word8 folds.
453+--
454+-- /Internal/
455+{-# INLINE foldConcat #-}
456+foldConcat :: Monad m =>
457+ Producer m a b -> Fold m b c -> StreamK m a -> m (c, StreamK m a)
458+foldConcat
459+ (Producer pstep pinject pextract)
460+ (Fold fstep begin done)
461+ stream = do
462+
463+ res <- begin
464+ case res of
465+ FL.Partial fs -> go fs stream
466+ FL.Done fb -> return (fb, stream)
467+
468+ where
469+
470+ go !acc m1 = do
471+ let stop = do
472+ r <- done acc
473+ return (r, nil)
474+ single a = do
475+ st <- pinject a
476+ res <- go1 SPEC acc st
477+ case res of
478+ Left fs -> do
479+ r <- done fs
480+ return (r, nil)
481+ Right (b, s) -> do
482+ x <- pextract s
483+ return (b, fromPure x)
484+ yieldk a r = do
485+ st <- pinject a
486+ res <- go1 SPEC acc st
487+ case res of
488+ Left fs -> go fs r
489+ Right (b, s) -> do
490+ x <- pextract s
491+ return (b, x `cons` r)
492+ in foldStream defState yieldk single stop m1
493+
494+ {-# INLINE go1 #-}
495+ go1 !_ !fs st = do
496+ r <- pstep st
497+ case r of
498+ Stream.Yield x s -> do
499+ res <- fstep fs x
500+ case res of
501+ FL.Done b -> return $ Right (b, s)
502+ FL.Partial fs1 -> go1 SPEC fs1 s
503+ Stream.Skip s -> go1 SPEC fs s
504+ Stream.Stop -> return $ Left fs
505+
361-- | Like 'foldl'' but with a monadic step function.
506-- | Like 'foldl'' but with a monadic step function.
362{-# INLINE foldlM' #-}
507{-# INLINE foldlM' #-}
363foldlM' :: Monad m => (b -> a -> m b) -> m b -> Stream m a -> m b
508foldlM' :: Monad m => (b -> a -> m b) -> m b -> Stream m a -> m b
@@ -993,13 +1138,13 @@ splitAt n ls
993 (xs', xs'') = splitAt' (m - 1) xs
1138 (xs', xs'') = splitAt' (m - 1) xs
994
1139
995-- | Run a 'Parser' over a stream and return rest of the Stream.
1140-- | Run a 'Parser' over a stream and return rest of the Stream.
996−{-# INLINE_NORMAL parseBreak #-}
1141+{-# INLINE_NORMAL parseBreakD #-}
997−parseBreak
1142+parseBreakD
998 :: Monad m
1143 :: Monad m
999 => PR.Parser a m b
1144 => PR.Parser a m b
1000 -> Stream m a
1145 -> Stream m a
1001 -> m (Either ParseError b, Stream m a)
1146 -> m (Either ParseError b, Stream m a)
1002−parseBreak (PR.Parser pstep initial extract) stream = do
1147+parseBreakD (PR.Parser pstep initial extract) stream = do
1003 res <- initial
1148 res <- initial
1004 case res of
1149 case res of
1005 PR.IPartial s -> goStream stream [] s
1150 PR.IPartial s -> goStream stream [] s
@@ -1052,7 +1197,7 @@ parseBreak (PR.Parser pstep initial extract) stream = do
1052 assertM(n <= length (x:buf))
1197 assertM(n <= length (x:buf))
1053 let src0 = Prelude.take n (x:buf)
1198 let src0 = Prelude.take n (x:buf)
1054 src = Prelude.reverse src0
1199 src = Prelude.reverse src0
1055− return (Right b, serial (fromList src) r)
1200+ return (Right b, append (fromList src) r)
1056 PR.Error err -> return (Left (ParseError err), r)
1201 PR.Error err -> return (Left (ParseError err), r)
1057 in foldStream defState yieldk single stop st
1202 in foldStream defState yieldk single stop st
1058
1203
@@ -1076,5 +1221,46 @@ parseBreak (PR.Parser pstep initial extract) stream = do
1076 assert (n <= length (x:buf)) (return ())
1221 assert (n <= length (x:buf)) (return ())
1077 let src0 = Prelude.take n (x:buf)
1222 let src0 = Prelude.take n (x:buf)
1078 src = Prelude.reverse src0
1223 src = Prelude.reverse src0
1079− return (Right b, serial (fromList src) st)
1224+ return (Right b, append (fromList src) st)
1080 PR.Error err -> return (Left (ParseError err), nil)
1225 PR.Error err -> return (Left (ParseError err), nil)
1226+
1227+-- | Parse a stream using the supplied 'Parser'.
1228+--
1229+-- /CPS/
1230+--
1231+{-# INLINE parseBreak #-}
1232+parseBreak :: Monad m =>
1233+ Parser.Parser a m b -> Stream m a -> m (Either ParseError b, Stream m a)
1234+parseBreak p = parseBreakD (PR.fromParserK p)
1235+
1236+{-# INLINE parse #-}
1237+parse :: Monad m =>
1238+ Parser.Parser a m b -> Stream m a -> m (Either ParseError b)
1239+parse f = fmap fst . parseBreak f
1240+
1241+-- | Sort the input stream using a supplied comparison function.
1242+--
1243+-- Sorting can be achieved by simply:
1244+--
1245+-- >>> sortBy cmp = StreamK.mergeMapWith (StreamK.mergeBy cmp) StreamK.fromPure
1246+--
1247+-- However, this combinator uses a parser to first split the input stream into
1248+-- down and up sorted segments and then merges them to optimize sorting when
1249+-- pre-sorted sequences exist in the input stream.
1250+--
1251+-- /O(n) space/
1252+--
1253+{-# INLINE sortBy #-}
1254+sortBy :: Monad m => (a -> a -> Ordering) -> Stream m a -> Stream m a
1255+-- sortBy f = Stream.concatPairsWith (Stream.mergeBy f) Stream.fromPure
1256+sortBy cmp =
1257+ let p =
1258+ Parser.groupByRollingEither
1259+ (\x -> (< GT) . cmp x)
1260+ FL.toStreamKRev
1261+ FL.toStreamK
1262+ in mergeMapWith (mergeBy cmp) id
1263+ . Stream.toStreamK
1264+ . Stream.catRights -- its a non-failing backtracking parser
1265+ . Stream.parseMany (fmap (either id id) p)
1266+ . Stream.fromStreamK
core/src/Streamly/Internal/Data/Stream/StreamDK/Type.hs → core/src/Streamly/Internal/Data/Stream/StreamK/Alt.hsrenamed+143−3
@@ -92,13 +92,153 @@
92-- a push style CPS representation should be able to be used along with StreamK
92-- a push style CPS representation should be able to be used along with StreamK
93-- to efficiently implement composable folds.
93-- to efficiently implement composable folds.
94
94
95−module Streamly.Internal.Data.Stream.StreamDK.Type
95+module Streamly.Internal.Data.Stream.StreamK.Alt
96+ (
97+ -- * Stream Type
98+
99+ Stream
96− ( Step(..)
100+ , Step (..)
97− , Stream (..)
101+
102+ -- * Construction
103+ , nil
104+ , cons
105+ , consM
106+ , unfoldr
107+ , unfoldrM
108+ , replicateM
109+
110+ -- * Folding
111+ , uncons
112+ , foldrS
113+
114+ -- * Specific Folds
115+ , drain
98 )
116 )
99where
117where
100
118
119+#include "inline.hs"
120+
101-- XXX Use Cons and Nil instead of Yield and Stop?
121-- XXX Use Cons and Nil instead of Yield and Stop?
102data Step m a = Yield a (Stream m a) | Stop
122data Step m a = Yield a (Stream m a) | Stop
103
123
104newtype Stream m a = Stream (m (Step m a))
124newtype Stream m a = Stream (m (Step m a))
125+
126+-------------------------------------------------------------------------------
127+-- Construction
128+-------------------------------------------------------------------------------
129+
130+nil :: Monad m => Stream m a
131+nil = Stream $ return Stop
132+
133+{-# INLINE_NORMAL cons #-}
134+cons :: Monad m => a -> Stream m a -> Stream m a
135+cons x xs = Stream $ return $ Yield x xs
136+
137+consM :: Monad m => m a -> Stream m a -> Stream m a
138+consM eff xs = Stream $ eff >>= \x -> return $ Yield x xs
139+
140+unfoldrM :: Monad m => (s -> m (Maybe (a, s))) -> s -> Stream m a
141+unfoldrM next state = Stream (step' state)
142+ where
143+ step' st = do
144+ r <- next st
145+ return $ case r of
146+ Just (x, s) -> Yield x (Stream (step' s))
147+ Nothing -> Stop
148+{-
149+unfoldrM next s0 = buildM $ \yld stp ->
150+ let go s = do
151+ r <- next s
152+ case r of
153+ Just (a, b) -> yld a (go b)
154+ Nothing -> stp
155+ in go s0
156+-}
157+
158+{-# INLINE unfoldr #-}
159+unfoldr :: Monad m => (b -> Maybe (a, b)) -> b -> Stream m a
160+unfoldr next s0 = build $ \yld stp ->
161+ let go s =
162+ case next s of
163+ Just (a, b) -> yld a (go b)
164+ Nothing -> stp
165+ in go s0
166+
167+replicateM :: Monad m => Int -> a -> Stream m a
168+replicateM n x = Stream (step n)
169+ where
170+ step i = return $
171+ if i <= 0
172+ then Stop
173+ else Yield x (Stream (step (i - 1)))
174+
175+-------------------------------------------------------------------------------
176+-- Folding
177+-------------------------------------------------------------------------------
178+
179+uncons :: Monad m => Stream m a -> m (Maybe (a, Stream m a))
180+uncons (Stream step) = do
181+ r <- step
182+ return $ case r of
183+ Yield x xs -> Just (x, xs)
184+ Stop -> Nothing
185+
186+-- | Lazy right associative fold to a stream.
187+{-# INLINE_NORMAL foldrS #-}
188+foldrS :: Monad m
189+ => (a -> Stream m b -> Stream m b)
190+ -> Stream m b
191+ -> Stream m a
192+ -> Stream m b
193+foldrS f streamb = go
194+ where
195+ go (Stream stepa) = Stream $ do
196+ r <- stepa
197+ case r of
198+ Yield x xs -> let Stream step = f x (go xs) in step
199+ Stop -> let Stream step = streamb in step
200+
201+{-# INLINE_LATE foldrM #-}
202+foldrM :: Monad m => (a -> m b -> m b) -> m b -> Stream m a -> m b
203+foldrM fstep acc = go
204+ where
205+ go (Stream step) = do
206+ r <- step
207+ case r of
208+ Yield x xs -> fstep x (go xs)
209+ Stop -> acc
210+
211+{-# INLINE_NORMAL build #-}
212+build :: Monad m
213+ => forall a. (forall b. (a -> b -> b) -> b -> b) -> Stream m a
214+build g = g cons nil
215+
216+{-# RULES
217+"foldrM/build" forall k z (g :: forall b. (a -> b -> b) -> b -> b).
218+ foldrM k z (build g) = g k z #-}
219+
220+{-
221+-- To fuse foldrM with unfoldrM we need the type m1 to be polymorphic such that
222+-- it is either Monad m or Stream m. So that we can use cons/nil as well as
223+-- monadic construction function as its arguments.
224+--
225+{-# INLINE_NORMAL buildM #-}
226+buildM :: Monad m
227+ => forall a. (forall b. (a -> m1 b -> m1 b) -> m1 b -> m1 b) -> Stream m a
228+buildM g = g cons nil
229+-}
230+
231+-------------------------------------------------------------------------------
232+-- Specific folds
233+-------------------------------------------------------------------------------
234+
235+{-# INLINE drain #-}
236+drain :: Monad m => Stream m a -> m ()
237+drain = foldrM (\_ xs -> xs) (return ())
238+{-
239+drain (Stream step) = do
240+ r <- step
241+ case r of
242+ Yield _ next -> drain next
243+ Stop -> return ()
244+ -}
core/src/Streamly/Internal/Data/Stream/StreamK/Type.hs+754−69
@@ -1,3 +1,4 @@
1+{-# LANGUAGE UndecidableInstances #-}
1-- |
2-- |
2-- Module : Streamly.Internal.Data.Stream.StreamK.Type
3-- Module : Streamly.Internal.Data.Stream.StreamK.Type
3-- Copyright : (c) 2017 Composewell Technologies
4-- Copyright : (c) 2017 Composewell Technologies
@@ -13,12 +14,16 @@
13--
14--
14module Streamly.Internal.Data.Stream.StreamK.Type
15module Streamly.Internal.Data.Stream.StreamK.Type
15 (
16 (
16− -- * The stream type
17+ -- * StreamK type
17− Stream (..)
18+ Stream (..) -- XXX stop exporting this
18− , toStreamK
19+ , StreamK
19− , fromStreamK
20
20
21+ -- * CrossStreamK type wrapper
22+ , CrossStreamK
23+ , unCross
24+ , mkCross
25+
21− -- * foldr/build
26+ -- * foldr/build Fusion
22 , mkStream
27 , mkStream
23 , foldStream
28 , foldStream
24 , foldStreamShared
29 , foldStreamShared
@@ -32,8 +37,10 @@ module Streamly.Internal.Data.Stream.StreamK.Type
32 , buildSM
37 , buildSM
33 , augmentS
38 , augmentS
34 , augmentSM
39 , augmentSM
40+ , unShare
35
41
36 -- * Construction
42 -- * Construction
43+ -- ** Primitives
37 , fromStopK
44 , fromStopK
38 , fromYieldK
45 , fromYieldK
39 , consK
46 , consK
@@ -44,58 +51,89 @@ module Streamly.Internal.Data.Stream.StreamK.Type
44 , nil
51 , nil
45 , nilM
52 , nilM
46
53
47− -- * Generation
54+ -- ** Unfolding
48− , fromEffect
49− , fromPure
50 , unfoldr
55 , unfoldr
51 , unfoldrMWith
56 , unfoldrMWith
57+ , unfoldrM
58+
59+ -- ** From Values
60+ , fromEffect
61+ , fromPure
52 , repeat
62 , repeat
53 , repeatMWith
63 , repeatMWith
54 , replicateMWith
64 , replicateMWith
65+
66+ -- ** From Indices
55 , fromIndicesMWith
67 , fromIndicesMWith
68+
69+ -- ** Iteration
56 , iterateMWith
70 , iterateMWith
71+
72+ -- ** From Containers
57 , fromFoldable
73 , fromFoldable
58 , fromFoldableM
74 , fromFoldableM
75+
76+ -- ** Cyclic
59 , mfix
77 , mfix
60
78
61 -- * Elimination
79 -- * Elimination
80+ -- ** Primitives
62 , uncons
81 , uncons
63− , foldl'
82+
83+ -- ** Strict Left Folds
84+ , Streamly.Internal.Data.Stream.StreamK.Type.foldl'
64 , foldlx'
85 , foldlx'
86+
87+ -- ** Lazy Right Folds
88+ , Streamly.Internal.Data.Stream.StreamK.Type.foldr
89+
90+ -- ** Specific Folds
65 , drain
91 , drain
66 , null
92 , null
67 , tail
93 , tail
68 , init
94 , init
69
95
70− -- * Transformation
96+ -- * Mapping
71− , conjoin
72− , serial
73 , map
97 , map
74 , mapMWith
98 , mapMWith
75 , mapMSerial
99 , mapMSerial
76− , unShare
77
100
101+ -- * Combining Two Streams
102+ -- ** Appending
103+ , conjoin
104+ , append
105+
106+ -- ** Interleave
107+ , interleave
108+ , interleaveFst
109+ , interleaveMin
110+
111+ -- ** Cross Product
78 , crossApplyWith
112 , crossApplyWith
79 , crossApply
113 , crossApply
80 , crossApplySnd
114 , crossApplySnd
81 , crossApplyFst
115 , crossApplyFst
116+ , crossWith
117+ , cross
82
118
119+ -- * Concat
120+ , before
121+ , concatEffect
122+ , concatMapEffect
83 , concatMapWith
123 , concatMapWith
84 , concatMap
124 , concatMap
85 , bindWith
125 , bindWith
86− , concatPairsWith
126+ , concatIterateWith
127+ , concatIterateLeftsWith
128+ , concatIterateScanWith
87
129
130+ -- * Merge
131+ , mergeMapWith
132+ , mergeIterateWith
133+
134+ -- * Buffered Operations
88 , foldlS
135 , foldlS
89 , reverse
136 , reverse
90−
91− , before
92− , concatEffect
93− , concatMapEffect
94−
95− -- * Interleave
96− , interleave
97− , interleaveFst
98− , interleaveMin
99 )
137 )
100where
138where
101
139
@@ -103,21 +141,44 @@ where
103
141
104-- import Control.Applicative (liftA2)
142-- import Control.Applicative (liftA2)
105import Control.Monad ((>=>))
143import Control.Monad ((>=>))
144+import Control.Monad.Catch (MonadThrow, throwM)
145+import Control.Monad.Trans.Class (MonadTrans(lift))
146+import Control.Applicative (liftA2)
147+import Control.Monad.IO.Class (MonadIO(..))
148+import Data.Foldable (Foldable(foldl'), fold, foldr)
106import Data.Function (fix)
149import Data.Function (fix)
150+import Data.Functor.Identity (Identity(..))
151+import Data.Maybe (fromMaybe)
152+import Data.Semigroup (Endo(..))
153+import GHC.Exts (IsList(..), IsString(..), oneShot)
154+import Streamly.Internal.BaseCompat ((#.))
155+import Streamly.Internal.Data.Maybe.Strict (Maybe'(..), toMaybe)
107import Streamly.Internal.Data.SVar.Type (State, adaptState, defState)
156import Streamly.Internal.Data.SVar.Type (State, adaptState, defState)
157+import Text.Read
158+ ( Lexeme(Ident), lexP, parens, prec, readPrec, readListPrec
159+ , readListPrecDefault)
108
160
109import qualified Prelude
161import qualified Prelude
110
162
111import Prelude hiding
163import Prelude hiding
112 (map, mapM, concatMap, foldr, repeat, null, reverse, tail, init)
164 (map, mapM, concatMap, foldr, repeat, null, reverse, tail, init)
113
165
166+-- $setup
167+-- >>> import Data.Function (fix, (&))
168+-- >>> import Data.Semigroup (cycle1)
169+-- >>> import Streamly.Internal.Data.Stream.StreamK (CrossStreamK(..))
170+-- >>> import qualified Streamly.Data.Fold as Fold
171+-- >>> import qualified Streamly.Data.Stream as Stream
172+-- >>> import qualified Streamly.Data.Stream.StreamK as StreamK
173+-- >>> import qualified Streamly.Internal.Data.Stream.StreamK as StreamK
174+-- >>> import qualified Streamly.Internal.FileSystem.Dir as Dir
175+
114------------------------------------------------------------------------------
176------------------------------------------------------------------------------
115-- Basic stream type
177-- Basic stream type
116------------------------------------------------------------------------------
178------------------------------------------------------------------------------
117
179
118−-- | The type @Stream m a@ represents a monadic stream of values of type 'a'
119−-- constructed using actions in monad 'm'. It uses stop, singleton and yield
120−-- continuations equivalent to the following direct style type:
180+-- It uses stop, singleton and yield continuations equivalent to the following
181+-- direct style type:
121--
182--
122-- @
183-- @
123-- data Stream m a = Stop | Singleton a | Yield a (Stream m a)
184-- data Stream m a = Stop | Singleton a | Yield a (Stream m a)
@@ -132,8 +193,17 @@ import Prelude hiding
132-- single element. We build singleton streams in the implementation of 'pure'
193-- single element. We build singleton streams in the implementation of 'pure'
133-- for Applicative and Monad, and in 'lift' for MonadTrans.
194-- for Applicative and Monad, and in 'lift' for MonadTrans.
134
195
135−-- XXX remove the Stream type parameter from State as it is always constant.
196+-- XXX remove the State param.
136−-- We can remove it from SVar as well
197+
198+-- | Continuation Passing Style (CPS) version of "Streamly.Data.Stream.Stream".
199+-- Unlike "Streamly.Data.Stream.Stream", 'StreamK' can be composed recursively
200+-- without affecting performance.
201+--
202+-- Semigroup instance appends two streams:
203+--
204+-- >>> (<>) = Stream.append
205+--
206+type StreamK = Stream
137
207
138newtype Stream m a =
208newtype Stream m a =
139 MkStream (forall r.
209 MkStream (forall r.
@@ -144,14 +214,6 @@ newtype Stream m a =
144 -> m r
214 -> m r
145 )
215 )
146
216
147−{-# INLINE fromStreamK #-}
148−fromStreamK :: Stream m a -> Stream m a
149−fromStreamK = id
150−
151−{-# INLINE toStreamK #-}
152−toStreamK :: Stream m a -> Stream m a
153−toStreamK = id
154−
155mkStream
217mkStream
156 :: (forall r. State Stream m a
218 :: (forall r. State Stream m a
157 -> (a -> Stream m a -> m r)
219 -> (a -> Stream m a -> m r)
@@ -195,17 +257,22 @@ consK k r = mkStream $ \_ yld _ _ -> k (`yld` r)
195infixr 5 `cons`
257infixr 5 `cons`
196
258
197-- faster than consM because there is no bind.
259-- faster than consM because there is no bind.
198−-- | Construct a stream by adding a pure value at the head of an existing
260+
199−-- stream. For serial streams this is the same as @(return a) \`consM` r@ but
261+-- | A right associative prepend operation to add a pure value at the head of
200−-- more efficient. For concurrent streams this is not concurrent whereas
262+-- an existing stream::
201−-- 'consM' is concurrent. For example:
202--
263--
203−-- @
204−-- > toList $ 1 \`cons` 2 \`cons` 3 \`cons` nil
264+-- >>> s = 1 `StreamK.cons` 2 `StreamK.cons` 3 `StreamK.cons` StreamK.nil
265+-- >>> Stream.fold Fold.toList (StreamK.toStream s)
205-- [1,2,3]
266-- [1,2,3]
206−-- @
207--
267--
208−-- @since 0.1.0
268+-- It can be used efficiently with 'Prelude.foldr':
269+--
270+-- >>> fromFoldable = Prelude.foldr StreamK.cons StreamK.nil
271+--
272+-- Same as the following but more efficient:
273+--
274+-- >>> cons x xs = return x `StreamK.consM` xs
275+--
209{-# INLINE_NORMAL cons #-}
276{-# INLINE_NORMAL cons #-}
210cons :: a -> Stream m a -> Stream m a
277cons :: a -> Stream m a -> Stream m a
211cons a r = mkStream $ \_ yield _ _ -> yield a r
278cons a r = mkStream $ \_ yield _ _ -> yield a r
@@ -224,35 +291,44 @@ infixr 5 .:
224(.:) :: a -> Stream m a -> Stream m a
291(.:) :: a -> Stream m a -> Stream m a
225(.:) = cons
292(.:) = cons
226
293
227−-- | An empty stream.
294+-- | A stream that terminates without producing any output or side effect.
228--
295--
229−-- @
296+-- >>> Stream.fold Fold.toList (StreamK.toStream StreamK.nil)
230−-- > toList nil
231-- []
297-- []
232−-- @
233--
298--
234−-- @since 0.1.0
235{-# INLINE_NORMAL nil #-}
299{-# INLINE_NORMAL nil #-}
236nil :: Stream m a
300nil :: Stream m a
237nil = mkStream $ \_ _ _ stp -> stp
301nil = mkStream $ \_ _ _ stp -> stp
238
302
239−-- | An empty stream producing a side effect.
303+-- | A stream that terminates without producing any output, but produces a side
304+-- effect.
240--
305--
241−-- @
242−-- > toList (nilM (print "nil"))
306+-- >>> Stream.fold Fold.toList (StreamK.toStream (StreamK.nilM (print "nil")))
243-- "nil"
307-- "nil"
244-- []
308-- []
245−-- @
246--
309--
247-- /Pre-release/
310-- /Pre-release/
248{-# INLINE_NORMAL nilM #-}
311{-# INLINE_NORMAL nilM #-}
249nilM :: Applicative m => m b -> Stream m a
312nilM :: Applicative m => m b -> Stream m a
250nilM m = mkStream $ \_ _ _ stp -> m *> stp
313nilM m = mkStream $ \_ _ _ stp -> m *> stp
251
314
315+-- | Create a singleton stream from a pure value.
316+--
317+-- >>> fromPure a = a `cons` StreamK.nil
318+-- >>> fromPure = pure
319+-- >>> fromPure = StreamK.fromEffect . pure
320+--
252{-# INLINE_NORMAL fromPure #-}
321{-# INLINE_NORMAL fromPure #-}
253fromPure :: a -> Stream m a
322fromPure :: a -> Stream m a
254fromPure a = mkStream $ \_ _ single _ -> single a
323fromPure a = mkStream $ \_ _ single _ -> single a
255
324
325+-- | Create a singleton stream from a monadic action.
326+--
327+-- >>> fromEffect m = m `consM` StreamK.nil
328+--
329+-- >>> Stream.fold Fold.drain $ StreamK.toStream $ StreamK.fromEffect (putStrLn "hello")
330+-- hello
331+--
256{-# INLINE_NORMAL fromEffect #-}
332{-# INLINE_NORMAL fromEffect #-}
257fromEffect :: Monad m => m a -> Stream m a
333fromEffect :: Monad m => m a -> Stream m a
258fromEffect m = mkStream $ \_ _ single _ -> m >>= single
334fromEffect m = mkStream $ \_ _ single _ -> m >>= single
@@ -262,6 +338,23 @@ infixr 5 `consM`
262-- NOTE: specializing the function outside the instance definition seems to
338-- NOTE: specializing the function outside the instance definition seems to
263-- improve performance quite a bit at times, even if we have the same
339-- improve performance quite a bit at times, even if we have the same
264-- SPECIALIZE in the instance definition.
340-- SPECIALIZE in the instance definition.
341+
342+-- | A right associative prepend operation to add an effectful value at the
343+-- head of an existing stream::
344+--
345+-- >>> s = putStrLn "hello" `consM` putStrLn "world" `consM` StreamK.nil
346+-- >>> Stream.fold Fold.drain (StreamK.toStream s)
347+-- hello
348+-- world
349+--
350+-- It can be used efficiently with 'Prelude.foldr':
351+--
352+-- >>> fromFoldableM = Prelude.foldr StreamK.consM StreamK.nil
353+--
354+-- Same as the following but more efficient:
355+--
356+-- >>> consM x xs = StreamK.fromEffect x `StreamK.append` xs
357+--
265{-# INLINE consM #-}
358{-# INLINE consM #-}
266{-# SPECIALIZE consM :: IO a -> Stream IO a -> Stream IO a #-}
359{-# SPECIALIZE consM :: IO a -> Stream IO a -> Stream IO a #-}
267consM :: Monad m => m a -> Stream m a -> Stream m a
360consM :: Monad m => m a -> Stream m a -> Stream m a
@@ -361,7 +454,34 @@ foldrSShared = foldrSWith foldStreamShared
361-- {-# RULES "foldrSShared/app" [1]
454-- {-# RULES "foldrSShared/app" [1]
362-- forall ys. foldrSShared consM ys = \xs -> xs `conjoin` ys #-}
455-- forall ys. foldrSShared consM ys = \xs -> xs `conjoin` ys #-}
363
456
364−-- | Lazy right associative fold to a stream.
457+-- | Right fold to a streaming monad.
458+--
459+-- > foldrS StreamK.cons StreamK.nil === id
460+--
461+-- 'foldrS' can be used to perform stateless stream to stream transformations
462+-- like map and filter in general. It can be coupled with a scan to perform
463+-- stateful transformations. However, note that the custom map and filter
464+-- routines can be much more efficient than this due to better stream fusion.
465+--
466+-- >>> input = StreamK.fromStream $ Stream.fromList [1..5]
467+-- >>> Stream.fold Fold.toList $ StreamK.toStream $ StreamK.foldrS StreamK.cons StreamK.nil input
468+-- [1,2,3,4,5]
469+--
470+-- Find if any element in the stream is 'True':
471+--
472+-- >>> step x xs = if odd x then StreamK.fromPure True else xs
473+-- >>> input = StreamK.fromStream (Stream.fromList (2:4:5:undefined)) :: StreamK IO Int
474+-- >>> Stream.fold Fold.toList $ StreamK.toStream $ StreamK.foldrS step (StreamK.fromPure False) input
475+-- [True]
476+--
477+-- Map (+2) on odd elements and filter out the even elements:
478+--
479+-- >>> step x xs = if odd x then (x + 2) `StreamK.cons` xs else xs
480+-- >>> input = StreamK.fromStream (Stream.fromList [1..5]) :: Stream IO Int
481+-- >>> Stream.fold Fold.toList $ StreamK.toStream $ StreamK.foldrS step StreamK.nil input
482+-- [3,5,7]
483+--
484+-- /Pre-release/
365{-# INLINE_NORMAL foldrS #-}
485{-# INLINE_NORMAL foldrS #-}
366foldrS ::
486foldrS ::
367 (a -> Stream m b -> Stream m b)
487 (a -> Stream m b -> Stream m b)
@@ -741,16 +861,25 @@ null m =
741-- Semigroup
861-- Semigroup
742------------------------------------------------------------------------------
862------------------------------------------------------------------------------
743
863
744−infixr 6 `serial`
864+infixr 6 `append`
745
865
746-- | Appends two streams sequentially, yielding all elements from the first
866-- | Appends two streams sequentially, yielding all elements from the first
747-- stream, and then all elements from the second stream.
867-- stream, and then all elements from the second stream.
748--
868--
869+-- >>> s1 = StreamK.fromStream $ Stream.fromList [1,2]
870+-- >>> s2 = StreamK.fromStream $ Stream.fromList [3,4]
871+-- >>> Stream.fold Fold.toList $ StreamK.toStream $ s1 `StreamK.append` s2
872+-- [1,2,3,4]
873+--
874+-- This has O(n) append performance where @n@ is the number of streams. It can
875+-- be used to efficiently fold an infinite lazy container of streams using
876+-- 'concatMapWith' et. al.
877+--
749−{-# INLINE serial #-}
878+{-# INLINE append #-}
750−serial :: Stream m a -> Stream m a -> Stream m a
879+append :: Stream m a -> Stream m a -> Stream m a
751-- XXX This doubles the time of toNullAp benchmark, may not be fusing properly
880-- XXX This doubles the time of toNullAp benchmark, may not be fusing properly
752-- serial xs ys = augmentS (\c n -> foldrS c n xs) ys
881-- serial xs ys = augmentS (\c n -> foldrS c n xs) ys
753−serial m1 m2 = go m1
882+append m1 m2 = go m1
754 where
883 where
755 go m = mkStream $ \st yld sng stp ->
884 go m = mkStream $ \st yld sng stp ->
756 let stop = foldStream st yld sng stp m2
885 let stop = foldStream st yld sng stp m2
@@ -764,7 +893,7 @@ conjoin :: Monad m => Stream m a -> Stream m a -> Stream m a
764conjoin xs = augmentSM (\c n -> foldrSM c n xs)
893conjoin xs = augmentSM (\c n -> foldrSM c n xs)
765
894
766instance Semigroup (Stream m a) where
895instance Semigroup (Stream m a) where
767− (<>) = serial
896+ (<>) = append
768
897
769------------------------------------------------------------------------------
898------------------------------------------------------------------------------
770-- Monoid
899-- Monoid
@@ -861,6 +990,163 @@ mapMWith cns f = go
861instance Monad m => Functor (Stream m) where
990instance Monad m => Functor (Stream m) where
862 fmap = map
991 fmap = map
863
992
993+------------------------------------------------------------------------------
994+-- Lists
995+------------------------------------------------------------------------------
996+
997+-- Serial streams can act like regular lists using the Identity monad
998+
999+-- XXX Show instance is 10x slower compared to read, we can do much better.
1000+-- The list show instance itself is really slow.
1001+
1002+-- XXX The default definitions of "<" in the Ord instance etc. do not perform
1003+-- well, because they do not get inlined. Need to add INLINE in Ord class in
1004+-- base?
1005+
1006+instance IsList (Stream Identity a) where
1007+ type (Item (Stream Identity a)) = a
1008+
1009+ {-# INLINE fromList #-}
1010+ fromList = fromFoldable
1011+
1012+ {-# INLINE toList #-}
1013+ toList = Data.Foldable.foldr (:) []
1014+
1015+-- XXX Fix these
1016+{-
1017+instance Eq a => Eq (Stream Identity a) where
1018+ {-# INLINE (==) #-}
1019+ (==) xs ys = runIdentity $ eqBy (==) xs ys
1020+
1021+instance Ord a => Ord (Stream Identity a) where
1022+ {-# INLINE compare #-}
1023+ compare xs ys = runIdentity $ cmpBy compare xs ys
1024+
1025+ {-# INLINE (<) #-}
1026+ x < y =
1027+ case compare x y of
1028+ LT -> True
1029+ _ -> False
1030+
1031+ {-# INLINE (<=) #-}
1032+ x <= y =
1033+ case compare x y of
1034+ GT -> False
1035+ _ -> True
1036+
1037+ {-# INLINE (>) #-}
1038+ x > y =
1039+ case compare x y of
1040+ GT -> True
1041+ _ -> False
1042+
1043+ {-# INLINE (>=) #-}
1044+ x >= y =
1045+ case compare x y of
1046+ LT -> False
1047+ _ -> True
1048+
1049+ {-# INLINE max #-}
1050+ max x y = if x <= y then y else x
1051+
1052+ {-# INLINE min #-}
1053+ min x y = if x <= y then x else y
1054+-}
1055+
1056+instance Show a => Show (Stream Identity a) where
1057+ showsPrec p dl = showParen (p > 10) $
1058+ showString "fromList " . shows (toList dl)
1059+
1060+instance Read a => Read (Stream Identity a) where
1061+ readPrec = parens $ prec 10 $ do
1062+ Ident "fromList" <- lexP
1063+ fromList <$> readPrec
1064+
1065+ readListPrec = readListPrecDefault
1066+
1067+instance (a ~ Char) => IsString (Stream Identity a) where
1068+ {-# INLINE fromString #-}
1069+ fromString = fromList
1070+
1071+-------------------------------------------------------------------------------
1072+-- Foldable
1073+-------------------------------------------------------------------------------
1074+
1075+-- | Lazy right associative fold.
1076+{-# INLINE foldr #-}
1077+foldr :: Monad m => (a -> b -> b) -> b -> Stream m a -> m b
1078+foldr step acc = foldrM (\x xs -> xs >>= \b -> return (step x b)) (return acc)
1079+
1080+-- The default Foldable instance has several issues:
1081+-- 1) several definitions do not have INLINE on them, so we provide
1082+-- re-implementations with INLINE pragmas.
1083+-- 2) the definitions of sum/product/maximum/minimum are inefficient as they
1084+-- use right folds, they cannot run in constant memory. We provide
1085+-- implementations using strict left folds here.
1086+
1087+instance (Foldable m, Monad m) => Foldable (Stream m) where
1088+
1089+ {-# INLINE foldMap #-}
1090+ foldMap f =
1091+ fold
1092+ . Streamly.Internal.Data.Stream.StreamK.Type.foldr (mappend . f) mempty
1093+
1094+ {-# INLINE foldr #-}
1095+ foldr f z t = appEndo (foldMap (Endo #. f) t) z
1096+
1097+ {-# INLINE foldl' #-}
1098+ foldl' f z0 xs = Data.Foldable.foldr f' id xs z0
1099+ where f' x k = oneShot $ \z -> k $! f z x
1100+
1101+ {-# INLINE length #-}
1102+ length = Data.Foldable.foldl' (\n _ -> n + 1) 0
1103+
1104+ {-# INLINE elem #-}
1105+ elem = any . (==)
1106+
1107+ {-# INLINE maximum #-}
1108+ maximum =
1109+ fromMaybe (errorWithoutStackTrace "maximum: empty stream")
1110+ . toMaybe
1111+ . Data.Foldable.foldl' getMax Nothing'
1112+
1113+ where
1114+
1115+ getMax Nothing' x = Just' x
1116+ getMax (Just' mx) x = Just' $! max mx x
1117+
1118+ {-# INLINE minimum #-}
1119+ minimum =
1120+ fromMaybe (errorWithoutStackTrace "minimum: empty stream")
1121+ . toMaybe
1122+ . Data.Foldable.foldl' getMin Nothing'
1123+
1124+ where
1125+
1126+ getMin Nothing' x = Just' x
1127+ getMin (Just' mn) x = Just' $! min mn x
1128+
1129+ {-# INLINE sum #-}
1130+ sum = Data.Foldable.foldl' (+) 0
1131+
1132+ {-# INLINE product #-}
1133+ product = Data.Foldable.foldl' (*) 1
1134+
1135+-------------------------------------------------------------------------------
1136+-- Traversable
1137+-------------------------------------------------------------------------------
1138+
1139+instance Traversable (Stream Identity) where
1140+ {-# INLINE traverse #-}
1141+ traverse f xs =
1142+ runIdentity
1143+ $ Streamly.Internal.Data.Stream.StreamK.Type.foldr
1144+ consA (pure mempty) xs
1145+
1146+ where
1147+
1148+ consA x ys = liftA2 cons (f x) ys
1149+
864-------------------------------------------------------------------------------
1150-------------------------------------------------------------------------------
865-- Nesting
1151-- Nesting
866-------------------------------------------------------------------------------
1152-------------------------------------------------------------------------------
@@ -895,6 +1181,15 @@ crossApplyWith par fstream stream = go1 fstream
895 yieldk a r = yld (f a) (go2 f r)
1181 yieldk a r = yld (f a) (go2 f r)
896 in foldStream (adaptState st) yieldk single stp m
1182 in foldStream (adaptState st) yieldk single stp m
897
1183
1184+-- | Apply a stream of functions to a stream of values and flatten the results.
1185+--
1186+-- Note that the second stream is evaluated multiple times.
1187+--
1188+-- Definition:
1189+--
1190+-- >>> crossApply = StreamK.crossApplyWith StreamK.append
1191+-- >>> crossApply = Stream.crossWith id
1192+--
898{-# INLINE crossApply #-}
1193{-# INLINE crossApply #-}
899crossApply ::
1194crossApply ::
900 Stream m (a -> b)
1195 Stream m (a -> b)
@@ -979,6 +1274,39 @@ crossApplyFst fstream stream = go1 fstream
979 yieldk _ r = yld f (go3 f r)
1274 yieldk _ r = yld f (go3 f r)
980 in foldStream (adaptState st) yieldk single stp m
1275 in foldStream (adaptState st) yieldk single stp m
981
1276
1277+-- |
1278+-- Definition:
1279+--
1280+-- >>> crossWith f m1 m2 = fmap f m1 `StreamK.crossApply` m2
1281+--
1282+-- Note that the second stream is evaluated multiple times.
1283+--
1284+{-# INLINE crossWith #-}
1285+crossWith :: Monad m => (a -> b -> c) -> Stream m a -> Stream m b -> Stream m c
1286+crossWith f m1 m2 = fmap f m1 `crossApply` m2
1287+
1288+-- | Given a @Stream m a@ and @Stream m b@ generate a stream with all possible
1289+-- combinations of the tuple @(a, b)@.
1290+--
1291+-- Definition:
1292+--
1293+-- >>> cross = StreamK.crossWith (,)
1294+--
1295+-- The second stream is evaluated multiple times. If that is not desired it can
1296+-- be cached in an 'Data.Array.Array' and then generated from the array before
1297+-- calling this function. Caching may also improve performance if the stream is
1298+-- expensive to evaluate.
1299+--
1300+-- See 'Streamly.Internal.Data.Unfold.cross' for a much faster fused
1301+-- alternative.
1302+--
1303+-- Time: O(m x n)
1304+--
1305+-- /Pre-release/
1306+{-# INLINE cross #-}
1307+cross :: Monad m => Stream m a -> Stream m b -> Stream m (a, b)
1308+cross = crossWith (,)
1309+
982-- XXX This is just concatMapWith with arguments flipped. We need to keep this
1310-- XXX This is just concatMapWith with arguments flipped. We need to keep this
983-- instead of using a concatMap style definition because the bind
1311-- instead of using a concatMap style definition because the bind
984-- implementation in Async and WAsync streams show significant perf degradation
1312-- implementation in Async and WAsync streams show significant perf degradation
@@ -1010,7 +1338,6 @@ bindWith par m1 f = go m1
1010-- argument specifies a merge or concat function that is used to merge the
1338-- argument specifies a merge or concat function that is used to merge the
1011-- streams generated by the map function.
1339-- streams generated by the map function.
1012--
1340--
1013−-- @since 0.7.0
1014{-# INLINE concatMapWith #-}
1341{-# INLINE concatMapWith #-}
1015concatMapWith
1342concatMapWith
1016 ::
1343 ::
@@ -1022,7 +1349,7 @@ concatMapWith par f xs = bindWith par xs f
1022
1349
1023{-# INLINE concatMap #-}
1350{-# INLINE concatMap #-}
1024concatMap :: (a -> Stream m b) -> Stream m a -> Stream m b
1351concatMap :: (a -> Stream m b) -> Stream m a -> Stream m b
1025−concatMap = concatMapWith serial
1352+concatMap = concatMapWith append
1026
1353
1027{-
1354{-
1028-- Fused version.
1355-- Fused version.
@@ -1042,17 +1369,34 @@ concatMap_ f xs = buildS
1042 (\c n -> foldrSShared (\x b -> foldrSShared c b (unShare $ f x)) n xs)
1369 (\c n -> foldrSShared (\x b -> foldrSShared c b (unShare $ f x)) n xs)
1043-}
1370-}
1044
1371
1045−-- | See 'Streamly.Internal.Data.Stream.concatPairsWith' for
1372+-- | Combine streams in pairs using a binary combinator, the resulting streams
1046−-- documentation.
1373+-- are then combined again in pairs recursively until we get to a single
1374+-- combined stream. The composition would thus form a binary tree.
1375+--
1376+-- For example, you can sort a stream using merge sort like this:
1377+--
1378+-- >>> s = StreamK.fromStream $ Stream.fromList [5,1,7,9,2]
1379+-- >>> generate = StreamK.fromPure
1380+-- >>> combine = StreamK.mergeBy compare
1381+-- >>> Stream.fold Fold.toList $ StreamK.toStream $ StreamK.mergeMapWith combine generate s
1382+-- [1,2,5,7,9]
1383+--
1384+-- Note that if the stream length is not a power of 2, the binary tree composed
1385+-- by mergeMapWith would not be balanced, which may or may not be important
1386+-- depending on what you are trying to achieve.
1387+--
1388+-- /Caution: the stream of streams must be finite/
1047--
1389--
1048−{-# INLINE concatPairsWith #-}
1390+-- /Pre-release/
1049−concatPairsWith
1391+--
1392+{-# INLINE mergeMapWith #-}
1393+mergeMapWith
1050 ::
1394 ::
1051 (Stream m b -> Stream m b -> Stream m b)
1395 (Stream m b -> Stream m b -> Stream m b)
1052 -> (a -> Stream m b)
1396 -> (a -> Stream m b)
1053 -> Stream m a
1397 -> Stream m a
1054 -> Stream m b
1398 -> Stream m b
1055−concatPairsWith combine f str = go (leafPairs str)
1399+mergeMapWith combine f str = go (leafPairs str)
1056
1400
1057 where
1401 where
1058
1402
@@ -1139,17 +1483,172 @@ concatUnfoldr :: IsStream t
1139concatUnfoldr = undefined
1483concatUnfoldr = undefined
1140-}
1484-}
1141
1485
1486+------------------------------------------------------------------------------
1487+-- concatIterate - Map and flatten Trees of Streams
1488+------------------------------------------------------------------------------
1489+
1490+-- | Yield an input element in the output stream, map a stream generator on it
1491+-- and repeat the process on the resulting stream. Resulting streams are
1492+-- flattened using the 'concatMapWith' combinator. This can be used for a depth
1493+-- first style (DFS) traversal of a tree like structure.
1494+--
1495+-- Example, list a directory tree using DFS:
1496+--
1497+-- >>> f = StreamK.fromStream . either Dir.readEitherPaths (const Stream.nil)
1498+-- >>> input = StreamK.fromPure (Left ".")
1499+-- >>> ls = StreamK.concatIterateWith StreamK.append f input
1500+--
1501+-- Note that 'iterateM' is a special case of 'concatIterateWith':
1502+--
1503+-- >>> iterateM f = StreamK.concatIterateWith StreamK.append (StreamK.fromEffect . f) . StreamK.fromEffect
1504+--
1505+-- /Pre-release/
1506+--
1507+{-# INLINE concatIterateWith #-}
1508+concatIterateWith ::
1509+ (Stream m a -> Stream m a -> Stream m a)
1510+ -> (a -> Stream m a)
1511+ -> Stream m a
1512+ -> Stream m a
1513+concatIterateWith combine f = iterateStream
1514+
1515+ where
1516+
1517+ iterateStream = concatMapWith combine generate
1518+
1519+ generate x = x `cons` iterateStream (f x)
1520+
1521+-- | Like 'concatIterateWith' but uses the pairwise flattening combinator
1522+-- 'mergeMapWith' for flattening the resulting streams. This can be used for a
1523+-- balanced traversal of a tree like structure.
1524+--
1525+-- Example, list a directory tree using balanced traversal:
1526+--
1527+-- >>> f = StreamK.fromStream . either Dir.readEitherPaths (const Stream.nil)
1528+-- >>> input = StreamK.fromPure (Left ".")
1529+-- >>> ls = StreamK.mergeIterateWith StreamK.interleave f input
1530+--
1531+-- /Pre-release/
1532+--
1533+{-# INLINE mergeIterateWith #-}
1534+mergeIterateWith ::
1535+ (Stream m a -> Stream m a -> Stream m a)
1536+ -> (a -> Stream m a)
1537+ -> Stream m a
1538+ -> Stream m a
1539+mergeIterateWith combine f = iterateStream
1540+
1541+ where
1542+
1543+ iterateStream = mergeMapWith combine generate
1544+
1545+ generate x = x `cons` iterateStream (f x)
1546+
1547+------------------------------------------------------------------------------
1548+-- Flattening Graphs
1549+------------------------------------------------------------------------------
1550+
1551+-- To traverse graphs we need a state to be carried around in the traversal.
1552+-- For example, we can use a hashmap to store the visited status of nodes.
1553+
1554+-- | Like 'iterateMap' but carries a state in the stream generation function.
1555+-- This can be used to traverse graph like structures, we can remember the
1556+-- visited nodes in the state to avoid cycles.
1557+--
1558+-- Note that a combination of 'iterateMap' and 'usingState' can also be used to
1559+-- traverse graphs. However, this function provides a more localized state
1560+-- instead of using a global state.
1561+--
1562+-- See also: 'mfix'
1563+--
1564+-- /Pre-release/
1565+--
1566+{-# INLINE concatIterateScanWith #-}
1567+concatIterateScanWith
1568+ :: Monad m
1569+ => (Stream m a -> Stream m a -> Stream m a)
1570+ -> (b -> a -> m (b, Stream m a))
1571+ -> m b
1572+ -> Stream m a
1573+ -> Stream m a
1574+concatIterateScanWith combine f initial stream =
1575+ concatEffect $ do
1576+ b <- initial
1577+ iterateStream (b, stream)
1578+
1579+ where
1580+
1581+ iterateStream (b, s) = pure $ concatMapWith combine (generate b) s
1582+
1583+ generate b a = a `cons` feedback b a
1584+
1585+ feedback b a = concatEffect $ f b a >>= iterateStream
1586+
1587+------------------------------------------------------------------------------
1588+-- Either streams
1589+------------------------------------------------------------------------------
1590+
1591+-- Keep concating either streams as long as rights are generated, stop as soon
1592+-- as a left is generated and concat the left stream.
1593+--
1594+-- See also: 'handle'
1595+--
1596+-- /Unimplemented/
1597+--
1598+{-
1599+concatMapEitherWith
1600+ :: (forall x. t m x -> t m x -> t m x)
1601+ -> (a -> t m (Either (Stream m b) b))
1602+ -> Stream m a
1603+ -> Stream m b
1604+concatMapEitherWith = undefined
1605+-}
1606+
1607+-- XXX We should prefer using the Maybe stream returning signatures over this.
1608+-- This API should perhaps be removed in favor of those.
1609+
1610+-- | In an 'Either' stream iterate on 'Left's. This is a special case of
1611+-- 'concatIterateWith':
1612+--
1613+-- >>> concatIterateLeftsWith combine f = StreamK.concatIterateWith combine (either f (const StreamK.nil))
1614+--
1615+-- To traverse a directory tree:
1616+--
1617+-- >>> input = StreamK.fromPure (Left ".")
1618+-- >>> ls = StreamK.concatIterateLeftsWith StreamK.append (StreamK.fromStream . Dir.readEither) input
1619+--
1620+-- /Pre-release/
1621+--
1622+{-# INLINE concatIterateLeftsWith #-}
1623+concatIterateLeftsWith
1624+ :: (b ~ Either a c)
1625+ => (Stream m b -> Stream m b -> Stream m b)
1626+ -> (a -> Stream m b)
1627+ -> Stream m b
1628+ -> Stream m b
1629+concatIterateLeftsWith combine f =
1630+ concatIterateWith combine (either f (const nil))
1631+
1142------------------------------------------------------------------------------
1632------------------------------------------------------------------------------
1143-- Interleaving
1633-- Interleaving
1144------------------------------------------------------------------------------
1634------------------------------------------------------------------------------
1145
1635
1636+infixr 6 `interleave`
1637+
1146-- Additionally we can have m elements yield from the first stream and n
1638-- Additionally we can have m elements yield from the first stream and n
1147-- elements yielding from the second stream. We can also have time slicing
1639-- elements yielding from the second stream. We can also have time slicing
1148-- variants of positional interleaving, e.g. run first stream for m seconds and
1640-- variants of positional interleaving, e.g. run first stream for m seconds and
1149-- run the second stream for n seconds.
1641-- run the second stream for n seconds.
1150−--
1151−-- Similar combinators can be implemented using WAhead style.
1152
1642
1643+-- | Interleaves two streams, yielding one element from each stream
1644+-- alternately. When one stream stops the rest of the other stream is used in
1645+-- the output stream.
1646+--
1647+-- When joining many streams in a left associative manner earlier streams will
1648+-- get exponential priority than the ones joining later. Because of exponential
1649+-- weighting it can be used with 'concatMapWith' even on a large number of
1650+-- streams.
1651+--
1153{-# INLINE interleave #-}
1652{-# INLINE interleave #-}
1154interleave :: Stream m a -> Stream m a -> Stream m a
1653interleave :: Stream m a -> Stream m a -> Stream m a
1155interleave m1 m2 = mkStream $ \st yld sng stp -> do
1654interleave m1 m2 = mkStream $ \st yld sng stp -> do
@@ -1158,7 +1657,9 @@ interleave m1 m2 = mkStream $ \st yld sng stp -> do
1158 yieldk a r = yld a (interleave m2 r)
1657 yieldk a r = yld a (interleave m2 r)
1159 foldStream st yieldk single stop m1
1658 foldStream st yieldk single stop m1
1160
1659
1660+infixr 6 `interleaveFst`
1661+
1161−-- | Like `interleaveK` but stops interleaving as soon as the first stream stops.
1662+-- | Like `interleave` but stops interleaving as soon as the first stream stops.
1162--
1663--
1163{-# INLINE interleaveFst #-}
1664{-# INLINE interleaveFst #-}
1164interleaveFst :: Stream m a -> Stream m a -> Stream m a
1665interleaveFst :: Stream m a -> Stream m a -> Stream m a
@@ -1174,6 +1675,11 @@ interleaveFst m1 m2 = mkStream $ \st yld sng stp -> do
1174 yieldk a r = yld a (interleave s1 r)
1675 yieldk a r = yld a (interleave s1 r)
1175 in foldStream st yieldk single stop s2
1676 in foldStream st yieldk single stop s2
1176
1677
1678+infixr 6 `interleaveMin`
1679+
1680+-- | Like `interleave` but stops interleaving as soon as any of the two streams
1681+-- stops.
1682+--
1177{-# INLINE interleaveMin #-}
1683{-# INLINE interleaveMin #-}
1178interleaveMin :: Stream m a -> Stream m a -> Stream m a
1684interleaveMin :: Stream m a -> Stream m a -> Stream m a
1179interleaveMin m1 m2 = mkStream $ \st yld _ stp -> do
1685interleaveMin m1 m2 = mkStream $ \st yld _ stp -> do
@@ -1214,6 +1720,10 @@ unfoldrMWith cns step = go
1214 Just (a, b) -> yld a (go b)
1720 Just (a, b) -> yld a (go b)
1215 Nothing -> stp
1721 Nothing -> stp
1216
1722
1723+{-# INLINE unfoldrM #-}
1724+unfoldrM :: Monad m => (b -> m (Maybe (a, b))) -> b -> Stream m a
1725+unfoldrM = unfoldrMWith consM
1726+
1217-- | Generate an infinite stream by repeating a pure value.
1727-- | Generate an infinite stream by repeating a pure value.
1218--
1728--
1219-- /Pre-release/
1729-- /Pre-release/
@@ -1274,6 +1784,56 @@ tailPartial m = mkStream $ \st yld sng stp ->
1274 yieldk _ r = foldStream st yld sng stp r
1784 yieldk _ r = foldStream st yld sng stp r
1275 in foldStream st yieldk single stop m
1785 in foldStream st yieldk single stop m
1276
1786
1787+-- | We can define cyclic structures using @let@:
1788+--
1789+-- >>> let (a, b) = ([1, b], head a) in (a, b)
1790+-- ([1,1],1)
1791+--
1792+-- The function @fix@ defined as:
1793+--
1794+-- >>> fix f = let x = f x in x
1795+--
1796+-- ensures that the argument of a function and its output refer to the same
1797+-- lazy value @x@ i.e. the same location in memory. Thus @x@ can be defined
1798+-- in terms of itself, creating structures with cyclic references.
1799+--
1800+-- >>> f ~(a, b) = ([1, b], head a)
1801+-- >>> fix f
1802+-- ([1,1],1)
1803+--
1804+-- 'Control.Monad.mfix' is essentially the same as @fix@ but for monadic
1805+-- values.
1806+--
1807+-- Using 'mfix' for streams we can construct a stream in which each element of
1808+-- the stream is defined in a cyclic fashion. The argument of the function
1809+-- being fixed represents the current element of the stream which is being
1810+-- returned by the stream monad. Thus, we can use the argument to construct
1811+-- itself.
1812+--
1813+-- In the following example, the argument @action@ of the function @f@
1814+-- represents the tuple @(x,y)@ returned by it in a given iteration. We define
1815+-- the first element of the tuple in terms of the second.
1816+--
1817+-- >>> import System.IO.Unsafe (unsafeInterleaveIO)
1818+--
1819+-- >>> :{
1820+-- main = Stream.fold (Fold.drainMapM print) $ StreamK.toStream $ StreamK.mfix f
1821+-- where
1822+-- f action = StreamK.unCross $ do
1823+-- let incr n act = fmap ((+n) . snd) $ unsafeInterleaveIO act
1824+-- x <- StreamK.mkCross $ StreamK.fromStream $ Stream.sequence $ Stream.fromList [incr 1 action, incr 2 action]
1825+-- y <- StreamK.mkCross $ StreamK.fromStream $ Stream.fromList [4,5]
1826+-- return (x, y)
1827+-- :}
1828+--
1829+-- Note: you cannot achieve this by just changing the order of the monad
1830+-- statements because that would change the order in which the stream elements
1831+-- are generated.
1832+--
1833+-- Note that the function @f@ must be lazy in its argument, that's why we use
1834+-- 'unsafeInterleaveIO' on @action@ because IO monad is strict.
1835+--
1836+-- /Pre-release/
1277{-# INLINE mfix #-}
1837{-# INLINE mfix #-}
1278mfix :: Monad m => (m a -> Stream m a) -> Stream m a
1838mfix :: Monad m => (m a -> Stream m a) -> Stream m a
1279mfix f = mkStream $ \st yld sng stp ->
1839mfix f = mkStream $ \st yld sng stp ->
@@ -1329,6 +1889,11 @@ tail =
1329 yieldk _ r = pure $ Just r
1889 yieldk _ r = pure $ Just r
1330 in foldStream defState yieldk single stop
1890 in foldStream defState yieldk single stop
1331
1891
1892+-- | Extract all but the last element of the stream, if any.
1893+--
1894+-- Note: This will end up buffering the entire stream.
1895+--
1896+-- /Pre-release/
1332{-# INLINE init #-}
1897{-# INLINE init #-}
1333init :: Applicative m => Stream m a -> m (Maybe (Stream m a))
1898init :: Applicative m => Stream m a -> m (Maybe (Stream m a))
1334init = go1
1899init = go1
@@ -1386,3 +1951,123 @@ concatMapEffect :: Monad m => (b -> Stream m a) -> m b -> Stream m a
1386concatMapEffect f action =
1951concatMapEffect f action =
1387 mkStream $ \st yld sng stp ->
1952 mkStream $ \st yld sng stp ->
1388 action >>= foldStreamShared st yld sng stp . f
1953 action >>= foldStreamShared st yld sng stp . f
1954+
1955+------------------------------------------------------------------------------
1956+-- Stream with a cross product style monad instance
1957+------------------------------------------------------------------------------
1958+
1959+-- | A newtype wrapper for the 'StreamK' type adding a cross product style
1960+-- monad instance.
1961+--
1962+-- A 'Monad' bind behaves like a @for@ loop:
1963+--
1964+-- >>> :{
1965+-- Stream.fold Fold.toList $ StreamK.toStream $ StreamK.unCross $ do
1966+-- x <- StreamK.mkCross $ StreamK.fromStream $ Stream.fromList [1,2]
1967+-- -- Perform the following actions for each x in the stream
1968+-- return x
1969+-- :}
1970+-- [1,2]
1971+--
1972+-- Nested monad binds behave like nested @for@ loops:
1973+--
1974+-- >>> :{
1975+-- Stream.fold Fold.toList $ StreamK.toStream $ StreamK.unCross $ do
1976+-- x <- StreamK.mkCross $ StreamK.fromStream $ Stream.fromList [1,2]
1977+-- y <- StreamK.mkCross $ StreamK.fromStream $ Stream.fromList [3,4]
1978+-- -- Perform the following actions for each x, for each y
1979+-- return (x, y)
1980+-- :}
1981+-- [(1,3),(1,4),(2,3),(2,4)]
1982+--
1983+newtype CrossStreamK m a = CrossStreamK {unCrossStreamK :: Stream m a}
1984+ deriving (Functor, Semigroup, Monoid, Foldable)
1985+
1986+-- | Wrap the 'StreamK' type in a 'CrossStreamK' newtype to enable cross
1987+-- product style applicative and monad instances.
1988+--
1989+-- This is a type level operation with no runtime overhead.
1990+{-# INLINE mkCross #-}
1991+mkCross :: StreamK m a -> CrossStreamK m a
1992+mkCross = CrossStreamK
1993+
1994+-- | Unwrap the 'StreamK' type from 'CrossStreamK' newtype.
1995+--
1996+-- This is a type level operation with no runtime overhead.
1997+{-# INLINE unCross #-}
1998+unCross :: CrossStreamK m a -> StreamK m a
1999+unCross = unCrossStreamK
2000+
2001+-- Pure (Identity monad) stream instances
2002+deriving instance Traversable (CrossStreamK Identity)
2003+deriving instance IsList (CrossStreamK Identity a)
2004+deriving instance (a ~ Char) => IsString (CrossStreamK Identity a)
2005+-- deriving instance Eq a => Eq (CrossStreamK Identity a)
2006+-- deriving instance Ord a => Ord (CrossStreamK Identity a)
2007+
2008+-- Do not use automatic derivation for this to show as "fromList" rather than
2009+-- "fromList Identity".
2010+instance Show a => Show (CrossStreamK Identity a) where
2011+ {-# INLINE show #-}
2012+ show (CrossStreamK xs) = show xs
2013+
2014+instance Read a => Read (CrossStreamK Identity a) where
2015+ {-# INLINE readPrec #-}
2016+ readPrec = fmap CrossStreamK readPrec
2017+
2018+------------------------------------------------------------------------------
2019+-- Applicative
2020+------------------------------------------------------------------------------
2021+
2022+-- Note: we need to define all the typeclass operations because we want to
2023+-- INLINE them.
2024+instance Monad m => Applicative (CrossStreamK m) where
2025+ {-# INLINE pure #-}
2026+ pure x = CrossStreamK (fromPure x)
2027+
2028+ {-# INLINE (<*>) #-}
2029+ (CrossStreamK s1) <*> (CrossStreamK s2) =
2030+ CrossStreamK (crossApply s1 s2)
2031+
2032+ {-# INLINE liftA2 #-}
2033+ liftA2 f x = (<*>) (fmap f x)
2034+
2035+ {-# INLINE (*>) #-}
2036+ (CrossStreamK s1) *> (CrossStreamK s2) =
2037+ CrossStreamK (crossApplySnd s1 s2)
2038+
2039+ {-# INLINE (<*) #-}
2040+ (CrossStreamK s1) <* (CrossStreamK s2) =
2041+ CrossStreamK (crossApplyFst s1 s2)
2042+
2043+------------------------------------------------------------------------------
2044+-- Monad
2045+------------------------------------------------------------------------------
2046+
2047+instance Monad m => Monad (CrossStreamK m) where
2048+ return = pure
2049+
2050+ -- Benchmarks better with CPS bind and pure:
2051+ -- Prime sieve (25x)
2052+ -- n binds, breakAfterSome, filterAllIn, state transformer (~2x)
2053+ --
2054+ {-# INLINE (>>=) #-}
2055+ (>>=) (CrossStreamK m) f =
2056+ CrossStreamK (bindWith append m (unCrossStreamK . f))
2057+
2058+ {-# INLINE (>>) #-}
2059+ (>>) = (*>)
2060+
2061+------------------------------------------------------------------------------
2062+-- Transformers
2063+------------------------------------------------------------------------------
2064+
2065+instance (MonadIO m) => MonadIO (CrossStreamK m) where
2066+ liftIO x = CrossStreamK (fromEffect $ liftIO x)
2067+
2068+instance MonadTrans CrossStreamK where
2069+ {-# INLINE lift #-}
2070+ lift x = CrossStreamK (fromEffect x)
2071+
2072+instance (MonadThrow m) => MonadThrow (CrossStreamK m) where
2073+ throwM = lift . throwM
core/src/Streamly/Internal/Data/Stream/Transform.hs+1−1
@@ -427,7 +427,7 @@ scanlMAfter' step initial done stream =
427--
427--
428{-# INLINE scan #-}
428{-# INLINE scan #-}
429scan :: Monad m => Fold m a b -> Stream m a -> Stream m b
429scan :: Monad m => Fold m a b -> Stream m a -> Stream m b
430−scan fld m = fromStreamD $ D.scanOnce fld $ toStreamD m
430+scan fld m = fromStreamD $ D.scan fld $ toStreamD m
431
431
432-- | Like 'scan' but restarts scanning afresh when the scanning fold
432-- | Like 'scan' but restarts scanning afresh when the scanning fold
433-- terminates.
433-- terminates.
core/src/Streamly/Internal/Data/Stream/Type.hs+31−18
@@ -11,13 +11,16 @@
11module Streamly.Internal.Data.Stream.Type
11module Streamly.Internal.Data.Stream.Type
12 (
12 (
13 -- * Stream Type
13 -- * Stream Type
14− Stream
14+ Stream -- XXX To be removed
15+ , StreamK
15
16
16 -- * Type Conversion
17 -- * Type Conversion
17 , fromStreamK
18 , fromStreamK
18 , toStreamK
19 , toStreamK
19 , fromStreamD
20 , fromStreamD
20 , toStreamD
21 , toStreamD
22+ , fromStream
23+ , toStream
21 , Streamly.Internal.Data.Stream.Type.fromList
24 , Streamly.Internal.Data.Stream.Type.fromList
22
25
23 -- * Construction
26 -- * Construction
@@ -76,21 +79,23 @@ import qualified Streamly.Internal.Data.Stream.StreamK.Type as K
76--
79--
77-- >>> (<>) = Stream.append
80-- >>> (<>) = Stream.append
78--
81--
79−newtype Stream m a = Stream (K.Stream m a)
82+newtype StreamK m a = StreamK (K.Stream m a)
80 -- XXX when deriving do we inherit an INLINE?
83 -- XXX when deriving do we inherit an INLINE?
81 deriving (Semigroup, Monoid)
84 deriving (Semigroup, Monoid)
82
85
86+type Stream = StreamK
87+
83------------------------------------------------------------------------------
88------------------------------------------------------------------------------
84-- Conversions
89-- Conversions
85------------------------------------------------------------------------------
90------------------------------------------------------------------------------
86
91
87{-# INLINE_EARLY fromStreamK #-}
92{-# INLINE_EARLY fromStreamK #-}
88fromStreamK :: K.Stream m a -> Stream m a
93fromStreamK :: K.Stream m a -> Stream m a
89−fromStreamK = Stream
94+fromStreamK = StreamK
90
95
91{-# INLINE_EARLY toStreamK #-}
96{-# INLINE_EARLY toStreamK #-}
92toStreamK :: Stream m a -> K.Stream m a
97toStreamK :: Stream m a -> K.Stream m a
93−toStreamK (Stream k) = k
98+toStreamK (StreamK k) = k
94
99
95{-# INLINE_EARLY fromStreamD #-}
100{-# INLINE_EARLY fromStreamD #-}
96fromStreamD :: Monad m => D.Stream m a -> Stream m a
101fromStreamD :: Monad m => D.Stream m a -> Stream m a
@@ -100,6 +105,14 @@ fromStreamD = fromStreamK . D.toStreamK
100toStreamD :: Applicative m => Stream m a -> D.Stream m a
105toStreamD :: Applicative m => Stream m a -> D.Stream m a
101toStreamD = D.fromStreamK . toStreamK
106toStreamD = D.fromStreamK . toStreamK
102
107
108+{-# INLINE fromStream #-}
109+fromStream :: Monad m => D.Stream m a -> Stream m a
110+fromStream = fromStreamD
111+
112+{-# INLINE toStream #-}
113+toStream :: Applicative m => Stream m a -> D.Stream m a
114+toStream = toStreamD
115+
103------------------------------------------------------------------------------
116------------------------------------------------------------------------------
104-- Generation
117-- Generation
105------------------------------------------------------------------------------
118------------------------------------------------------------------------------
@@ -162,18 +175,18 @@ instance IsList (Stream Identity a) where
162 type (Item (Stream Identity a)) = a
175 type (Item (Stream Identity a)) = a
163
176
164 {-# INLINE fromList #-}
177 {-# INLINE fromList #-}
165− fromList xs = Stream $ P.fromList xs
178+ fromList xs = StreamK $ P.fromList xs
166
179
167 {-# INLINE toList #-}
180 {-# INLINE toList #-}
168− toList (Stream xs) = runIdentity $ P.toList xs
181+ toList (StreamK xs) = runIdentity $ P.toList xs
169
182
170instance Eq a => Eq (Stream Identity a) where
183instance Eq a => Eq (Stream Identity a) where
171 {-# INLINE (==) #-}
184 {-# INLINE (==) #-}
172− (==) (Stream xs) (Stream ys) = runIdentity $ P.eqBy (==) xs ys
185+ (==) (StreamK xs) (StreamK ys) = runIdentity $ P.eqBy (==) xs ys
173
186
174instance Ord a => Ord (Stream Identity a) where
187instance Ord a => Ord (Stream Identity a) where
175 {-# INLINE compare #-}
188 {-# INLINE compare #-}
176− compare (Stream xs) (Stream ys) = runIdentity $ P.cmpBy compare xs ys
189+ compare (StreamK xs) (StreamK ys) = runIdentity $ P.cmpBy compare xs ys
177
190
178 {-# INLINE (<) #-}
191 {-# INLINE (<) #-}
179 x < y =
192 x < y =
@@ -218,7 +231,7 @@ instance Read a => Read (Stream Identity a) where
218
231
219instance (a ~ Char) => IsString (Stream Identity a) where
232instance (a ~ Char) => IsString (Stream Identity a) where
220 {-# INLINE fromString #-}
233 {-# INLINE fromString #-}
221− fromString xs = Stream $ P.fromList xs
234+ fromString xs = StreamK $ P.fromList xs
222
235
223-------------------------------------------------------------------------------
236-------------------------------------------------------------------------------
224-- Foldable
237-- Foldable
@@ -234,7 +247,7 @@ instance (a ~ Char) => IsString (Stream Identity a) where
234instance (Foldable m, Monad m) => Foldable (Stream m) where
247instance (Foldable m, Monad m) => Foldable (Stream m) where
235
248
236 {-# INLINE foldMap #-}
249 {-# INLINE foldMap #-}
237− foldMap f (Stream xs) = fold $ P.foldr (mappend . f) mempty xs
250+ foldMap f (StreamK xs) = fold $ P.foldr (mappend . f) mempty xs
238
251
239 {-# INLINE foldr #-}
252 {-# INLINE foldr #-}
240 foldr f z t = appEndo (foldMap (Endo #. f) t) z
253 foldr f z t = appEndo (foldMap (Endo #. f) t) z
@@ -283,8 +296,8 @@ instance (Foldable m, Monad m) => Foldable (Stream m) where
283
296
284instance Traversable (Stream Identity) where
297instance Traversable (Stream Identity) where
285 {-# INLINE traverse #-}
298 {-# INLINE traverse #-}
286− traverse f (Stream xs) =
299+ traverse f (StreamK xs) =
287− fmap Stream $ runIdentity $ P.foldr consA (pure mempty) xs
300+ fmap StreamK $ runIdentity $ P.foldr consA (pure mempty) xs
288
301
289 where
302 where
290
303
@@ -396,19 +409,19 @@ fromEffect = fromStreamK . K.fromEffect
396-- >>> crossApply = Stream.crossWith id
409-- >>> crossApply = Stream.crossWith id
397--
410--
398{-# INLINE crossApply #-}
411{-# INLINE crossApply #-}
399−crossApply :: Monad m => Stream m (a -> b) -> Stream m a -> Stream m b
412+crossApply :: Stream m (a -> b) -> Stream m a -> Stream m b
400crossApply m1 m2 =
413crossApply m1 m2 =
401− fromStreamD $ D.crossApply (toStreamD m1) (toStreamD m2)
414+ fromStreamK $ K.crossApply (toStreamK m1) (toStreamK m2)
402
415
403{-# INLINE crossApplySnd #-}
416{-# INLINE crossApplySnd #-}
404−crossApplySnd :: Monad m => Stream m a -> Stream m b -> Stream m b
417+crossApplySnd :: Stream m a -> Stream m b -> Stream m b
405crossApplySnd m1 m2 =
418crossApplySnd m1 m2 =
406− fromStreamD $ D.crossApplySnd (toStreamD m1) (toStreamD m2)
419+ fromStreamK $ K.crossApplySnd (toStreamK m1) (toStreamK m2)
407
420
408{-# INLINE crossApplyFst #-}
421{-# INLINE crossApplyFst #-}
409−crossApplyFst :: Monad m => Stream m a -> Stream m b -> Stream m a
422+crossApplyFst :: Stream m a -> Stream m b -> Stream m a
410crossApplyFst m1 m2 =
423crossApplyFst m1 m2 =
411− fromStreamD $ D.crossApplyFst (toStreamD m1) (toStreamD m2)
424+ fromStreamK $ K.crossApplyFst (toStreamK m1) (toStreamK m2)
412
425
413-- |
426-- |
414-- Definition:
427-- Definition:
core/src/Streamly/Internal/Data/Unfold.hs+2−3
@@ -292,7 +292,6 @@ import qualified Data.Tuple as Tuple
292import qualified Streamly.Internal.Data.Fold.Type as FL
292import qualified Streamly.Internal.Data.Fold.Type as FL
293import qualified Streamly.Internal.Data.Stream.StreamD.Type as D
293import qualified Streamly.Internal.Data.Stream.StreamD.Type as D
294import qualified Streamly.Internal.Data.Stream.StreamK.Type as K
294import qualified Streamly.Internal.Data.Stream.StreamK.Type as K
295−import qualified Streamly.Internal.Data.Stream.Type as Stream
296import qualified Prelude
295import qualified Prelude
297
296
298import Streamly.Internal.Data.Unfold.Enumeration
297import Streamly.Internal.Data.Unfold.Enumeration
@@ -604,8 +603,8 @@ fromStreamK = Unfold step pure
604 Nothing -> Stop) <$> K.uncons stream
603 Nothing -> Stop) <$> K.uncons stream
605
604
606{-# INLINE fromStream #-}
605{-# INLINE fromStream #-}
607−fromStream :: Applicative m => Unfold m (Stream.Stream m a) a
606+fromStream :: Applicative m => Unfold m (Stream m a) a
608−fromStream = lmap Stream.toStreamK fromStreamK
607+fromStream = fromStreamD
609
608
610-------------------------------------------------------------------------------
609-------------------------------------------------------------------------------
611-- Unfolds
610-- Unfolds
core/src/Streamly/Internal/FileSystem/File.hs+9−5
@@ -107,18 +107,18 @@ import Streamly.Data.Fold (chunksOf, drain)
107import Streamly.Internal.Data.Array.Type (Array(..), writeNUnsafe)
107import Streamly.Internal.Data.Array.Type (Array(..), writeNUnsafe)
108import Streamly.Internal.Data.Fold.Type (Fold(..))
108import Streamly.Internal.Data.Fold.Type (Fold(..))
109import Streamly.Data.Stream (Stream)
109import Streamly.Data.Stream (Stream)
110+import Streamly.Internal.Data.Unboxed (Unbox)
110import Streamly.Internal.Data.Unfold.Type (Unfold(..))
111import Streamly.Internal.Data.Unfold.Type (Unfold(..))
111-- import Streamly.String (encodeUtf8, decodeUtf8, foldLines)
112-- import Streamly.String (encodeUtf8, decodeUtf8, foldLines)
112import Streamly.Internal.System.IO (defaultChunkSize)
113import Streamly.Internal.System.IO (defaultChunkSize)
113
114
114import qualified Streamly.Data.Array as A
115import qualified Streamly.Data.Array as A
116+import qualified Streamly.Data.Stream as S
115import qualified Streamly.Data.Unfold as UF
117import qualified Streamly.Data.Unfold as UF
116import qualified Streamly.Internal.Data.Unfold as UF (bracketIO)
118import qualified Streamly.Internal.Data.Unfold as UF (bracketIO)
117import qualified Streamly.Internal.Data.Fold.Type as FL
119import qualified Streamly.Internal.Data.Fold.Type as FL
118 (Step(..), snoc, reduce)
120 (Step(..), snoc, reduce)
119import qualified Streamly.Internal.FileSystem.Handle as FH
121import qualified Streamly.Internal.FileSystem.Handle as FH
120−import qualified Streamly.Internal.Data.Stream.Chunked as AS
121−import qualified Streamly.Data.Stream as S (fold, bracketIO, mapM)
122
122
123-------------------------------------------------------------------------------
123-------------------------------------------------------------------------------
124-- References
124-- References
@@ -339,6 +339,10 @@ readWithBufferOf = readerWith
339reader :: (MonadIO m, MonadCatch m) => Unfold m FilePath Word8
339reader :: (MonadIO m, MonadCatch m) => Unfold m FilePath Word8
340reader = UF.many A.reader (usingFile FH.chunkReader)
340reader = UF.many A.reader (usingFile FH.chunkReader)
341
341
342+{-# INLINE concatChunks #-}
343+concatChunks :: (Monad m, Unbox a) => Stream m (Array a) -> Stream m a
344+concatChunks = S.unfoldMany A.reader
345+
342-- | Generate a stream of bytes from a file specified by path. The stream ends
346-- | Generate a stream of bytes from a file specified by path. The stream ends
343-- when EOF is encountered. File is locked using multiple reader and single
347-- when EOF is encountered. File is locked using multiple reader and single
344-- writer locking mode.
348-- writer locking mode.
@@ -347,7 +351,7 @@ reader = UF.many A.reader (usingFile FH.chunkReader)
347--
351--
348{-# INLINE read #-}
352{-# INLINE read #-}
349read :: (MonadIO m, MonadCatch m) => FilePath -> Stream m Word8
353read :: (MonadIO m, MonadCatch m) => FilePath -> Stream m Word8
350−read file = AS.concat $ withFile file ReadMode FH.readChunks
354+read file = concatChunks $ withFile file ReadMode FH.readChunks
351
355
352{-# DEPRECATED toBytes "Please use 'read' instead" #-}
356{-# DEPRECATED toBytes "Please use 'read' instead" #-}
353{-# INLINE toBytes #-}
357{-# INLINE toBytes #-}
@@ -401,7 +405,7 @@ fromChunks = fromChunksMode WriteMode
401{-# INLINE fromBytesWith #-}
405{-# INLINE fromBytesWith #-}
402fromBytesWith :: (MonadIO m, MonadCatch m)
406fromBytesWith :: (MonadIO m, MonadCatch m)
403 => Int -> FilePath -> Stream m Word8 -> m ()
407 => Int -> FilePath -> Stream m Word8 -> m ()
404−fromBytesWith n file xs = fromChunks file $ AS.arraysOf n xs
408+fromBytesWith n file xs = fromChunks file $ S.arraysOf n xs
405
409
406{-# DEPRECATED fromBytesWithBufferOf "Please use 'fromBytesWith' instead" #-}
410{-# DEPRECATED fromBytesWithBufferOf "Please use 'fromBytesWith' instead" #-}
407{-# INLINE fromBytesWithBufferOf #-}
411{-# INLINE fromBytesWithBufferOf #-}
@@ -498,7 +502,7 @@ appendChunks = fromChunksMode AppendMode
498{-# INLINE appendWith #-}
502{-# INLINE appendWith #-}
499appendWith :: (MonadIO m, MonadCatch m)
503appendWith :: (MonadIO m, MonadCatch m)
500 => Int -> FilePath -> Stream m Word8 -> m ()
504 => Int -> FilePath -> Stream m Word8 -> m ()
501−appendWith n file xs = appendChunks file $ AS.arraysOf n xs
505+appendWith n file xs = appendChunks file $ S.arraysOf n xs
502
506
503-- | Append a byte stream to a file. Combines the bytes in chunks of size up to
507-- | Append a byte stream to a file. Combines the bytes in chunks of size up to
504-- 'A.defaultChunkSize' before writing. If the file exists then the new data
508-- 'A.defaultChunkSize' before writing. If the file exists then the new data
core/src/Streamly/Internal/FileSystem/Handle.hs+10−6
@@ -124,7 +124,7 @@ import Streamly.Internal.Data.Refold.Type (Refold(..))
124import Streamly.Internal.Data.Unfold.Type (Unfold(..))
124import Streamly.Internal.Data.Unfold.Type (Unfold(..))
125import Streamly.Internal.Data.Array.Type
125import Streamly.Internal.Data.Array.Type
126 (Array(..), writeNUnsafe, unsafeFreezeWithShrink, byteLength)
126 (Array(..), writeNUnsafe, unsafeFreezeWithShrink, byteLength)
127−import Streamly.Internal.Data.Stream.Type (Stream)
127+import Streamly.Internal.Data.Stream.StreamD.Type (Stream)
128import Streamly.Internal.Data.Stream.Chunked (lpackArraysChunksOf)
128import Streamly.Internal.Data.Stream.Chunked (lpackArraysChunksOf)
129-- import Streamly.String (encodeUtf8, decodeUtf8, foldLines)
129-- import Streamly.String (encodeUtf8, decodeUtf8, foldLines)
130import Streamly.Internal.System.IO (defaultChunkSize)
130import Streamly.Internal.System.IO (defaultChunkSize)
@@ -136,7 +136,7 @@ import qualified Streamly.Internal.Data.Stream.Chunked as AS
136import qualified Streamly.Internal.Data.Array.Mut.Type as MArray
136import qualified Streamly.Internal.Data.Array.Mut.Type as MArray
137import qualified Streamly.Internal.Data.Refold.Type as Refold
137import qualified Streamly.Internal.Data.Refold.Type as Refold
138import qualified Streamly.Internal.Data.Fold.Type as FL(refoldMany)
138import qualified Streamly.Internal.Data.Fold.Type as FL(refoldMany)
139−import qualified Streamly.Internal.Data.Stream as S
139+import qualified Streamly.Internal.Data.Stream.StreamD as S
140import qualified Streamly.Internal.Data.Stream.StreamD.Type as D
140import qualified Streamly.Internal.Data.Stream.StreamD.Type as D
141 (Stream(..), Step(..))
141 (Stream(..), Step(..))
142import qualified Streamly.Internal.Data.Unfold as UF
142import qualified Streamly.Internal.Data.Unfold as UF
@@ -228,7 +228,7 @@ _getChunksWith size h = S.fromStreamK go
228--
228--
229{-# INLINE_NORMAL readChunksWith #-}
229{-# INLINE_NORMAL readChunksWith #-}
230readChunksWith :: MonadIO m => Int -> Handle -> Stream m (Array Word8)
230readChunksWith :: MonadIO m => Int -> Handle -> Stream m (Array Word8)
231−readChunksWith size h = S.fromStreamD (D.Stream step ())
231+readChunksWith size h = D.Stream step ()
232 where
232 where
233 {-# INLINE_LATE step #-}
233 {-# INLINE_LATE step #-}
234 step _ _ = do
234 step _ _ = do
@@ -340,6 +340,10 @@ readerWith = UF.many A.reader chunkReaderWith
340readWithBufferOf :: MonadIO m => Unfold m (Int, Handle) Word8
340readWithBufferOf :: MonadIO m => Unfold m (Int, Handle) Word8
341readWithBufferOf = readerWith
341readWithBufferOf = readerWith
342
342
343+{-# INLINE concatChunks #-}
344+concatChunks :: (Monad m, Unbox a) => Stream m (Array a) -> Stream m a
345+concatChunks = S.unfoldMany A.reader
346+
343-- | @readWith bufsize handle@ reads a byte stream from a file
347-- | @readWith bufsize handle@ reads a byte stream from a file
344-- handle, reads are performed in chunks of up to @bufsize@.
348-- handle, reads are performed in chunks of up to @bufsize@.
345--
349--
@@ -348,7 +352,7 @@ readWithBufferOf = readerWith
348-- /Pre-release/
352-- /Pre-release/
349{-# INLINE readWith #-}
353{-# INLINE readWith #-}
350readWith :: MonadIO m => Int -> Handle -> Stream m Word8
354readWith :: MonadIO m => Int -> Handle -> Stream m Word8
351−readWith size h = AS.concat $ readChunksWith size h
355+readWith size h = concatChunks $ readChunksWith size h
352
356
353-- | Unfolds a file handle into a byte stream. IO requests to the device are
357-- | Unfolds a file handle into a byte stream. IO requests to the device are
354-- performed in sizes of
358-- performed in sizes of
@@ -367,7 +371,7 @@ reader = UF.many A.reader chunkReader
367-- /Pre-release/
371-- /Pre-release/
368{-# INLINE read #-}
372{-# INLINE read #-}
369read :: MonadIO m => Handle -> Stream m Word8
373read :: MonadIO m => Handle -> Stream m Word8
370−read = AS.concat . readChunks
374+read = concatChunks . readChunks
371
375
372-------------------------------------------------------------------------------
376-------------------------------------------------------------------------------
373-- Writing
377-- Writing
@@ -429,7 +433,7 @@ putChunksWith n h xs = putChunks h $ AS.compact n xs
429--
433--
430{-# INLINE putBytesWith #-}
434{-# INLINE putBytesWith #-}
431putBytesWith :: MonadIO m => Int -> Handle -> Stream m Word8 -> m ()
435putBytesWith :: MonadIO m => Int -> Handle -> Stream m Word8 -> m ()
432−putBytesWith n h m = putChunks h $ S.arraysOf n m
436+putBytesWith n h m = putChunks h $ A.arraysOf n m
433
437
434-- putBytesWith n h m = putChunks h $ AS.arraysOf n m
438-- putBytesWith n h m = putChunks h $ AS.arraysOf n m
435
439
core/src/Streamly/Internal/Serialize/ToBytes.hs+17−17
@@ -44,10 +44,10 @@ where
44import Data.Bits (shiftR)
44import Data.Bits (shiftR)
45import Data.Word (Word8, Word16, Word32, Word64)
45import Data.Word (Word8, Word16, Word32, Word64)
46import GHC.Float (castDoubleToWord64, castFloatToWord32)
46import GHC.Float (castDoubleToWord64, castFloatToWord32)
47−import Streamly.Internal.Data.Stream (Stream, fromStreamD)
47+import Streamly.Internal.Data.Stream.StreamD (Stream)
48import Streamly.Internal.Data.Stream.StreamD (Step(..))
48import Streamly.Internal.Data.Stream.StreamD (Step(..))
49
49
50−import qualified Streamly.Data.Stream as Stream
50+import qualified Streamly.Internal.Data.Stream.StreamD as Stream
51import qualified Streamly.Internal.Data.Stream.StreamD as D
51import qualified Streamly.Internal.Data.Stream.StreamD as D
52
52
53import Data.Int (Int8, Int16, Int32, Int64)
53import Data.Int (Int8, Int16, Int32, Int64)
@@ -63,7 +63,7 @@ import Data.Int (Int8, Int16, Int32, Int64)
63-- /Pre-release/
63-- /Pre-release/
64--
64--
65{-# INLINE unit #-}
65{-# INLINE unit #-}
66−unit :: Stream m Word8
66+unit :: Applicative m => Stream m Word8
67unit = Stream.fromPure 0
67unit = Stream.fromPure 0
68
68
69{-# INLINE boolToWord8 #-}
69{-# INLINE boolToWord8 #-}
@@ -81,7 +81,7 @@ boolToWord8 True = 1
81-- /Pre-release/
81-- /Pre-release/
82--
82--
83{-# INLINE bool #-}
83{-# INLINE bool #-}
84−bool :: Bool -> Stream m Word8
84+bool :: Applicative m => Bool -> Stream m Word8
85bool = Stream.fromPure . boolToWord8
85bool = Stream.fromPure . boolToWord8
86
86
87{-# INLINE orderingToWord8 #-}
87{-# INLINE orderingToWord8 #-}
@@ -101,7 +101,7 @@ orderingToWord8 GT = 2
101-- /Pre-release/
101-- /Pre-release/
102--
102--
103{-# INLINE ordering #-}
103{-# INLINE ordering #-}
104−ordering :: Ordering -> Stream m Word8
104+ordering :: Applicative m => Ordering -> Stream m Word8
105ordering = Stream.fromPure . orderingToWord8
105ordering = Stream.fromPure . orderingToWord8
106
106
107-- | Stream a 'Word8'.
107-- | Stream a 'Word8'.
@@ -109,7 +109,7 @@ ordering = Stream.fromPure . orderingToWord8
109-- /Pre-release/
109-- /Pre-release/
110--
110--
111{-# INLINE word8 #-}
111{-# INLINE word8 #-}
112−word8 :: Word8 -> Stream m Word8
112+word8 :: Applicative m => Word8 -> Stream m Word8
113word8 = Stream.fromPure
113word8 = Stream.fromPure
114
114
115data W16State = W16B1 | W16B2 | W16Done
115data W16State = W16B1 | W16B2 | W16Done
@@ -131,7 +131,7 @@ word16beD w = D.Stream step W16B1
131--
131--
132{-# INLINE word16be #-}
132{-# INLINE word16be #-}
133word16be :: Monad m => Word16 -> Stream m Word8
133word16be :: Monad m => Word16 -> Stream m Word8
134−word16be = fromStreamD . word16beD
134+word16be = word16beD
135
135
136-- | Little endian (LSB first) Word16
136-- | Little endian (LSB first) Word16
137{-# INLINE word16leD #-}
137{-# INLINE word16leD #-}
@@ -151,7 +151,7 @@ word16leD w = D.Stream step W16B1
151--
151--
152{-# INLINE word16le #-}
152{-# INLINE word16le #-}
153word16le :: Monad m => Word16 -> Stream m Word8
153word16le :: Monad m => Word16 -> Stream m Word8
154−word16le = fromStreamD . word16leD
154+word16le = word16leD
155
155
156data W32State = W32B1 | W32B2 | W32B3 | W32B4 | W32Done
156data W32State = W32B1 | W32B2 | W32B3 | W32B4 | W32Done
157
157
@@ -177,7 +177,7 @@ word32beD w = D.Stream step W32B1
177--
177--
178{-# INLINE word32be #-}
178{-# INLINE word32be #-}
179word32be :: Monad m => Word32 -> Stream m Word8
179word32be :: Monad m => Word32 -> Stream m Word8
180−word32be = fromStreamD . word32beD
180+word32be = word32beD
181
181
182-- | Little endian (LSB first) Word32
182-- | Little endian (LSB first) Word32
183{-# INLINE word32leD #-}
183{-# INLINE word32leD #-}
@@ -201,7 +201,7 @@ word32leD w = D.Stream step W32B1
201--
201--
202{-# INLINE word32le #-}
202{-# INLINE word32le #-}
203word32le :: Monad m => Word32 -> Stream m Word8
203word32le :: Monad m => Word32 -> Stream m Word8
204−word32le = fromStreamD . word32leD
204+word32le = word32leD
205
205
206data W64State =
206data W64State =
207 W64B1 | W64B2 | W64B3 | W64B4 | W64B5 | W64B6 | W64B7 | W64B8 | W64Done
207 W64B1 | W64B2 | W64B3 | W64B4 | W64B5 | W64B6 | W64B7 | W64B8 | W64Done
@@ -232,7 +232,7 @@ word64beD w = D.Stream step W64B1
232--
232--
233{-# INLINE word64be #-}
233{-# INLINE word64be #-}
234word64be :: Monad m => Word64 -> Stream m Word8
234word64be :: Monad m => Word64 -> Stream m Word8
235−word64be = fromStreamD . word64beD
235+word64be = word64beD
236
236
237-- | Little endian (LSB first) Word64
237-- | Little endian (LSB first) Word64
238{-# INLINE word64leD #-}
238{-# INLINE word64leD #-}
@@ -260,10 +260,10 @@ word64leD w = D.Stream step W64B1
260--
260--
261{-# INLINE word64le #-}
261{-# INLINE word64le #-}
262word64le :: Monad m => Word64 -> Stream m Word8
262word64le :: Monad m => Word64 -> Stream m Word8
263−word64le = fromStreamD . word64leD
263+word64le = word64leD
264
264
265{-# INLINE int8 #-}
265{-# INLINE int8 #-}
266−int8 :: Int8 -> Stream m Word8
266+int8 :: Applicative m => Int8 -> Stream m Word8
267int8 i = word8 (fromIntegral i :: Word8)
267int8 i = word8 (fromIntegral i :: Word8)
268
268
269-- | Stream a 'Int16' as two bytes, the first byte is the MSB of the Int16
269-- | Stream a 'Int16' as two bytes, the first byte is the MSB of the Int16
@@ -318,22 +318,22 @@ int64le i = word64le (fromIntegral i :: Word64)
318-- | Big endian (MSB first) Float
318-- | Big endian (MSB first) Float
319{-# INLINE float32be #-}
319{-# INLINE float32be #-}
320float32be :: Monad m => Float -> Stream m Word8
320float32be :: Monad m => Float -> Stream m Word8
321−float32be = fromStreamD . word32beD . castFloatToWord32
321+float32be = word32beD . castFloatToWord32
322
322
323-- | Little endian (LSB first) Float
323-- | Little endian (LSB first) Float
324{-# INLINE float32le #-}
324{-# INLINE float32le #-}
325float32le :: Monad m => Float -> Stream m Word8
325float32le :: Monad m => Float -> Stream m Word8
326−float32le = fromStreamD . word32leD . castFloatToWord32
326+float32le = word32leD . castFloatToWord32
327
327
328-- | Big endian (MSB first) Double
328-- | Big endian (MSB first) Double
329{-# INLINE double64be #-}
329{-# INLINE double64be #-}
330double64be :: Monad m => Double -> Stream m Word8
330double64be :: Monad m => Double -> Stream m Word8
331−double64be = fromStreamD . word64beD . castDoubleToWord64
331+double64be = word64beD . castDoubleToWord64
332
332
333-- | Little endian (LSB first) Double
333-- | Little endian (LSB first) Double
334{-# INLINE double64le #-}
334{-# INLINE double64le #-}
335double64le :: Monad m => Double -> Stream m Word8
335double64le :: Monad m => Double -> Stream m Word8
336−double64le = fromStreamD . word64leD . castDoubleToWord64
336+double64le = word64leD . castDoubleToWord64
337
337
338-------------------------------------------------------------------------------
338-------------------------------------------------------------------------------
339-- Host byte order
339-- Host byte order
core/src/Streamly/Internal/Unicode/Stream.hs+14−17
@@ -105,7 +105,7 @@ import System.IO.Unsafe (unsafePerformIO)
105import Streamly.Internal.Data.Array.Type (Array(..))
105import Streamly.Internal.Data.Array.Type (Array(..))
106import Streamly.Internal.Data.Array.Mut.Type (MutableByteArray)
106import Streamly.Internal.Data.Array.Mut.Type (MutableByteArray)
107import Streamly.Internal.Data.Fold (Fold)
107import Streamly.Internal.Data.Fold (Fold)
108−import Streamly.Internal.Data.Stream (Stream, fromStreamD, toStreamD)
108+import Streamly.Internal.Data.Stream.StreamD (Stream)
109import Streamly.Internal.Data.Stream.StreamD (Step (..))
109import Streamly.Internal.Data.Stream.StreamD (Step (..))
110import Streamly.Internal.Data.SVar.Type (adaptState)
110import Streamly.Internal.Data.SVar.Type (adaptState)
111import Streamly.Internal.Data.Tuple.Strict (Tuple'(..))
111import Streamly.Internal.Data.Tuple.Strict (Tuple'(..))
@@ -118,7 +118,7 @@ import qualified Streamly.Data.Unfold as Unfold
118import qualified Streamly.Internal.Data.Array.Type as Array
118import qualified Streamly.Internal.Data.Array.Type as Array
119import qualified Streamly.Internal.Data.Parser as Parser (Parser)
119import qualified Streamly.Internal.Data.Parser as Parser (Parser)
120import qualified Streamly.Internal.Data.Parser.ParserD as ParserD
120import qualified Streamly.Internal.Data.Parser.ParserD as ParserD
121−import qualified Streamly.Internal.Data.Stream as Stream
121+import qualified Streamly.Internal.Data.Stream.StreamD as Stream
122import qualified Streamly.Internal.Data.Stream.StreamD as D
122import qualified Streamly.Internal.Data.Stream.StreamD as D
123
123
124import Prelude hiding (lines, words, unlines, unwords)
124import Prelude hiding (lines, words, unlines, unwords)
@@ -417,7 +417,7 @@ decodeUtf8EitherD = resumeDecodeUtf8EitherD 0 0
417{-# INLINE decodeUtf8Either #-}
417{-# INLINE decodeUtf8Either #-}
418decodeUtf8Either :: Monad m
418decodeUtf8Either :: Monad m
419 => Stream m Word8 -> Stream m (Either DecodeError Char)
419 => Stream m Word8 -> Stream m (Either DecodeError Char)
420−decodeUtf8Either = fromStreamD . decodeUtf8EitherD . toStreamD
420+decodeUtf8Either = decodeUtf8EitherD
421
421
422-- |
422-- |
423--
423--
@@ -429,8 +429,7 @@ resumeDecodeUtf8Either
429 -> CodePoint
429 -> CodePoint
430 -> Stream m Word8
430 -> Stream m Word8
431 -> Stream m (Either DecodeError Char)
431 -> Stream m (Either DecodeError Char)
432−resumeDecodeUtf8Either st cp =
432+resumeDecodeUtf8Either = resumeDecodeUtf8EitherD
433− fromStreamD . resumeDecodeUtf8EitherD st cp . toStreamD
434
433
435-------------------------------------------------------------------------------
434-------------------------------------------------------------------------------
436-- One shot decoding
435-- One shot decoding
@@ -646,7 +645,7 @@ decodeUtf8D = decodeUtf8WithD TransliterateCodingFailure
646--
645--
647{-# INLINE decodeUtf8 #-}
646{-# INLINE decodeUtf8 #-}
648decodeUtf8 :: Monad m => Stream m Word8 -> Stream m Char
647decodeUtf8 :: Monad m => Stream m Word8 -> Stream m Char
649−decodeUtf8 = fromStreamD . decodeUtf8D . toStreamD
648+decodeUtf8 = decodeUtf8D
650
649
651{-# INLINE decodeUtf8D' #-}
650{-# INLINE decodeUtf8D' #-}
652decodeUtf8D' :: Monad m => D.Stream m Word8 -> D.Stream m Char
651decodeUtf8D' :: Monad m => D.Stream m Word8 -> D.Stream m Char
@@ -657,7 +656,7 @@ decodeUtf8D' = decodeUtf8WithD ErrorOnCodingFailure
657--
656--
658{-# INLINE decodeUtf8' #-}
657{-# INLINE decodeUtf8' #-}
659decodeUtf8' :: Monad m => Stream m Word8 -> Stream m Char
658decodeUtf8' :: Monad m => Stream m Word8 -> Stream m Char
660−decodeUtf8' = fromStreamD . decodeUtf8D' . toStreamD
659+decodeUtf8' = decodeUtf8D'
661
660
662{-# INLINE decodeUtf8D_ #-}
661{-# INLINE decodeUtf8D_ #-}
663decodeUtf8D_ :: Monad m => D.Stream m Word8 -> D.Stream m Char
662decodeUtf8D_ :: Monad m => D.Stream m Word8 -> D.Stream m Char
@@ -668,7 +667,7 @@ decodeUtf8D_ = decodeUtf8WithD DropOnCodingFailure
668--
667--
669{-# INLINE decodeUtf8_ #-}
668{-# INLINE decodeUtf8_ #-}
670decodeUtf8_ :: Monad m => Stream m Word8 -> Stream m Char
669decodeUtf8_ :: Monad m => Stream m Word8 -> Stream m Char
671−decodeUtf8_ = fromStreamD . decodeUtf8D_ . toStreamD
670+decodeUtf8_ = decodeUtf8D_
672
671
673-- | Same as 'decodeUtf8'
672-- | Same as 'decodeUtf8'
674--
673--
@@ -817,8 +816,7 @@ decodeUtf8ArraysD = decodeUtf8ArraysWithD TransliterateCodingFailure
817-- /Pre-release/
816-- /Pre-release/
818{-# INLINE decodeUtf8Arrays #-}
817{-# INLINE decodeUtf8Arrays #-}
819decodeUtf8Arrays :: MonadIO m => Stream m (Array Word8) -> Stream m Char
818decodeUtf8Arrays :: MonadIO m => Stream m (Array Word8) -> Stream m Char
820−decodeUtf8Arrays =
819+decodeUtf8Arrays = decodeUtf8ArraysD
821− fromStreamD . decodeUtf8ArraysD . toStreamD
822
820
823{-# INLINE decodeUtf8ArraysD' #-}
821{-# INLINE decodeUtf8ArraysD' #-}
824decodeUtf8ArraysD' ::
822decodeUtf8ArraysD' ::
@@ -832,7 +830,7 @@ decodeUtf8ArraysD' = decodeUtf8ArraysWithD ErrorOnCodingFailure
832-- /Pre-release/
830-- /Pre-release/
833{-# INLINE decodeUtf8Arrays' #-}
831{-# INLINE decodeUtf8Arrays' #-}
834decodeUtf8Arrays' :: MonadIO m => Stream m (Array Word8) -> Stream m Char
832decodeUtf8Arrays' :: MonadIO m => Stream m (Array Word8) -> Stream m Char
835−decodeUtf8Arrays' = fromStreamD . decodeUtf8ArraysD' . toStreamD
833+decodeUtf8Arrays' = decodeUtf8ArraysD'
836
834
837{-# INLINE decodeUtf8ArraysD_ #-}
835{-# INLINE decodeUtf8ArraysD_ #-}
838decodeUtf8ArraysD_ ::
836decodeUtf8ArraysD_ ::
@@ -847,8 +845,7 @@ decodeUtf8ArraysD_ = decodeUtf8ArraysWithD DropOnCodingFailure
847{-# INLINE decodeUtf8Arrays_ #-}
845{-# INLINE decodeUtf8Arrays_ #-}
848decodeUtf8Arrays_ ::
846decodeUtf8Arrays_ ::
849 MonadIO m => Stream m (Array Word8) -> Stream m Char
847 MonadIO m => Stream m (Array Word8) -> Stream m Char
850−decodeUtf8Arrays_ =
848+decodeUtf8Arrays_ = decodeUtf8ArraysD_
851− fromStreamD . decodeUtf8ArraysD_ . toStreamD
852
849
853-------------------------------------------------------------------------------
850-------------------------------------------------------------------------------
854-- Encoding Unicode (UTF-8) Characters
851-- Encoding Unicode (UTF-8) Characters
@@ -922,7 +919,7 @@ encodeUtf8D' = D.unfoldMany readCharUtf8'
922--
919--
923{-# INLINE encodeUtf8' #-}
920{-# INLINE encodeUtf8' #-}
924encodeUtf8' :: Monad m => Stream m Char -> Stream m Word8
921encodeUtf8' :: Monad m => Stream m Char -> Stream m Word8
925−encodeUtf8' = fromStreamD . encodeUtf8D' . toStreamD
922+encodeUtf8' = encodeUtf8D'
926
923
927{-# INLINE_NORMAL readCharUtf8 #-}
924{-# INLINE_NORMAL readCharUtf8 #-}
928readCharUtf8 :: Monad m => Unfold m Char Word8
925readCharUtf8 :: Monad m => Unfold m Char Word8
@@ -941,7 +938,7 @@ encodeUtf8D = D.unfoldMany readCharUtf8
941--
938--
942{-# INLINE encodeUtf8 #-}
939{-# INLINE encodeUtf8 #-}
943encodeUtf8 :: Monad m => Stream m Char -> Stream m Word8
940encodeUtf8 :: Monad m => Stream m Char -> Stream m Word8
944−encodeUtf8 = fromStreamD . encodeUtf8D . toStreamD
941+encodeUtf8 = encodeUtf8D
945
942
946{-# INLINE_NORMAL readCharUtf8_ #-}
943{-# INLINE_NORMAL readCharUtf8_ #-}
947readCharUtf8_ :: Monad m => Unfold m Char Word8
944readCharUtf8_ :: Monad m => Unfold m Char Word8
@@ -956,7 +953,7 @@ encodeUtf8D_ = D.unfoldMany readCharUtf8_
956--
953--
957{-# INLINE encodeUtf8_ #-}
954{-# INLINE encodeUtf8_ #-}
958encodeUtf8_ :: Monad m => Stream m Char -> Stream m Word8
955encodeUtf8_ :: Monad m => Stream m Char -> Stream m Word8
959−encodeUtf8_ = fromStreamD . encodeUtf8D_ . toStreamD
956+encodeUtf8_ = encodeUtf8D_
960
957
961-- | Same as 'encodeUtf8'
958-- | Same as 'encodeUtf8'
962--
959--
@@ -1085,7 +1082,7 @@ isSpace c
1085-- /Pre-release/
1082-- /Pre-release/
1086{-# INLINE words #-}
1083{-# INLINE words #-}
1087words :: Monad m => Fold m Char b -> Stream m Char -> Stream m b
1084words :: Monad m => Fold m Char b -> Stream m Char -> Stream m b
1088−words f m = Stream.fromStreamD $ D.wordsBy isSpace f (Stream.toStreamD m)
1085+words f = D.wordsBy isSpace f
1089
1086
1090-- | Unfold a stream to character streams using the supplied 'Unfold'
1087-- | Unfold a stream to character streams using the supplied 'Unfold'
1091-- and concat the results suffixing a newline character @\\n@ to each stream.
1088-- and concat the results suffixing a newline character @\\n@ to each stream.
core/streamly-core.cabal+21−21
@@ -299,8 +299,10 @@ library
299 , Streamly.Internal.Data.Stream.StreamD.Transform
299 , Streamly.Internal.Data.Stream.StreamD.Transform
300 , Streamly.Internal.Data.Stream.StreamD.Exception
300 , Streamly.Internal.Data.Stream.StreamD.Exception
301 , Streamly.Internal.Data.Stream.StreamD.Lift
301 , Streamly.Internal.Data.Stream.StreamD.Lift
302+ , Streamly.Internal.Data.Stream.StreamD.Top
302 , Streamly.Internal.Data.Stream.StreamD
303 , Streamly.Internal.Data.Stream.StreamD
303 , Streamly.Internal.Data.Stream.Common
304 , Streamly.Internal.Data.Stream.Common
305+ , Streamly.Internal.Data.Stream
304
306
305 , Streamly.Internal.Data.Parser.ParserD.Tee
307 , Streamly.Internal.Data.Parser.ParserD.Tee
306 , Streamly.Internal.Data.Parser.ParserD
308 , Streamly.Internal.Data.Parser.ParserD
@@ -317,32 +319,16 @@ library
317 , Streamly.Internal.Data.Parser.Chunked.Type
319 , Streamly.Internal.Data.Parser.Chunked.Type
318 , Streamly.Internal.Data.Parser.Chunked
320 , Streamly.Internal.Data.Parser.Chunked
319 , Streamly.Internal.Data.Pipe
321 , Streamly.Internal.Data.Pipe
320− , Streamly.Internal.Data.Stream.Type
321− , Streamly.Internal.Data.Stream.Eliminate
322− , Streamly.Internal.Data.Stream.Enumerate
323− , Streamly.Internal.Data.Stream.Generate
324− , Streamly.Internal.Data.Stream.Transform
325− , Streamly.Internal.Data.Stream.Bottom
326− , Streamly.Internal.Data.Stream.Exception
327− , Streamly.Internal.Data.Stream.Expand
328− , Streamly.Internal.Data.Stream.Lift
329− , Streamly.Internal.Data.Stream.Reduce
330− , Streamly.Internal.Data.Stream.Top
331
322
332 -- streamly-transformers (non-base)
323 -- streamly-transformers (non-base)
333 , Streamly.Internal.Data.Stream.StreamD.Transformer
324 , Streamly.Internal.Data.Stream.StreamD.Transformer
334 , Streamly.Internal.Data.Stream.StreamK.Transformer
325 , Streamly.Internal.Data.Stream.StreamK.Transformer
335− , Streamly.Internal.Data.Stream.Transformer
336
326
337 -- streamly-containers (non-base)
327 -- streamly-containers (non-base)
338− , Streamly.Internal.Data.Stream.Container
328+ , Streamly.Internal.Data.Stream.StreamD.Container
339 , Streamly.Internal.Data.Fold.Container
329 , Streamly.Internal.Data.Fold.Container
340
330
341− , Streamly.Internal.Data.Stream
342 , Streamly.Internal.Data.Stream.Chunked
331 , Streamly.Internal.Data.Stream.Chunked
343− , Streamly.Internal.Data.Stream.Zip
344− , Streamly.Internal.Data.Stream.Cross
345− , Streamly.Internal.Data.List
346
332
347 -- streamly-core-data-arrays
333 -- streamly-core-data-arrays
348 , Streamly.Internal.Data.Array.Generic
334 , Streamly.Internal.Data.Array.Generic
@@ -405,6 +391,7 @@ library
405 , Streamly.Data.Fold
391 , Streamly.Data.Fold
406 , Streamly.Data.Parser
392 , Streamly.Data.Parser
407 , Streamly.Data.Stream
393 , Streamly.Data.Stream
394+ , Streamly.Data.Stream.StreamK
408 , Streamly.Data.Unfold
395 , Streamly.Data.Unfold
409 , Streamly.FileSystem.Dir
396 , Streamly.FileSystem.Dir
410 , Streamly.FileSystem.File
397 , Streamly.FileSystem.File
@@ -413,12 +400,25 @@ library
413 , Streamly.Unicode.Stream
400 , Streamly.Unicode.Stream
414 , Streamly.Unicode.String
401 , Streamly.Unicode.String
415
402
416− other-modules: Streamly.Data.Stream.Zip
417−
418 if flag(dev)
403 if flag(dev)
419 exposed-modules:
404 exposed-modules:
420− Streamly.Internal.Data.Stream.StreamDK
405+ Streamly.Internal.Data.Stream.StreamK.Alt
421− , Streamly.Internal.Data.Stream.StreamDK.Type
406+ , Streamly.Internal.Data.Stream.Type
407+ , Streamly.Internal.Data.Stream.Eliminate
408+ , Streamly.Internal.Data.Stream.Enumerate
409+ , Streamly.Internal.Data.Stream.Generate
410+ , Streamly.Internal.Data.Stream.Transform
411+ , Streamly.Internal.Data.Stream.Bottom
412+ , Streamly.Internal.Data.Stream.Exception
413+ , Streamly.Internal.Data.Stream.Expand
414+ , Streamly.Internal.Data.Stream.Lift
415+ , Streamly.Internal.Data.Stream.Reduce
416+ , Streamly.Internal.Data.Stream.Transformer
417+ , Streamly.Internal.Data.Stream.StreamDK
418+ , Streamly.Internal.Data.Stream.Zip
419+ , Streamly.Internal.Data.Stream.Cross
420+ , Streamly.Internal.Data.List
421+ , Streamly.Data.Stream.Zip
422
422
423 build-depends:
423 build-depends:
424 -- streamly-base
424 -- streamly-base
hie.yaml+10
@@ -16,6 +16,12 @@ cradle:
16 config:
16 config:
17 cradle:
17 cradle:
18 cabal:
18 cabal:
19+ - path: "./benchmark/Streamly/Benchmark/Data/Array.hs"
20+ component: "bench:Data.Array"
21+ - path: "./benchmark/Streamly/Benchmark/Data/Array/Generic.hs"
22+ component: "bench:Data.Array.Generic"
23+ - path: "./benchmark/Streamly/Benchmark/Data/Array/Mut.hs"
24+ component: "bench:Data.Array.Mut"
19 - path: "./benchmark/Streamly/Benchmark/Data/Array/Stream.hs"
25 - path: "./benchmark/Streamly/Benchmark/Data/Array/Stream.hs"
20 component: "bench:Data.Array.Stream"
26 component: "bench:Data.Array.Stream"
21 - path: "./benchmark/Streamly/Benchmark/Data/Fold.hs"
27 - path: "./benchmark/Streamly/Benchmark/Data/Fold.hs"
@@ -34,12 +40,16 @@ cradle:
34 component: "bench:Data.Stream.ToStreamK"
40 component: "bench:Data.Stream.ToStreamK"
35 - path: "./benchmark/Streamly/Benchmark/Data/Stream/Common.hs"
41 - path: "./benchmark/Streamly/Benchmark/Data/Stream/Common.hs"
36 component: "bench:Data.Stream"
42 component: "bench:Data.Stream"
43+ - path: "./benchmark/Streamly/Benchmark/Data/Stream/Eliminate.hs"
44+ component: "bench:Data.Stream"
37 - path: "./benchmark/Streamly/Benchmark/Data/Stream/Expand.hs"
45 - path: "./benchmark/Streamly/Benchmark/Data/Stream/Expand.hs"
38 component: "bench:Data.Stream"
46 component: "bench:Data.Stream"
39 - path: "./benchmark/Streamly/Benchmark/Data/Stream/Exceptions.hs"
47 - path: "./benchmark/Streamly/Benchmark/Data/Stream/Exceptions.hs"
40 component: "bench:Data.Stream"
48 component: "bench:Data.Stream"
41 - path: "./benchmark/Streamly/Benchmark/Data/Stream/Generate.hs"
49 - path: "./benchmark/Streamly/Benchmark/Data/Stream/Generate.hs"
42 component: "bench:Data.Stream"
50 component: "bench:Data.Stream"
51+ - path: "./benchmark/Streamly/Benchmark/Data/Stream/Lift.hs"
52+ component: "bench:Data.Stream"
43 - path: "./benchmark/Streamly/Benchmark/Data/Stream/Reduce.hs"
53 - path: "./benchmark/Streamly/Benchmark/Data/Stream/Reduce.hs"
44 component: "bench:Data.Stream"
54 component: "bench:Data.Stream"
45 - path: "./benchmark/Streamly/Benchmark/Data/Stream/Transform.hs"
55 - path: "./benchmark/Streamly/Benchmark/Data/Stream/Transform.hs"
src/Streamly/Data/Array/Foreign.hs+3−3
@@ -30,8 +30,8 @@
30-- it to IO monad as follows:
30-- it to IO monad as follows:
31--
31--
32-- >>> import Data.Functor.Identity (Identity, runIdentity)
32-- >>> import Data.Functor.Identity (Identity, runIdentity)
33−-- >>> s = Stream.fromList [1..10] :: Stream Identity Int
33+-- >>> s = Stream.fromList [1..10] :: SerialT Identity Int
34−-- >>> s1 = Stream.hoist (return . runIdentity) s :: Stream IO Int
34+-- >>> s1 = Stream.hoist (return . runIdentity) s :: SerialT IO Int
35-- >>> Stream.fold Array.write s1 :: IO (Array Int)
35-- >>> Stream.fold Array.write s1 :: IO (Array Int)
36-- fromList [1,2,3,4,5,6,7,8,9,10]
36-- fromList [1,2,3,4,5,6,7,8,9,10]
37--
37--
@@ -102,7 +102,7 @@ import Streamly.Internal.Data.Array as A
102-- >>> :set -fno-warn-deprecations
102-- >>> :set -fno-warn-deprecations
103-- >>> :set -XFlexibleContexts
103-- >>> :set -XFlexibleContexts
104-- >>> :set -package streamly
104-- >>> :set -package streamly
105−-- >>> import Streamly.Internal.Data.Stream (Stream)
105+-- >>> import Streamly.Prelude (SerialT)
106-- >>> import Streamly.Data.Array (Array)
106-- >>> import Streamly.Data.Array (Array)
107-- >>> import qualified Streamly.Internal.Data.Stream.IsStream as Stream
107-- >>> import qualified Streamly.Internal.Data.Stream.IsStream as Stream
108-- >>> import qualified Streamly.Data.Array as Array
108-- >>> import qualified Streamly.Data.Array as Array
src/Streamly/Data/Stream/MkType.hs−7
@@ -37,13 +37,6 @@
37-- $(mkZipType "ParZipStream" "parApply" True)
37-- $(mkZipType "ParZipStream" "parApply" True)
38-- :}
38-- :}
39--
39--
40−-- Example, create a monad type with an interleaving cross product bind:
41−--
42−-- >>> :{
43−-- interleaveBind = flip (Stream.concatMapWith Stream.interleave)
44−-- $(mkCrossType "InterleaveStream" "interleaveBind" False)
45−-- :}
46−--
47-- Example, create a monad type with an eager concurrent cross product bind:
40-- Example, create a monad type with an eager concurrent cross product bind:
48--
41--
49-- >>> :{
42-- >>> :{
src/Streamly/Internal/Data/SmallArray.hs+3−4
@@ -56,7 +56,6 @@ import Streamly.Internal.Data.Unfold.Type (Unfold(..))
56import qualified Streamly.Internal.Data.Stream.StreamD as D
56import qualified Streamly.Internal.Data.Stream.StreamD as D
57import qualified Streamly.Internal.Data.Fold.Type as FL
57import qualified Streamly.Internal.Data.Fold.Type as FL
58 (Fold (..), Step (Done, Partial))
58 (Fold (..), Step (Done, Partial))
59−import qualified Streamly.Internal.Data.Stream.Type as Stream
60
59
61import Streamly.Internal.Data.SmallArray.Type
60import Streamly.Internal.Data.SmallArray.Type
62
61
@@ -165,15 +164,15 @@ instance NFData a => NFData (SmallArray a) where
165fromStreamN :: MonadIO m => Int -> Stream m a -> m (SmallArray a)
164fromStreamN :: MonadIO m => Int -> Stream m a -> m (SmallArray a)
166fromStreamN n m = do
165fromStreamN n m = do
167 when (n < 0) $ error "fromStreamN: negative write count specified"
166 when (n < 0) $ error "fromStreamN: negative write count specified"
168− fromStreamDN n $ D.fromStreamK $ Stream.toStreamK m
167+ fromStreamDN n m
169
168
170{-# INLINE_EARLY read #-}
169{-# INLINE_EARLY read #-}
171read :: Monad m => SmallArray a -> Stream m a
170read :: Monad m => SmallArray a -> Stream m a
172−read = Stream.fromStreamK . D.toStreamK . toStreamD
171+read = toStreamD
173
172
174{-# INLINE_EARLY readRev #-}
173{-# INLINE_EARLY readRev #-}
175readRev :: Monad m => SmallArray a -> Stream m a
174readRev :: Monad m => SmallArray a -> Stream m a
176−readRev = Stream.fromStreamK . D.toStreamK . toStreamDRev
175+readRev = toStreamDRev
177
176
178{-# INLINE fold #-}
177{-# INLINE fold #-}
179fold :: Monad m => Fold m a b -> SmallArray a -> m b
178fold :: Monad m => Fold m a b -> SmallArray a -> m b
src/Streamly/Internal/Data/Stream/Ahead.hs+2−1
@@ -1,4 +1,5 @@
1{-# LANGUAGE UndecidableInstances #-}
1{-# LANGUAGE UndecidableInstances #-}
2+{-# OPTIONS_GHC -fno-warn-deprecations #-}
2
3
3-- |
4-- |
4-- Module : Streamly.Internal.Data.Stream.Ahead
5-- Module : Streamly.Internal.Data.Stream.Ahead
@@ -55,7 +56,7 @@ import qualified Streamly.Internal.Data.Stream.StreamK.Type as K
55 , nil, concatMapWith, fromPure, bindWith)
56 , nil, concatMapWith, fromPure, bindWith)
56import qualified Streamly.Internal.Data.Stream.StreamD.Type as D
57import qualified Streamly.Internal.Data.Stream.StreamD.Type as D
57 (mapM, fromStreamK, toStreamK)
58 (mapM, fromStreamK, toStreamK)
58−import qualified Streamly.Internal.Data.Stream as Stream (toStreamK)
59+import qualified Streamly.Internal.Data.Stream.Serial as Stream (toStreamK)
59
60
60import Streamly.Internal.Data.Stream.SVar.Generate
61import Streamly.Internal.Data.Stream.SVar.Generate
61import Streamly.Internal.Data.SVar
62import Streamly.Internal.Data.SVar
src/Streamly/Internal/Data/Stream/Async.hs+2−1
@@ -1,4 +1,5 @@
1{-# LANGUAGE UndecidableInstances #-}
1{-# LANGUAGE UndecidableInstances #-}
2+{-# OPTIONS_GHC -fno-warn-deprecations #-}
2
3
3#include "inline.hs"
4#include "inline.hs"
4
5
@@ -66,7 +67,7 @@ import qualified Streamly.Internal.Data.Stream.StreamK.Type as K
66 , nil, concatMapWith, fromPure, bindWith)
67 , nil, concatMapWith, fromPure, bindWith)
67import qualified Streamly.Internal.Data.Stream.StreamD.Type as D
68import qualified Streamly.Internal.Data.Stream.StreamD.Type as D
68 (Stream(..), Step(..), mapM, toStreamK, fromStreamK)
69 (Stream(..), Step(..), mapM, toStreamK, fromStreamK)
69−import qualified Streamly.Internal.Data.Stream as Stream (toStreamK)
70+import qualified Streamly.Internal.Data.Stream.Serial as Stream (toStreamK)
70
71
71import Streamly.Internal.Data.SVar
72import Streamly.Internal.Data.SVar
72
73
src/Streamly/Internal/Data/Stream/Concurrent.hs+8−11
@@ -110,11 +110,11 @@ import Streamly.Internal.Data.Stream.Channel.Types
110 , concatMapDivK
110 , concatMapDivK
111 )
111 )
112import Streamly.Internal.Data.Stream.Channel.Worker (sendWithDoorBell)
112import Streamly.Internal.Data.Stream.Channel.Worker (sendWithDoorBell)
113−import Streamly.Internal.Data.Stream.Type (Stream)
113+import Streamly.Internal.Data.Stream.StreamD.Type (Stream)
114import Streamly.Internal.Data.Stream.StreamD (Step(..))
114import Streamly.Internal.Data.Stream.StreamD (Step(..))
115
115
116import qualified Streamly.Internal.Data.IORef.Unboxed as Unboxed
116import qualified Streamly.Internal.Data.IORef.Unboxed as Unboxed
117−import qualified Streamly.Internal.Data.Stream as Stream
117+import qualified Streamly.Internal.Data.Stream.StreamD as Stream
118import qualified Streamly.Internal.Data.Stream.StreamD as D
118import qualified Streamly.Internal.Data.Stream.StreamD as D
119import qualified Streamly.Internal.Data.Stream.StreamK as K
119import qualified Streamly.Internal.Data.Stream.StreamK as K
120import qualified Streamly.Internal.Data.Stream.StreamK.Type as K
120import qualified Streamly.Internal.Data.Stream.StreamK.Type as K
@@ -206,10 +206,10 @@ _appendGeneric newChan modifier stream1 stream2 = K.concatEffect action
206 toChannelK chan stream1
206 toChannelK chan stream1
207 FirstStops -> do
207 FirstStops -> do
208 toChannelK chan stream2
208 toChannelK chan stream2
209− toChannelK chan (K.serial stream1 done)
209+ toChannelK chan (K.append stream1 done)
210 AnyStops -> do
210 AnyStops -> do
211− toChannelK chan (K.serial stream2 done)
211+ toChannelK chan (K.append stream2 done)
212− toChannelK chan (K.serial stream1 done)
212+ toChannelK chan (K.append stream1 done)
213 return $ Stream.toStreamK $ fromChannel chan
213 return $ Stream.toStreamK $ fromChannel chan
214
214
215-- | Create a new channel and add both the streams to it for async evaluation.
215-- | Create a new channel and add both the streams to it for async evaluation.
@@ -319,7 +319,7 @@ parConcatMapChanKAny :: MonadAsync m =>
319 Channel m b -> (a -> K.Stream m b) -> K.Stream m a -> K.Stream m b
319 Channel m b -> (a -> K.Stream m b) -> K.Stream m a -> K.Stream m b
320parConcatMapChanKAny chan f stream =
320parConcatMapChanKAny chan f stream =
321 let done = K.nilM (stopChannel chan)
321 let done = K.nilM (stopChannel chan)
322− run q = concatMapDivK q (\x -> K.serial (f x) done)
322+ run q = concatMapDivK q (\x -> K.append (f x) done)
323 in K.concatMapEffect (`run` stream) (mkEnqueue chan run)
323 in K.concatMapEffect (`run` stream) (mkEnqueue chan run)
324
324
325{-# INLINE parConcatMapChanKFirst #-}
325{-# INLINE parConcatMapChanKFirst #-}
@@ -335,7 +335,7 @@ parConcatMapChanKFirst chan f stream =
335 Just (h, t) -> do
335 Just (h, t) -> do
336 q <- mkEnqueue chan run
336 q <- mkEnqueue chan run
337 q t
337 q t
338− return $ K.serial (f h) done
338+ return $ K.append (f h) done
339
339
340{-# INLINE parConcatMapChanKGeneric #-}
340{-# INLINE parConcatMapChanKGeneric #-}
341parConcatMapChanKGeneric :: MonadAsync m =>
341parConcatMapChanKGeneric :: MonadAsync m =>
@@ -771,7 +771,4 @@ tapCount ::
771 -> (Stream m Int -> m b)
771 -> (Stream m Int -> m b)
772 -> Stream m a
772 -> Stream m a
773 -> Stream m a
773 -> Stream m a
774−tapCount predicate f xs =
774+tapCount = tapCountD
775− Stream.fromStreamD
776− $ tapCountD predicate (f . Stream.fromStreamD)
777− $ Stream.toStreamD xs
src/Streamly/Internal/Data/Stream/Concurrent/Channel.hs+4−4
@@ -51,7 +51,7 @@ module Streamly.Internal.Data.Stream.Concurrent.Channel
51where
51where
52
52
53import Streamly.Internal.Control.Concurrent (MonadAsync)
53import Streamly.Internal.Control.Concurrent (MonadAsync)
54−import Streamly.Internal.Data.Stream (Stream, fromStreamK, toStreamK)
54+import Streamly.Internal.Data.Stream.StreamD (Stream)
55import Streamly.Internal.Data.Stream.Concurrent.Channel.Operations
55import Streamly.Internal.Data.Stream.Concurrent.Channel.Operations
56 (fromChannel, fromChannelK, toChannel, toChannelK)
56 (fromChannel, fromChannelK, toChannel, toChannelK)
57
57
@@ -59,7 +59,7 @@ import qualified Streamly.Internal.Data.Stream.Concurrent.Channel.Append
59 as Append
59 as Append
60import qualified Streamly.Internal.Data.Stream.Concurrent.Channel.Interleave
60import qualified Streamly.Internal.Data.Stream.Concurrent.Channel.Interleave
61 as Interleave
61 as Interleave
62−import qualified Streamly.Internal.Data.Stream.StreamK.Type as K
62+import qualified Streamly.Internal.Data.Stream.StreamK as K
63
63
64import Streamly.Internal.Data.Stream.Concurrent.Channel.Type
64import Streamly.Internal.Data.Stream.Concurrent.Channel.Type
65import Streamly.Internal.Data.Stream.Channel.Types
65import Streamly.Internal.Data.Stream.Channel.Types
@@ -102,5 +102,5 @@ withChannel :: MonadAsync m =>
102 -> (Channel m b -> Stream m a -> Stream m b)
102 -> (Channel m b -> Stream m a -> Stream m b)
103 -> Stream m b
103 -> Stream m b
104withChannel modifier input evaluator =
104withChannel modifier input evaluator =
105− let f chan stream = toStreamK $ evaluator chan (fromStreamK stream)
105+ let f chan stream = K.fromStream $ evaluator chan (K.toStream stream)
106− in fromStreamK $ withChannelK modifier (toStreamK input) f
106+ in K.toStream $ withChannelK modifier (K.fromStream input) f
src/Streamly/Internal/Data/Stream/Concurrent/Channel/Operations.hs+2−2
@@ -34,11 +34,11 @@ import Data.IORef (newIORef, readIORef, mkWeakIORef, writeIORef)
34import Data.Maybe (isNothing)
34import Data.Maybe (isNothing)
35import Streamly.Internal.Control.Concurrent
35import Streamly.Internal.Control.Concurrent
36 (MonadAsync, MonadRunInIO, askRunInIO)
36 (MonadAsync, MonadRunInIO, askRunInIO)
37−import Streamly.Internal.Data.Stream.Type (Stream)
37+import Streamly.Internal.Data.Stream.StreamD.Type (Stream)
38import Streamly.Internal.Data.Time.Clock (Clock(Monotonic), getTime)
38import Streamly.Internal.Data.Time.Clock (Clock(Monotonic), getTime)
39import System.Mem (performMajorGC)
39import System.Mem (performMajorGC)
40
40
41−import qualified Streamly.Internal.Data.Stream as Stream
41+import qualified Streamly.Internal.Data.Stream.StreamD as Stream
42import qualified Streamly.Internal.Data.Stream.StreamD.Type as D
42import qualified Streamly.Internal.Data.Stream.StreamD.Type as D
43import qualified Streamly.Internal.Data.Stream.StreamK.Type as K
43import qualified Streamly.Internal.Data.Stream.StreamK.Type as K
44
44
src/Streamly/Internal/Data/Stream/Exception/Lifted.hs+4−6
@@ -35,7 +35,7 @@ import Data.Map.Strict (Map)
35import GHC.Exts (inline)
35import GHC.Exts (inline)
36import Streamly.Internal.Control.Concurrent
36import Streamly.Internal.Control.Concurrent
37 (MonadRunInIO, MonadAsync, withRunInIO)
37 (MonadRunInIO, MonadAsync, withRunInIO)
38−import Streamly.Internal.Data.Stream.Type (Stream, fromStreamD, toStreamD)
38+import Streamly.Internal.Data.Stream.StreamD.Type (Stream)
39import Streamly.Internal.Data.IOFinalizer.Lifted
39import Streamly.Internal.Data.IOFinalizer.Lifted
40 (newIOFinalizer, runIOFinalizer, clearingIOFinalizer)
40 (newIOFinalizer, runIOFinalizer, clearingIOFinalizer)
41import Streamly.Internal.Data.Stream.StreamD (Step(..))
41import Streamly.Internal.Data.Stream.StreamD (Step(..))
@@ -153,8 +153,7 @@ bracket3 :: (MonadAsync m, MonadCatch m)
153 -> (b -> m e)
153 -> (b -> m e)
154 -> (b -> Stream m a)
154 -> (b -> Stream m a)
155 -> Stream m a
155 -> Stream m a
156−bracket3 bef aft gc exc bet = fromStreamD $
156+bracket3 = bracket3D
157− bracket3D bef aft exc gc (toStreamD . bet)
158
157
159-- | Run the alloc action @m b@ with async exceptions disabled but keeping
158-- | Run the alloc action @m b@ with async exceptions disabled but keeping
160-- blocking operations interruptible (see 'Control.Exception.mask'). Use the
159-- blocking operations interruptible (see 'Control.Exception.mask'). Use the
@@ -236,7 +235,7 @@ after ::
236 (MonadIO m, MonadBaseControl IO m)
235 (MonadIO m, MonadBaseControl IO m)
237#endif
236#endif
238 => m b -> Stream m a -> Stream m a
237 => m b -> Stream m a -> Stream m a
239−after action xs = fromStreamD $ afterD action $ toStreamD xs
238+after = afterD
240
239
241data RetryState emap s1 s2
240data RetryState emap s1 s2
242 = RetryWithMap emap s1
241 = RetryWithMap emap s1
@@ -329,5 +328,4 @@ retry :: (MonadCatch m, Exception e, Ord e)
329 -- ^ default handler for those exceptions that are not in the map
328 -- ^ default handler for those exceptions that are not in the map
330 -> Stream m a
329 -> Stream m a
331 -> Stream m a
330 -> Stream m a
332−retry emap handler inp =
331+retry = retryD
333− fromStreamD $ retryD emap (toStreamD . handler) $ toStreamD inp
src/Streamly/Internal/Data/Stream/IsStream.hs+13−9
@@ -1,5 +1,4 @@
1{-# OPTIONS_GHC -Wno-deprecations -Wno-orphans #-}
1{-# OPTIONS_GHC -Wno-deprecations -Wno-orphans #-}
2−{-# LANGUAGE StandaloneDeriving #-}
3
2
4-- |
3-- |
5-- Module : Streamly.Internal.Data.Stream.IsStream
4-- Module : Streamly.Internal.Data.Stream.IsStream
@@ -23,15 +22,13 @@ module Streamly.Internal.Data.Stream.IsStream {-# DEPRECATED "Please use \"Stre
23 , module Streamly.Internal.Data.Stream.IsStream.Exception
22 , module Streamly.Internal.Data.Stream.IsStream.Exception
24 , module Streamly.Internal.Data.Stream.IsStream.Lift
23 , module Streamly.Internal.Data.Stream.IsStream.Lift
25 , module Streamly.Internal.Data.Stream.IsStream.Top
24 , module Streamly.Internal.Data.Stream.IsStream.Top
25+ , fromStream
26+ , toStream
26 )
27 )
27where
28where
28
29
29−import Control.DeepSeq (NFData(..), NFData1(..))
30−import Data.Functor.Identity (Identity(..))
31−import Streamly.Internal.Data.Stream.Zip (ZipStream(..))
32−
33import Streamly.Internal.Data.Stream.IsStream.Top
30import Streamly.Internal.Data.Stream.IsStream.Top
34−import Streamly.Internal.Data.Stream.IsStream.Eliminate
31+import Streamly.Internal.Data.Stream.IsStream.Eliminate hiding (toStream)
35import Streamly.Internal.Data.Stream.IsStream.Exception
32import Streamly.Internal.Data.Stream.IsStream.Exception
36import Streamly.Internal.Data.Stream.IsStream.Generate
33import Streamly.Internal.Data.Stream.IsStream.Generate
37import Streamly.Internal.Data.Stream.IsStream.Lift
34import Streamly.Internal.Data.Stream.IsStream.Lift
@@ -40,7 +37,14 @@ import Streamly.Internal.Data.Stream.IsStream.Reduce
40import Streamly.Internal.Data.Stream.IsStream.Transform
37import Streamly.Internal.Data.Stream.IsStream.Transform
41import Streamly.Internal.Data.Stream.IsStream.Type
38import Streamly.Internal.Data.Stream.IsStream.Type
42 hiding (cmpBy, drain, eqBy, foldl', fold, toList, toStream
39 hiding (cmpBy, drain, eqBy, foldl', fold, toList, toStream
43− , fromEffect, fromPure, repeat)
40+ , fromEffect, fromPure, repeat, fromStream)
41+
42+import qualified Streamly.Internal.Data.Stream.StreamD as D
43+
44+{-# INLINE fromStream #-}
45+fromStream :: (IsStream t, Monad m) => D.Stream m a -> t m a
46+fromStream = fromStreamD
44
47
45−deriving instance NFData a => NFData (ZipStream Identity a)
48+{-# INLINE toStream #-}
46−deriving instance NFData1 (ZipStream Identity)
49+toStream :: (IsStream t, Monad m) => t m a -> D.Stream m a
50+toStream = toStreamD
src/Streamly/Internal/Data/Stream/IsStream/Common.hs+33−9
@@ -24,8 +24,7 @@ module Streamly.Internal.Data.Stream.IsStream.Common {-# DEPRECATED "Please use
24
24
25 -- * Elimination
25 -- * Elimination
26 , foldContinue
26 , foldContinue
27− , Stream.fold
27+ , fold
28− , Stream.foldBreak
29
28
30 -- * Transformation
29 -- * Transformation
31 , map
30 , map
@@ -82,7 +81,6 @@ import Streamly.Internal.Data.Time.Units (AbsTime, RelTime64, addToAbsTime64)
82import Streamly.Internal.System.IO (defaultChunkSize)
81import Streamly.Internal.System.IO (defaultChunkSize)
83import Streamly.Internal.Data.Unboxed (Unbox)
82import Streamly.Internal.Data.Unboxed (Unbox)
84
83
85−import qualified Streamly.Data.Stream as Stream (fold, foldBreak)
86import qualified Streamly.Internal.Data.Array.Type as A
84import qualified Streamly.Internal.Data.Array.Type as A
87import qualified Streamly.Internal.Data.Stream.Async as Async
85import qualified Streamly.Internal.Data.Stream.Async as Async
88import qualified Streamly.Internal.Data.Stream.IsStream.Type as IsStream
86import qualified Streamly.Internal.Data.Stream.IsStream.Type as IsStream
@@ -90,10 +88,10 @@ import qualified Streamly.Internal.Data.Stream.Parallel as Par
90import qualified Streamly.Internal.Data.Stream.StreamK.Type as K
88import qualified Streamly.Internal.Data.Stream.StreamK.Type as K
91 (fromPure, fromEffect, repeatMWith, reverse)
89 (fromPure, fromEffect, repeatMWith, reverse)
92import qualified Streamly.Internal.Data.Stream.StreamD as D
90import qualified Streamly.Internal.Data.Stream.StreamD as D
93− (repeatM, times, foldContinue, map, scanlMAfter', postscanlMAfter'
91+ (repeatM, timesWith, foldAddLazy, map, scanlMAfter', postscanlMAfter'
94 , postscanlM', take, takeWhile, takeEndBy, drop, findIndices
92 , postscanlM', take, takeWhile, takeEndBy, drop, findIndices
95 , fromStreamK, toStreamK, concatMapM, concatMap, foldManyPost, splitOnSeq
93 , fromStreamK, toStreamK, concatMapM, concatMap, foldManyPost, splitOnSeq
96− , zipWithM, zipWith, intersperseM, reverse)
94+ , zipWithM, zipWith, intersperseM, reverse, fold)
97
95
98import Prelude hiding (take, takeWhile, drop, reverse, concatMap, map, zipWith)
96import Prelude hiding (take, takeWhile, drop, reverse, concatMap, map, zipWith)
99
97
@@ -231,7 +229,7 @@ repeatMSerial = fromStreamD . D.repeatM
231--
229--
232{-# INLINE timesWith #-}
230{-# INLINE timesWith #-}
233timesWith :: (IsStream t, MonadAsync m) => Double -> t m (AbsTime, RelTime64)
231timesWith :: (IsStream t, MonadAsync m) => Double -> t m (AbsTime, RelTime64)
234−timesWith g = fromStreamD $ D.times g
232+timesWith g = fromStreamD $ D.timesWith g
235
233
236-- | @absTimesWith g@ returns a stream of absolute timestamps using a clock of
234-- | @absTimesWith g@ returns a stream of absolute timestamps using a clock of
237-- granularity @g@ specified in seconds. A low granularity clock is more
235-- granularity @g@ specified in seconds. A low granularity clock is more
@@ -279,14 +277,40 @@ relTimesWith = fmap snd . timesWith
279-- number of streams to a given fold efficiently with full stream fusion. For
277-- number of streams to a given fold efficiently with full stream fusion. For
280-- example, to fold a list of streams on the same sum fold:
278-- example, to fold a list of streams on the same sum fold:
281--
279--
282−-- >>> concatFold = Prelude.foldl Stream.foldContinue Fold.sum
280+-- > concatFold = Prelude.foldl Stream.foldContinue Fold.sum
283--
281--
284−-- >>> fold f = Fold.extractM . Stream.foldContinue f
282+-- > fold f = Fold.extractM . Stream.foldContinue f
285--
283--
286-- /Internal/
284-- /Internal/
287{-# INLINE foldContinue #-}
285{-# INLINE foldContinue #-}
288foldContinue :: Monad m => Fold m a b -> SerialT m a -> Fold m a b
286foldContinue :: Monad m => Fold m a b -> SerialT m a -> Fold m a b
289−foldContinue f s = D.foldContinue f $ IsStream.toStreamD s
287+foldContinue f s = D.foldAddLazy f $ IsStream.toStreamD s
288+
289+-- | Fold a stream using the supplied left 'Fold' and reducing the resulting
290+-- expression strictly at each step. The behavior is similar to 'foldl''. A
291+-- 'Fold' can terminate early without consuming the full stream. See the
292+-- documentation of individual 'Fold's for termination behavior.
293+--
294+-- >>> Stream.fold Fold.sum (Stream.enumerateFromTo 1 100)
295+-- 5050
296+--
297+-- Folds never fail, therefore, they produce a default value even when no input
298+-- is provided. It means we can always fold an empty stream and get a valid
299+-- result. For example:
300+--
301+-- >>> Stream.fold Fold.sum Stream.nil
302+-- 0
303+--
304+-- However, 'foldMany' on an empty stream results in an empty stream.
305+-- Therefore, @Stream.fold f@ is not the same as @Stream.head . Stream.foldMany
306+-- f@.
307+--
308+-- @fold f = Stream.parse (Parser.fromFold f)@
309+--
310+-- @since 0.7.0
311+{-# INLINE fold #-}
312+fold :: Monad m => Fold m a b -> SerialT m a -> m b
313+fold fl strm = D.fold fl $ IsStream.toStreamD strm
290
314
291------------------------------------------------------------------------------
315------------------------------------------------------------------------------
292-- Transformation
316-- Transformation
src/Streamly/Internal/Data/Stream/IsStream/Eliminate.hs+118−29
@@ -25,16 +25,12 @@ module Streamly.Internal.Data.Stream.IsStream.Eliminate {-# DEPRECATED "Please u
25 -- * Running a 'Fold'
25 -- * Running a 'Fold'
26 -- See "Streamly.Internal.Data.Fold".
26 -- See "Streamly.Internal.Data.Fold".
27 fold
27 fold
28− , foldBreak
29− , foldContinue
30
28
31 -- * Running a 'Parser'
29 -- * Running a 'Parser'
32 -- "Streamly.Internal.Data.Parser".
30 -- "Streamly.Internal.Data.Parser".
33− , Stream.parse
31+ , parse
34− , Stream.parseK
32+ , parseK
35− , Stream.parseD
33+ , parseD
36− , Stream.parseBreak
37− , Stream.parseBreakD
38
34
39 -- * Stream Deconstruction
35 -- * Stream Deconstruction
40 -- | foldr and foldl do not provide the remaining stream. 'uncons' is more
36 -- | foldr and foldl do not provide the remaining stream. 'uncons' is more
@@ -44,8 +40,8 @@ module Streamly.Internal.Data.Stream.IsStream.Eliminate {-# DEPRECATED "Please u
44 , uncons
40 , uncons
45
41
46 -- * Right Folds
42 -- * Right Folds
47− , Stream.foldrM
43+ , foldrM
48− , Stream.foldr
44+ , foldr
49
45
50 -- * Left Folds
46 -- * Left Folds
51 -- Lazy left folds are useful only for reversing the stream
47 -- Lazy left folds are useful only for reversing the stream
@@ -141,7 +137,7 @@ module Streamly.Internal.Data.Stream.IsStream.Eliminate {-# DEPRECATED "Please u
141 -- trimming sequences
137 -- trimming sequences
142 , stripPrefix
138 , stripPrefix
143 -- , stripInfix
139 -- , stripInfix
144− , Stream.stripSuffix
140+ , stripSuffix
145
141
146 -- * Deprecated
142 -- * Deprecated
147 , foldx
143 , foldx
@@ -160,27 +156,29 @@ import Control.Monad.IO.Class (MonadIO(..))
160import Control.Monad.Trans.Class (MonadTrans(..))
156import Control.Monad.Trans.Class (MonadTrans(..))
161import Foreign.Storable (Storable)
157import Foreign.Storable (Storable)
162import Streamly.Internal.Control.Concurrent (MonadAsync)
158import Streamly.Internal.Control.Concurrent (MonadAsync)
159+import Streamly.Internal.Data.Parser (Parser (..))
163import Streamly.Internal.Data.SVar (defState)
160import Streamly.Internal.Data.SVar (defState)
164import Streamly.Internal.Data.Stream.IsStream.Common
161import Streamly.Internal.Data.Stream.IsStream.Common
165− ( fold, foldBreak, foldContinue, drop, findIndices, reverse, splitOnSeq
162+ ( fold, drop, findIndices, reverse, splitOnSeq
166 , take , takeWhile, mkParallel)
163 , take , takeWhile, mkParallel)
167import Streamly.Internal.Data.Stream.IsStream.Type
164import Streamly.Internal.Data.Stream.IsStream.Type
168− (IsStream, toStreamD, fromStreamD, toStreamD)
165+ (IsStream, fromStreamD, toStreamD)
169import Streamly.Internal.Data.Stream.Serial (SerialT)
166import Streamly.Internal.Data.Stream.Serial (SerialT)
170import Streamly.Internal.Data.Unboxed (Unbox)
167import Streamly.Internal.Data.Unboxed (Unbox)
171
168
172−import qualified Streamly.Data.Array as A
169+import qualified Streamly.Internal.Data.Array as A
173−import qualified Streamly.Data.Stream as Stream
170+import qualified Streamly.Internal.Data.Stream.Serial as Stream
174import qualified Streamly.Internal.Data.Fold as FL
171import qualified Streamly.Internal.Data.Fold as FL
172+import qualified Streamly.Internal.Data.Parser.ParserD as PRD
173+import qualified Streamly.Internal.Data.Parser.ParserK.Type as PRK
175import qualified Streamly.Internal.Data.Stream.IsStream.Type as IsStream
174import qualified Streamly.Internal.Data.Stream.IsStream.Type as IsStream
176import qualified Streamly.Internal.Data.Stream.StreamD as D
175import qualified Streamly.Internal.Data.Stream.StreamD as D
177 (foldr1, foldlT, foldlM', mapM_, null, head, headElse, last, elem
176 (foldr1, foldlT, foldlM', mapM_, null, head, headElse, last, elem
178 , notElem, all, any, minimum, minimumBy, maximum, maximumBy, the, lookup
177 , notElem, all, any, minimum, minimumBy, maximum, maximumBy, the, lookup
179− , find, findM, toListRev, isPrefixOf, isSubsequenceOf, stripPrefix, (!!))
178+ , find, findM, toListRev, isPrefixOf, isSubsequenceOf, stripPrefix, (!!)
179+ , fromStreamK, foldrM, parseD)
180import qualified Streamly.Internal.Data.Stream.StreamK.Type as K
180import qualified Streamly.Internal.Data.Stream.StreamK.Type as K
181 (uncons, foldlS, tail, init)
181 (uncons, foldlS, tail, init)
182−import qualified Streamly.Internal.Data.Stream as Stream
183− (foldr, toStreamK, parseK, parseD, parseBreakD, foldrM, stripSuffix)
184import qualified System.IO as IO
182import qualified System.IO as IO
185
183
186import Prelude hiding
184import Prelude hiding
@@ -216,16 +214,6 @@ import Prelude hiding
216-- the stream one element at a time, therefore, does not take adavantage of
214-- the stream one element at a time, therefore, does not take adavantage of
217-- stream fusion.
215-- stream fusion.
218--
216--
219−-- 'foldBreak' is a more general way of consuming a stream piecemeal.
220−--
221−-- >>> :{
222−-- uncons xs = do
223−-- r <- Stream.foldBreak Fold.one xs
224−-- return $ case r of
225−-- (Nothing, _) -> Nothing
226−-- (Just h, t) -> Just (h, Stream.fromSerial t)
227−-- :}
228−--
229-- @since 0.1.0
217-- @since 0.1.0
230{-# INLINE uncons #-}
218{-# INLINE uncons #-}
231uncons :: (IsStream t, Monad m) => SerialT m a -> m (Maybe (a, t m a))
219uncons :: (IsStream t, Monad m) => SerialT m a -> m (Maybe (a, t m a))
@@ -234,6 +222,46 @@ uncons = fmap (fmap (fmap IsStream.fromStream)) . K.uncons . Stream.toStreamK
234------------------------------------------------------------------------------
222------------------------------------------------------------------------------
235-- Right Folds
223-- Right Folds
236------------------------------------------------------------------------------
224------------------------------------------------------------------------------
225+
226+-- | Right associative/lazy pull fold. @foldrM build final stream@ constructs
227+-- an output structure using the step function @build@. @build@ is invoked with
228+-- the next input element and the remaining (lazy) tail of the output
229+-- structure. It builds a lazy output expression using the two. When the "tail
230+-- structure" in the output expression is evaluated it calls @build@ again thus
231+-- lazily consuming the input @stream@ until either the output expression built
232+-- by @build@ is free of the "tail" or the input is exhausted in which case
233+-- @final@ is used as the terminating case for the output structure. For more
234+-- details see the description in the previous section.
235+--
236+-- Example, determine if any element is 'odd' in a stream:
237+--
238+-- >>> Stream.foldrM (\x xs -> if odd x then return True else xs) (return False) $ Stream.fromList (2:4:5:undefined)
239+-- True
240+--
241+-- /Since: 0.7.0 (signature changed)/
242+--
243+-- /Since: 0.2.0 (signature changed)/
244+--
245+-- /Since: 0.1.0/
246+{-# INLINE foldrM #-}
247+foldrM :: Monad m => (a -> m b -> m b) -> m b -> SerialT m a -> m b
248+foldrM step acc (Stream.SerialT m) = D.foldrM step acc $ D.fromStreamK m
249+
250+-- | Right fold, lazy for lazy monads and pure streams, and strict for strict
251+-- monads.
252+--
253+-- Please avoid using this routine in strict monads like IO unless you need a
254+-- strict right fold. This is provided only for use in lazy monads (e.g.
255+-- Identity) or pure streams. Note that with this signature it is not possible
256+-- to implement a lazy foldr when the monad @m@ is strict. In that case it
257+-- would be strict in its accumulator and therefore would necessarily consume
258+-- all its input.
259+--
260+-- @since 0.1.0
261+{-# INLINE foldr #-}
262+foldr :: Monad m => (a -> b -> b) -> b -> SerialT m a -> m b
263+foldr f z = foldrM (\a b -> f a <$> b) (return z)
264+
237-- XXX This seems to be of limited use as it cannot be used to construct
265-- XXX This seems to be of limited use as it cannot be used to construct
238-- recursive structures and for reduction foldl1' is better.
266-- recursive structures and for reduction foldl1' is better.
239--
267--
@@ -336,6 +364,48 @@ foldlM' step begin = D.foldlM' step begin . IsStream.toStreamD
336runSink :: Monad m => Sink m a -> SerialT m a -> m ()
364runSink :: Monad m => Sink m a -> SerialT m a -> m ()
337runSink = fold . toFold
365runSink = fold . toFold
338-}
366-}
367+
368+------------------------------------------------------------------------------
369+-- Running a Parser
370+------------------------------------------------------------------------------
371+
372+-- | Parse a stream using the supplied ParserD 'PRD.Parser'.
373+--
374+-- /Internal/
375+--
376+{-# INLINE_NORMAL parseD #-}
377+parseD :: Monad m => PRD.Parser a m b -> SerialT m a -> m (Either PRD.ParseError b)
378+parseD p = D.parseD p . toStreamD
379+
380+-- | Parse a stream using the supplied ParserK 'PRK.Parser'.
381+--
382+-- /Internal/
383+{-# INLINE parseK #-}
384+parseK :: Monad m => PRK.Parser a m b -> SerialT m a -> m (Either PRD.ParseError b)
385+parseK = parse
386+
387+-- | Parse a stream using the supplied 'Parser'.
388+--
389+-- Unlike folds, parsers may not always result in a valid output, they may
390+-- result in an error. For example:
391+--
392+-- >>> Stream.parse (Parser.takeEQ 1 Fold.drain) Stream.nil
393+-- Left (ParseError "takeEQ: Expecting exactly 1 elements, input terminated on 0")
394+--
395+-- Note:
396+--
397+-- @
398+-- fold f = Stream.parse (Parser.fromFold f)
399+-- @
400+--
401+-- @parse p@ is not the same as @head . parseMany p@ on an empty stream.
402+--
403+-- /Pre-release/
404+--
405+{-# INLINE [3] parse #-}
406+parse :: Monad m => Parser a m b -> SerialT m a -> m (Either PRD.ParseError b)
407+parse = parseD . PRD.fromParserK
408+
339------------------------------------------------------------------------------
409------------------------------------------------------------------------------
340-- Specific Fold Functions
410-- Specific Fold Functions
341------------------------------------------------------------------------------
411------------------------------------------------------------------------------
@@ -563,7 +633,7 @@ product = foldl' (*) 1
563-- /Pre-release/
633-- /Pre-release/
564{-# INLINE mconcat #-}
634{-# INLINE mconcat #-}
565mconcat :: (Monad m, Monoid a) => SerialT m a -> m a
635mconcat :: (Monad m, Monoid a) => SerialT m a -> m a
566−mconcat = Stream.foldr mappend mempty
636+mconcat = foldr mappend mempty
567
637
568-- |
638-- |
569-- @
639-- @
@@ -743,7 +813,7 @@ toHandle h = go
743--
813--
744{-# INLINE toStream #-}
814{-# INLINE toStream #-}
745toStream :: Monad m => SerialT m a -> m (SerialT n a)
815toStream :: Monad m => SerialT m a -> m (SerialT n a)
746−toStream = Stream.foldr IsStream.cons IsStream.nil
816+toStream = foldr IsStream.cons IsStream.nil
747
817
748-- | Convert a stream to a pure stream in reverse order.
818-- | Convert a stream to a pure stream in reverse order.
749--
819--
@@ -923,6 +993,25 @@ stripPrefix
923stripPrefix m1 m2 = fmap fromStreamD <$>
993stripPrefix m1 m2 = fmap fromStreamD <$>
924 D.stripPrefix (toStreamD m1) (toStreamD m2)
994 D.stripPrefix (toStreamD m1) (toStreamD m2)
925
995
996+-- | Drops the given suffix from a stream. Returns 'Nothing' if the stream does
997+-- not end with the given suffix. Returns @Just nil@ when the suffix is the
998+-- same as the stream.
999+--
1000+-- It may be more efficient to convert the stream to an Array and use
1001+-- stripSuffix on that especially if the elements have a Storable or Prim
1002+-- instance.
1003+--
1004+-- See also "Streamly.Internal.Data.Stream.IsStream.Nesting.dropSuffix".
1005+--
1006+-- Space: @O(n)@, buffers the entire input stream as well as the suffix
1007+--
1008+-- /Pre-release/
1009+{-# INLINE stripSuffix #-}
1010+stripSuffix
1011+ :: (Monad m, Eq a)
1012+ => SerialT m a -> SerialT m a -> m (Maybe (SerialT m a))
1013+stripSuffix m1 m2 = fmap reverse <$> stripPrefix (reverse m1) (reverse m2)
1014+
926------------------------------------------------------------------------------
1015------------------------------------------------------------------------------
927-- Comparison
1016-- Comparison
928------------------------------------------------------------------------------
1017------------------------------------------------------------------------------
src/Streamly/Internal/Data/Stream/IsStream/Exception.hs+6−6
@@ -34,10 +34,10 @@ import Streamly.Internal.Data.Stream.IsStream.Type
34
34
35import qualified Streamly.Internal.Data.Stream.StreamD.Exception as D
35import qualified Streamly.Internal.Data.Stream.StreamD.Exception as D
36 ( before
36 ( before
37− , after_
37+ , afterUnsafe
38 , onException
38 , onException
39− , bracket_
39+ , bracketUnsafe
40− , finally_
40+ , finallyUnsafe
41 , ghandle
41 , ghandle
42 , handle
42 , handle
43 )
43 )
@@ -86,7 +86,7 @@ before action xs = fromStreamD $ D.before action $ toStreamD xs
86--
86--
87{-# INLINE after_ #-}
87{-# INLINE after_ #-}
88after_ :: (IsStream t, Monad m) => m b -> t m a -> t m a
88after_ :: (IsStream t, Monad m) => m b -> t m a -> t m a
89−after_ action xs = fromStreamD $ D.after_ action $ toStreamD xs
89+after_ action xs = fromStreamD $ D.afterUnsafe action $ toStreamD xs
90
90
91-- | Run the action @m b@ whenever the stream @t m a@ stops normally, or if it
91-- | Run the action @m b@ whenever the stream @t m a@ stops normally, or if it
92-- is garbage collected after a partial lazy evaluation.
92-- is garbage collected after a partial lazy evaluation.
@@ -126,7 +126,7 @@ onException action xs = fromStreamD $ D.onException action $ toStreamD xs
126--
126--
127{-# INLINE finally_ #-}
127{-# INLINE finally_ #-}
128finally_ :: (IsStream t, MonadCatch m) => m b -> t m a -> t m a
128finally_ :: (IsStream t, MonadCatch m) => m b -> t m a -> t m a
129−finally_ action xs = fromStreamD $ D.finally_ action $ toStreamD xs
129+finally_ action xs = fromStreamD $ D.finallyUnsafe action $ toStreamD xs
130
130
131-- | Run the action @m b@ whenever the stream @t m a@ stops normally, aborts
131-- | Run the action @m b@ whenever the stream @t m a@ stops normally, aborts
132-- due to an exception or if it is garbage collected after a partial lazy
132-- due to an exception or if it is garbage collected after a partial lazy
@@ -161,7 +161,7 @@ finally action xs = bracket (return ()) (const action) (const xs)
161bracket_ :: (IsStream t, MonadCatch m)
161bracket_ :: (IsStream t, MonadCatch m)
162 => m b -> (b -> m c) -> (b -> t m a) -> t m a
162 => m b -> (b -> m c) -> (b -> t m a) -> t m a
163bracket_ bef aft bet = fromStreamD $
163bracket_ bef aft bet = fromStreamD $
164− D.bracket_ bef aft (toStreamD . bet)
164+ D.bracketUnsafe bef aft (toStreamD . bet)
165
165
166-- | Run the alloc action @m b@ with async exceptions disabled but keeping
166-- | Run the alloc action @m b@ with async exceptions disabled but keeping
167-- blocking operations interruptible (see 'Control.Exception.mask'). Use the
167-- blocking operations interruptible (see 'Control.Exception.mask'). Use the
src/Streamly/Internal/Data/Stream/IsStream/Expand.hs+12−12
@@ -179,13 +179,13 @@ import qualified Streamly.Internal.Data.Stream.IsStream.Type as IsStream
179import qualified Streamly.Internal.Data.Stream.Parallel as Par
179import qualified Streamly.Internal.Data.Stream.Parallel as Par
180import qualified Streamly.Internal.Data.Stream.Serial as Serial
180import qualified Streamly.Internal.Data.Stream.Serial as Serial
181import qualified Streamly.Internal.Data.Stream.StreamD as D
181import qualified Streamly.Internal.Data.Stream.StreamD as D
182− (append, interleave, interleaveSuffix, interleaveInfix, interleaveMin
182+ (append, interleave, interleaveFstSuffix, interleaveFst, interleaveMin
183− , roundRobin, mergeByM, unfoldMany, unfoldManyInterleave, intersperse
183+ , roundRobin, mergeByM, unfoldMany, unfoldInterleave, intersperse
184− , unfoldManyRoundRobin, interpose, interposeSuffix, gintercalate
184+ , unfoldRoundRobin, interpose, interposeSuffix, gintercalate
185 , gintercalateSuffix, intersperseMSuffix)
185 , gintercalateSuffix, intersperseMSuffix)
186import qualified Streamly.Internal.Data.Stream.StreamK as K (mergeBy, mergeByM)
186import qualified Streamly.Internal.Data.Stream.StreamK as K (mergeBy, mergeByM)
187import qualified Streamly.Internal.Data.Stream.StreamK.Type as K
187import qualified Streamly.Internal.Data.Stream.StreamK.Type as K
188− (interleave, serial, concatPairsWith)
188+ (interleave, append, mergeMapWith)
189import qualified Streamly.Internal.Data.Stream.ZipAsync as ZipAsync
189import qualified Streamly.Internal.Data.Stream.ZipAsync as ZipAsync
190
190
191import Prelude hiding (concat, concatMap, zipWith)
191import Prelude hiding (concat, concatMap, zipWith)
@@ -250,7 +250,7 @@ infixr 6 `serial`
250-- @since 0.8.0
250-- @since 0.8.0
251{-# INLINE serial #-}
251{-# INLINE serial #-}
252serial :: IsStream t => t m a -> t m a -> t m a
252serial :: IsStream t => t m a -> t m a -> t m a
253−serial m1 m2 = fromStream $ K.serial (toStream m1) (toStream m2)
253+serial m1 m2 = fromStream $ K.append (toStream m1) (toStream m2)
254
254
255-------------------------------------------------------------------------------
255-------------------------------------------------------------------------------
256-- Interleaving
256-- Interleaving
@@ -346,7 +346,7 @@ interleave m1 m2 = fromStreamD $ D.interleave (toStreamD m1) (toStreamD m2)
346{-# INLINE interleaveSuffix #-}
346{-# INLINE interleaveSuffix #-}
347interleaveSuffix ::(IsStream t, Monad m) => t m b -> t m b -> t m b
347interleaveSuffix ::(IsStream t, Monad m) => t m b -> t m b -> t m b
348interleaveSuffix m1 m2 =
348interleaveSuffix m1 m2 =
349− fromStreamD $ D.interleaveSuffix (toStreamD m1) (toStreamD m2)
349+ fromStreamD $ D.interleaveFstSuffix (toStreamD m1) (toStreamD m2)
350
350
351-- | Interleaves the outputs of two streams, yielding elements from each stream
351-- | Interleaves the outputs of two streams, yielding elements from each stream
352-- alternately, starting from the first stream and ending at the first stream.
352-- alternately, starting from the first stream and ending at the first stream.
@@ -370,7 +370,7 @@ interleaveSuffix m1 m2 =
370{-# INLINE interleaveInfix #-}
370{-# INLINE interleaveInfix #-}
371interleaveInfix ::(IsStream t, Monad m) => t m b -> t m b -> t m b
371interleaveInfix ::(IsStream t, Monad m) => t m b -> t m b -> t m b
372interleaveInfix m1 m2 =
372interleaveInfix m1 m2 =
373− fromStreamD $ D.interleaveInfix (toStreamD m1) (toStreamD m2)
373+ fromStreamD $ D.interleaveFst (toStreamD m1) (toStreamD m2)
374
374
375-- | Interleaves the outputs of two streams, yielding elements from each stream
375-- | Interleaves the outputs of two streams, yielding elements from each stream
376-- alternately, starting from the first stream. The output stops as soon as any
376-- alternately, starting from the first stream. The output stops as soon as any
@@ -835,7 +835,7 @@ unfoldMany u m = fromStreamD $ D.unfoldMany u (toStreamD m)
835unfoldManyInterleave ::(IsStream t, Monad m)
835unfoldManyInterleave ::(IsStream t, Monad m)
836 => Unfold m a b -> t m a -> t m b
836 => Unfold m a b -> t m a -> t m b
837unfoldManyInterleave u m =
837unfoldManyInterleave u m =
838− fromStreamD $ D.unfoldManyInterleave u (toStreamD m)
838+ fromStreamD $ D.unfoldInterleave u (toStreamD m)
839
839
840-- | Like 'unfoldMany' but executes the streams in the same way as
840-- | Like 'unfoldMany' but executes the streams in the same way as
841-- 'roundrobin'.
841-- 'roundrobin'.
@@ -845,7 +845,7 @@ unfoldManyInterleave u m =
845unfoldManyRoundRobin ::(IsStream t, Monad m)
845unfoldManyRoundRobin ::(IsStream t, Monad m)
846 => Unfold m a b -> t m a -> t m b
846 => Unfold m a b -> t m a -> t m b
847unfoldManyRoundRobin u m =
847unfoldManyRoundRobin u m =
848− fromStreamD $ D.unfoldManyRoundRobin u (toStreamD m)
848+ fromStreamD $ D.unfoldRoundRobin u (toStreamD m)
849
849
850------------------------------------------------------------------------------
850------------------------------------------------------------------------------
851-- Combine N Streams - interpose
851-- Combine N Streams - interpose
@@ -863,7 +863,7 @@ unfoldManyRoundRobin u m =
863interpose :: (IsStream t, Monad m)
863interpose :: (IsStream t, Monad m)
864 => c -> Unfold m b c -> t m b -> t m c
864 => c -> Unfold m b c -> t m b -> t m c
865interpose x unf str =
865interpose x unf str =
866− fromStreamD $ D.interpose (return x) unf (toStreamD str)
866+ fromStreamD $ D.interpose x unf (toStreamD str)
867
867
868-- interposeSuffix x unf str = gintercalateSuffix unf str UF.identity (repeat x)
868-- interposeSuffix x unf str = gintercalateSuffix unf str UF.identity (repeat x)
869--
869--
@@ -877,7 +877,7 @@ interpose x unf str =
877interposeSuffix :: (IsStream t, Monad m)
877interposeSuffix :: (IsStream t, Monad m)
878 => c -> Unfold m b c -> t m b -> t m c
878 => c -> Unfold m b c -> t m b -> t m c
879interposeSuffix x unf str =
879interposeSuffix x unf str =
880− fromStreamD $ D.interposeSuffix (return x) unf (toStreamD str)
880+ fromStreamD $ D.interposeSuffix x unf (toStreamD str)
881
881
882------------------------------------------------------------------------------
882------------------------------------------------------------------------------
883-- Combine N Streams - intercalate
883-- Combine N Streams - intercalate
@@ -1013,7 +1013,7 @@ concatPairsWith :: IsStream t =>
1013 -> t m b
1013 -> t m b
1014concatPairsWith par f m =
1014concatPairsWith par f m =
1015 fromStream
1015 fromStream
1016− $ K.concatPairsWith
1016+ $ K.mergeMapWith
1017 (\s1 s2 -> toStream $ fromStream s1 `par` fromStream s2)
1017 (\s1 s2 -> toStream $ fromStream s1 `par` fromStream s2)
1018 (toStream . f)
1018 (toStream . f)
1019 (toStream m)
1019 (toStream m)
src/Streamly/Internal/Data/Stream/IsStream/Generate.hs+2−3
@@ -102,7 +102,6 @@ import Streamly.Internal.Data.Stream.IsStream.Common
102import Streamly.Internal.Data.Stream.IsStream.Type
102import Streamly.Internal.Data.Stream.IsStream.Type
103 (IsStream (..), fromSerial, consM, fromStreamD)
103 (IsStream (..), fromSerial, consM, fromStreamD)
104import Streamly.Internal.Data.Stream.Serial (SerialT, WSerialT)
104import Streamly.Internal.Data.Stream.Serial (SerialT, WSerialT)
105−import Streamly.Internal.Data.Stream.Zip (ZipSerialM)
106import Streamly.Internal.Data.Time.Units (AbsTime , RelTime64, addToAbsTime64)
105import Streamly.Internal.Data.Time.Units (AbsTime , RelTime64, addToAbsTime64)
107import Streamly.Internal.Data.Unboxed (Unbox)
106import Streamly.Internal.Data.Unboxed (Unbox)
108
107
@@ -118,7 +117,7 @@ import qualified Streamly.Internal.Data.Stream.StreamD as D
118import qualified Streamly.Internal.Data.Stream.StreamK.Type as K
117import qualified Streamly.Internal.Data.Stream.StreamK.Type as K
119 (unfoldr, unfoldrMWith, replicateMWith, fromIndicesMWith, iterateMWith
118 (unfoldr, unfoldrMWith, replicateMWith, fromIndicesMWith, iterateMWith
120 , mfix, fromFoldable, fromFoldableM)
119 , mfix, fromFoldable, fromFoldableM)
121−import qualified Streamly.Internal.Data.Stream.Type as Stream (fromStreamK)
120+import qualified Streamly.Internal.Data.Stream.Serial as Stream (fromStreamK)
122import qualified System.IO as IO
121import qualified System.IO as IO
123
122
124import Prelude hiding (iterate, replicate, repeat)
123import Prelude hiding (iterate, replicate, repeat)
@@ -241,7 +240,7 @@ unfoldrMWSerial f = fromSerial . Serial.unfoldrM f
241{-# RULES "unfoldrM zipSerial" unfoldrM = unfoldrMZipSerial #-}
240{-# RULES "unfoldrM zipSerial" unfoldrM = unfoldrMZipSerial #-}
242{-# INLINE_EARLY unfoldrMZipSerial #-}
241{-# INLINE_EARLY unfoldrMZipSerial #-}
243unfoldrMZipSerial :: MonadAsync m =>
242unfoldrMZipSerial :: MonadAsync m =>
244− (b -> m (Maybe (a, b))) -> b -> ZipSerialM m a
243+ (b -> m (Maybe (a, b))) -> b -> IsStream.ZipSerialM m a
245unfoldrMZipSerial f = fromSerial . Serial.unfoldrM f
244unfoldrMZipSerial f = fromSerial . Serial.unfoldrM f
246
245
247------------------------------------------------------------------------------
246------------------------------------------------------------------------------
src/Streamly/Internal/Data/Stream/IsStream/Lift.hs+3−3
@@ -35,7 +35,7 @@ import Streamly.Internal.Data.Stream.IsStream.Type
35import Streamly.Internal.Data.Stream.Serial (SerialT)
35import Streamly.Internal.Data.Stream.Serial (SerialT)
36
36
37import qualified Streamly.Internal.Data.Stream.StreamD as D
37import qualified Streamly.Internal.Data.Stream.StreamD as D
38− (hoist, liftInner, runReaderT, evalStateT, runStateT)
38+ (morphInner, liftInner, runReaderT, evalStateT, runStateT)
39
39
40------------------------------------------------------------------------------
40------------------------------------------------------------------------------
41-- Generalize the underlying monad
41-- Generalize the underlying monad
@@ -48,7 +48,7 @@ import qualified Streamly.Internal.Data.Stream.StreamD as D
48{-# INLINE hoist #-}
48{-# INLINE hoist #-}
49hoist :: (Monad m, Monad n)
49hoist :: (Monad m, Monad n)
50 => (forall x. m x -> n x) -> SerialT m a -> SerialT n a
50 => (forall x. m x -> n x) -> SerialT m a -> SerialT n a
51−hoist f xs = fromStreamD $ D.hoist f (toStreamD xs)
51+hoist f xs = fromStreamD $ D.morphInner f (toStreamD xs)
52
52
53-- | Generalize the inner monad of the stream from 'Identity' to any monad.
53-- | Generalize the inner monad of the stream from 'Identity' to any monad.
54--
54--
@@ -56,7 +56,7 @@ hoist f xs = fromStreamD $ D.hoist f (toStreamD xs)
56--
56--
57{-# INLINE generally #-}
57{-# INLINE generally #-}
58generally :: (IsStream t, Monad m) => t Identity a -> t m a
58generally :: (IsStream t, Monad m) => t Identity a -> t m a
59−generally xs = fromStreamD $ D.hoist (return . runIdentity) (toStreamD xs)
59+generally xs = fromStreamD $ D.morphInner (return . runIdentity) (toStreamD xs)
60
60
61------------------------------------------------------------------------------
61------------------------------------------------------------------------------
62-- Add and remove a monad transformer
62-- Add and remove a monad transformer
src/Streamly/Internal/Data/Stream/IsStream/Reduce.hs+10−8
@@ -176,13 +176,14 @@ import Streamly.Internal.Data.Stream.IsStream.Common
176 , fromPure)
176 , fromPure)
177import Streamly.Internal.Data.Stream.IsStream.Type
177import Streamly.Internal.Data.Stream.IsStream.Type
178 (IsStream(..), fromStreamD, toStreamD, cons)
178 (IsStream(..), fromStreamD, toStreamD, cons)
179+import Streamly.Internal.Data.Stream.Serial(toStreamK)
179import Streamly.Internal.Data.Time.Units
180import Streamly.Internal.Data.Time.Units
180 ( AbsTime, MilliSecond64(..), addToAbsTime, toRelTime
181 ( AbsTime, MilliSecond64(..), addToAbsTime, toRelTime
181 , toAbsTime)
182 , toAbsTime)
182import Streamly.Internal.Data.Unboxed (Unbox)
183import Streamly.Internal.Data.Unboxed (Unbox)
183
184
184import qualified Data.Heap as H
185import qualified Data.Heap as H
185−import qualified Streamly.Data.Unfold as Unfold
186+import qualified Streamly.Internal.Data.Unfold as Unfold
186import qualified Streamly.Internal.Data.Array.Type as A
187import qualified Streamly.Internal.Data.Array.Type as A
187 (arraysOf, read)
188 (arraysOf, read)
188import qualified Streamly.Internal.Data.Fold as FL
189import qualified Streamly.Internal.Data.Fold as FL
@@ -197,8 +198,8 @@ import qualified Streamly.Internal.Data.Stream.StreamD as D
197 , refoldMany
198 , refoldMany
198 , foldIterateM
199 , foldIterateM
199 , refoldIterateM
200 , refoldIterateM
200− , parseMany
201+ , parseManyD
201− , parseIterate
202+ , parseIterateD
202 , groupsBy
203 , groupsBy
203 , groupsRollingBy
204 , groupsRollingBy
204 , wordsBy
205 , wordsBy
@@ -387,7 +388,7 @@ parseMany
387 -> t m a
388 -> t m a
388 -> t m (Either ParseError b)
389 -> t m (Either ParseError b)
389parseMany p m =
390parseMany p m =
390− fromStreamD $ D.parseMany (PRD.fromParserK p) (toStreamD m)
391+ fromStreamD $ D.parseManyD (PRD.fromParserK p) (toStreamD m)
391
392
392-- | Same as parseMany but for StreamD streams.
393-- | Same as parseMany but for StreamD streams.
393--
394--
@@ -400,7 +401,7 @@ parseManyD
400 -> t m a
401 -> t m a
401 -> t m (Either ParseError b)
402 -> t m (Either ParseError b)
402parseManyD p m =
403parseManyD p m =
403− fromStreamD $ D.parseMany p (toStreamD m)
404+ fromStreamD $ D.parseManyD p (toStreamD m)
404
405
405-- | Apply a stream of parsers to an input stream and emit the results in the
406-- | Apply a stream of parsers to an input stream and emit the results in the
406-- output stream.
407-- output stream.
@@ -455,7 +456,7 @@ parseIterate
455 -> t m a
456 -> t m a
456 -> t m (Either ParseError b)
457 -> t m (Either ParseError b)
457parseIterate f i m = fromStreamD $
458parseIterate f i m = fromStreamD $
458− D.parseIterate (PRD.fromParserK . f) i (toStreamD m)
459+ D.parseIterateD (PRD.fromParserK . f) i (toStreamD m)
459
460
460------------------------------------------------------------------------------
461------------------------------------------------------------------------------
461-- Grouping
462-- Grouping
@@ -846,7 +847,7 @@ splitBySeq
846 :: (IsStream t, MonadAsync m, Storable a, Unbox a, Enum a, Eq a)
847 :: (IsStream t, MonadAsync m, Storable a, Unbox a, Enum a, Eq a)
847 => Array a -> Fold m a b -> t m a -> t m b
848 => Array a -> Fold m a b -> t m a -> t m b
848splitBySeq patt f m =
849splitBySeq patt f m =
849− intersperseM (fold f (A.read patt)) $ splitOnSeq patt f m
850+ intersperseM (fold f (fromStreamD $ A.read patt)) $ splitOnSeq patt f m
850
851
851-- | Like 'splitSuffixBy' but the separator is a sequence of elements, instead
852-- | Like 'splitSuffixBy' but the separator is a sequence of elements, instead
852-- of a predicate for a single element.
853-- of a predicate for a single element.
@@ -1322,7 +1323,8 @@ classifySessionsByGeneric
1322 -> t m (Key f, b) -- ^ session key, fold result
1323 -> t m (Key f, b) -- ^ session key, fold result
1323classifySessionsByGeneric _ tick reset ejectPred tmout
1324classifySessionsByGeneric _ tick reset ejectPred tmout
1324 (Fold step initial extract) input =
1325 (Fold step initial extract) input =
1326+ Expand.unfoldMany
1325− Expand.unfoldMany (Unfold.lmap sessionOutputStream Unfold.fromStream)
1327+ (Unfold.lmap (toStreamK . sessionOutputStream) Unfold.fromStreamK)
1326 $ scanlMAfter' sstep (return szero) (flush extract)
1328 $ scanlMAfter' sstep (return szero) (flush extract)
1327 $ interjectSuffix tick (return Nothing)
1329 $ interjectSuffix tick (return Nothing)
1328 $ map Just input
1330 $ map Just input
src/Streamly/Internal/Data/Stream/IsStream/Top.hs+4−4
@@ -72,8 +72,8 @@ import qualified Data.Map.Strict as Map
72-- import qualified Streamly.Internal.Data.Array.Generic as Array
72-- import qualified Streamly.Internal.Data.Array.Generic as Array
73-- (fromStream, length, read)
73-- (fromStream, length, read)
74-- import qualified Streamly.Data.Array.Mut as MA
74-- import qualified Streamly.Data.Array.Mut as MA
75−import qualified Streamly.Internal.Data.Fold as Fold
75+import qualified Streamly.Internal.Data.Fold as Fold (one, last)
76− (one, last, toStream, toStreamRev)
76+import qualified Streamly.Internal.Data.Fold.Type as Fold
77import qualified Streamly.Internal.Data.Parser as Parser
77import qualified Streamly.Internal.Data.Parser as Parser
78 (groupByRollingEither)
78 (groupByRollingEither)
79-- import qualified Streamly.Internal.Data.Stream.IsStream.Lift as Stream
79-- import qualified Streamly.Internal.Data.Stream.IsStream.Lift as Stream
@@ -247,8 +247,8 @@ sortBy cmp =
247 let p =
247 let p =
248 Parser.groupByRollingEither
248 Parser.groupByRollingEither
249 (\x -> (< GT) . cmp x)
249 (\x -> (< GT) . cmp x)
250− Fold.toStreamRev
250+ (fmap fromStream Fold.toStreamKRev)
251− Fold.toStream
251+ (fmap fromStream Fold.toStreamK)
252 in Stream.concatPairsWith (Stream.mergeBy cmp) id
252 in Stream.concatPairsWith (Stream.mergeBy cmp) id
253 . Stream.rights . Stream.parseMany (fmap (either id id) p)
253 . Stream.rights . Stream.parseMany (fmap (either id id) p)
254
254
src/Streamly/Internal/Data/Stream/IsStream/Transform.hs+4−4
@@ -257,8 +257,8 @@ import qualified Streamly.Internal.Data.Stream.Concurrent as Concur
257import qualified Streamly.Internal.Data.Stream.Parallel as Par
257import qualified Streamly.Internal.Data.Stream.Parallel as Par
258import qualified Streamly.Internal.Data.Stream.Serial as Serial
258import qualified Streamly.Internal.Data.Stream.Serial as Serial
259import qualified Streamly.Internal.Data.Stream.StreamD as D
259import qualified Streamly.Internal.Data.Stream.StreamD as D
260− (transform, foldrT, tap, tapOffsetEvery, mapM, scanOnce
260+ (transform, foldrT, tap, tapOffsetEvery, mapM, scan
261− , scanMany, postscanOnce, scanlx', scanlM', scanl', postscanl', prescanl'
261+ , scanMany, postscan, scanlx', scanlM', scanl', postscanl', prescanl'
262 , prescanlM', scanl1M', scanl1', filter, filterM, uniq, deleteBy, takeWhileM
262 , prescanlM', scanl1M', scanl1', filter, filterM, uniq, deleteBy, takeWhileM
263 , dropWhile, dropWhileM, insertBy, intersperse
263 , dropWhile, dropWhileM, insertBy, intersperse
264 , intersperseM_, intersperseMSuffix, intersperseMSuffix_
264 , intersperseM_, intersperseMSuffix, intersperseMSuffix_
@@ -631,7 +631,7 @@ trace_ eff = fromStreamD . D.mapM (\x -> eff >> return x) . toStreamD
631-- @since 0.7.0
631-- @since 0.7.0
632{-# INLINE scan #-}
632{-# INLINE scan #-}
633scan :: (IsStream t, Monad m) => Fold m a b -> t m a -> t m b
633scan :: (IsStream t, Monad m) => Fold m a b -> t m a -> t m b
634−scan fld m = fromStreamD $ D.scanOnce fld $ toStreamD m
634+scan fld m = fromStreamD $ D.scan fld $ toStreamD m
635
635
636-- | Like 'scan' but restarts scanning afresh when the scanning fold
636-- | Like 'scan' but restarts scanning afresh when the scanning fold
637-- terminates.
637-- terminates.
@@ -659,7 +659,7 @@ scanMany fld m = fromStreamD $ D.scanMany fld $ toStreamD m
659-- @since 0.7.0
659-- @since 0.7.0
660{-# INLINE postscan #-}
660{-# INLINE postscan #-}
661postscan :: (IsStream t, Monad m) => Fold m a b -> t m a -> t m b
661postscan :: (IsStream t, Monad m) => Fold m a b -> t m a -> t m b
662−postscan fld = fromStreamD . D.postscanOnce fld . toStreamD
662+postscan fld = fromStreamD . D.postscan fld . toStreamD
663
663
664------------------------------------------------------------------------------
664------------------------------------------------------------------------------
665-- Scanning - Transformation by Folding
665-- Scanning - Transformation by Folding
src/Streamly/Internal/Data/Stream/IsStream/Type.hs+18−8
@@ -20,6 +20,8 @@ module Streamly.Internal.Data.Stream.IsStream.Type {-# DEPRECATED "Please use \"
20 -- * Type Conversion
20 -- * Type Conversion
21 , fromStreamD
21 , fromStreamD
22 , toStreamD
22 , toStreamD
23+ , toStreamK
24+ , fromStreamK
23 , adapt
25 , adapt
24 , toConsK
26 , toConsK
25
27
@@ -124,9 +126,9 @@ import qualified Streamly.Internal.Data.Stream.StreamD.Type as D
124import qualified Streamly.Internal.Data.Stream.StreamK.Type as K
126import qualified Streamly.Internal.Data.Stream.StreamK.Type as K
125 (Stream(..), cons, fromEffect
127 (Stream(..), cons, fromEffect
126 , nil, fromPure, bindWith, drain
128 , nil, fromPure, bindWith, drain
127− , fromFoldable, consM, nilM, repeat)
129+ , fromFoldable, nilM, repeat)
128−import qualified Streamly.Data.Stream as Stream
130+import qualified Streamly.Internal.Data.Stream.StreamK as StreamK
129−import qualified Streamly.Internal.Data.Stream as Stream
131+import qualified Streamly.Internal.Data.Stream.Serial as Stream
130 (fromStreamK, toStreamK)
132 (fromStreamK, toStreamK)
131import qualified Streamly.Internal.Data.Stream.Zip as Zip
133import qualified Streamly.Internal.Data.Stream.Zip as Zip
132import qualified Streamly.Internal.Data.Stream.ZipAsync as ZipAsync
134import qualified Streamly.Internal.Data.Stream.ZipAsync as ZipAsync
@@ -201,6 +203,14 @@ class
201-- Type adapting combinators
203-- Type adapting combinators
202-------------------------------------------------------------------------------
204-------------------------------------------------------------------------------
203
205
206+{-# INLINE toStreamK #-}
207+toStreamK :: IsStream t => t m a -> StreamK.StreamK m a
208+toStreamK = toStream
209+
210+{-# INLINE fromStreamK #-}
211+fromStreamK :: IsStream t => StreamK.StreamK m a -> t m a
212+fromStreamK = fromStream
213+
204-- XXX Move/reset the State here by reconstructing the stream with cleared
214-- XXX Move/reset the State here by reconstructing the stream with cleared
205-- state. Can we make sure we do not do that when t1 = t2? If we do this then
215-- state. Can we make sure we do not do that when t1 = t2? If we do this then
206-- we do not need to do that explicitly using svarStyle. It would act as
216-- we do not need to do that explicitly using svarStyle. It would act as
@@ -443,7 +453,7 @@ foldStream st yld sng stp m =
443fromSerial :: IsStream t => SerialT m a -> t m a
453fromSerial :: IsStream t => SerialT m a -> t m a
444fromSerial = adapt
454fromSerial = adapt
445
455
446−instance IsStream Stream.Stream where
456+instance IsStream SerialT where
447 toStream = Stream.toStreamK
457 toStream = Stream.toStreamK
448 fromStream = Stream.fromStreamK
458 fromStream = Stream.fromStreamK
449
459
@@ -574,8 +584,8 @@ instance IsStream ParallelT where
574-------------------------------------------------------------------------------
584-------------------------------------------------------------------------------
575
585
576consMZip :: Monad m => m a -> ZipSerialM m a -> ZipSerialM m a
586consMZip :: Monad m => m a -> ZipSerialM m a -> ZipSerialM m a
577−consMZip m (Zip.ZipStream r) =
587+consMZip m (Zip.ZipSerialM r) =
578− Zip.ZipStream $ Stream.fromStreamK $ K.consM m (Stream.toStreamK r)
588+ Zip.ZipSerialM $ StreamK.consM m r
579
589
580-- | Fix the type of a polymorphic stream as 'ZipSerialM'.
590-- | Fix the type of a polymorphic stream as 'ZipSerialM'.
581--
591--
@@ -585,8 +595,8 @@ consMZip m (Zip.ZipStream r) =
585fromZipSerial :: IsStream t => ZipSerialM m a -> t m a
595fromZipSerial :: IsStream t => ZipSerialM m a -> t m a
586fromZipSerial = adapt
596fromZipSerial = adapt
587instance IsStream ZipSerialM where
597instance IsStream ZipSerialM where
588− toStream = Stream.toStreamK . Zip.unZipStream
598+ toStream = Zip.getZipSerialM
589− fromStream = Zip.ZipStream . Stream.fromStreamK
599+ fromStream = Zip.ZipSerialM
590
600
591 {-# INLINE consM #-}
601 {-# INLINE consM #-}
592 {-# SPECIALIZE consM :: IO a -> ZipSerialM IO a -> ZipSerialM IO a #-}
602 {-# SPECIALIZE consM :: IO a -> ZipSerialM IO a -> ZipSerialM IO a #-}
src/Streamly/Internal/Data/Stream/MkType.hs+7−12
@@ -215,6 +215,7 @@ derivOrdIdent _Type =
215 (singleton <$> [t|Ord $(varT _a)|])
215 (singleton <$> [t|Ord $(varT _a)|])
216 (appT (conT _Ord) (foldl1 appT [conT _Type, conT _Identity, varT _a]))
216 (appT (conT _Ord) (foldl1 appT [conT _Type, conT _Identity, varT _a]))
217
217
218+{-
218derivTraversableIdent :: Name -> Q Dec
219derivTraversableIdent :: Name -> Q Dec
219derivTraversableIdent _Type =
220derivTraversableIdent _Type =
220 standaloneDerivD
221 standaloneDerivD
@@ -222,6 +223,7 @@ derivTraversableIdent _Type =
222 (appT
223 (appT
223 (conT _Traversable)
224 (conT _Traversable)
224 (foldl1 appT [conT _Type, conT _Identity]))
225 (foldl1 appT [conT _Type, conT _Identity]))
226+-}
225
227
226showInstance :: Name -> Q Dec
228showInstance :: Name -> Q Dec
227showInstance _Type =
229showInstance _Type =
@@ -503,7 +505,7 @@ flattenDec (ma:mas) = do
503-- >>> putStrLn $ pprint expr
505-- >>> putStrLn $ pprint expr
504-- newtype ZipStream m a
506-- newtype ZipStream m a
505-- = ZipStream (Stream.Stream m a)
507-- = ZipStream (Stream.Stream m a)
506−-- deriving (Semigroup, Monoid, Foldable)
508+-- deriving Foldable
507-- mkZipStream :: Stream.Stream m a -> ZipStream m a
509-- mkZipStream :: Stream.Stream m a -> ZipStream m a
508-- mkZipStream = ZipStream
510-- mkZipStream = ZipStream
509-- unZipStream :: ZipStream m a -> Stream.Stream m a
511-- unZipStream :: ZipStream m a -> Stream.Stream m a
@@ -513,7 +515,6 @@ flattenDec (ma:mas) = do
513-- GHC.Types.Char => IsString (ZipStream Identity a)
515-- GHC.Types.Char => IsString (ZipStream Identity a)
514-- deriving instance GHC.Classes.Eq a => Eq (ZipStream Identity a)
516-- deriving instance GHC.Classes.Eq a => Eq (ZipStream Identity a)
515-- deriving instance GHC.Classes.Ord a => Ord (ZipStream Identity a)
517-- deriving instance GHC.Classes.Ord a => Ord (ZipStream Identity a)
516−-- deriving instance Traversable (ZipStream Identity)
517-- instance Show a => Show (ZipStream Identity a)
518-- instance Show a => Show (ZipStream Identity a)
518-- where {-# INLINE show #-}
519-- where {-# INLINE show #-}
519-- show (ZipStream strm) = show strm
520-- show (ZipStream strm) = show strm
@@ -535,17 +536,14 @@ mkZipType
535 -> Q [Dec]
536 -> Q [Dec]
536mkZipType dtNameStr apOpStr isConcurrent =
537mkZipType dtNameStr apOpStr isConcurrent =
537 flattenDec
538 flattenDec
538− [ typeDec dtNameStr
539+ [ typeDec dtNameStr [_Foldable | not isConcurrent]
539− $ if not isConcurrent
540− then [_Semigroup, _Monoid, _Foldable]
541− else []
542 , sequence
540 , sequence
543 $ if not isConcurrent
541 $ if not isConcurrent
544 then [ derivIsListIdent _Type
542 then [ derivIsListIdent _Type
545 , derivIsStringIdent _Type
543 , derivIsStringIdent _Type
546 , derivEqIdent _Type
544 , derivEqIdent _Type
547 , derivOrdIdent _Type
545 , derivOrdIdent _Type
548− , derivTraversableIdent _Type
546+ -- , derivTraversableIdent _Type
549 , showInstance _Type
547 , showInstance _Type
550 , readInstance _Type
548 , readInstance _Type
551 ]
549 ]
@@ -607,17 +605,14 @@ mkCrossType
607 -> Q [Dec]
605 -> Q [Dec]
608mkCrossType dtNameStr bindOpStr isConcurrent =
606mkCrossType dtNameStr bindOpStr isConcurrent =
609 flattenDec
607 flattenDec
610− [ typeDec dtNameStr
608+ [ typeDec dtNameStr [_Foldable | not isConcurrent]
611− $ if not isConcurrent
612− then [_Semigroup, _Monoid, _Foldable]
613− else []
614 , sequence
609 , sequence
615 $ if not isConcurrent
610 $ if not isConcurrent
616 then [ derivIsListIdent _Type
611 then [ derivIsListIdent _Type
617 , derivIsStringIdent _Type
612 , derivIsStringIdent _Type
618 , derivEqIdent _Type
613 , derivEqIdent _Type
619 , derivOrdIdent _Type
614 , derivOrdIdent _Type
620− , derivTraversableIdent _Type
615+ -- , derivTraversableIdent _Type
621 , showInstance _Type
616 , showInstance _Type
622 , readInstance _Type
617 , readInstance _Type
623 ]
618 ]
src/Streamly/Internal/Data/Stream/Parallel.hs+6−96
@@ -1,4 +1,5 @@
1{-# LANGUAGE UndecidableInstances #-}
1{-# LANGUAGE UndecidableInstances #-}
2+{-# OPTIONS_GHC -fno-warn-deprecations #-}
2
3
3-- |
4-- |
4-- Module : Streamly.Internal.Data.Stream.Parallel
5-- Module : Streamly.Internal.Data.Stream.Parallel
@@ -11,7 +12,7 @@
11--
12--
12-- To run examples in this module:
13-- To run examples in this module:
13--
14--
14−-- >>> import qualified Streamly.Data.Stream as Stream
15+-- >>> import qualified Streamly.Prelude as Stream
15-- >>> import Control.Concurrent (threadDelay)
16-- >>> import Control.Concurrent (threadDelay)
16-- >>> :{
17-- >>> :{
17-- delay n = do
18-- delay n = do
@@ -42,15 +43,10 @@ module Streamly.Internal.Data.Stream.Parallel {-# DEPRECATED "Please use \"Strea
42
43
43 -- * Callbacks
44 -- * Callbacks
44 , newCallbackStream
45 , newCallbackStream
45−
46− -- * Combinators
47− , interjectSuffix
48− , takeInterval
49− , dropInterval
50 )
46 )
51where
47where
52
48
53−import Control.Concurrent (myThreadId, takeMVar, threadDelay)
49+import Control.Concurrent (myThreadId, takeMVar)
54import Control.Monad (when)
50import Control.Monad (when)
55import Control.Monad.Base (MonadBase(..), liftBaseDefault)
51import Control.Monad.Base (MonadBase(..), liftBaseDefault)
56import Control.Monad.Catch (MonadThrow, throwM)
52import Control.Monad.Catch (MonadThrow, throwM)
@@ -61,12 +57,11 @@ import Control.Monad.State.Class (MonadState(..))
61import Control.Monad.Trans.Class (MonadTrans(lift))
57import Control.Monad.Trans.Class (MonadTrans(lift))
62import Data.Functor (void)
58import Data.Functor (void)
63import Data.IORef (readIORef, writeIORef)
59import Data.IORef (readIORef, writeIORef)
64−import Data.Maybe (fromJust, isNothing)
60+import Data.Maybe (fromJust)
65
61
66import Streamly.Data.Fold (Fold)
62import Streamly.Data.Fold (Fold)
67import Streamly.Internal.Control.Concurrent (MonadAsync)
63import Streamly.Internal.Control.Concurrent (MonadAsync)
68import Streamly.Internal.Data.Stream.StreamD.Type (Step(..))
64import Streamly.Internal.Data.Stream.StreamD.Type (Step(..))
69−import Streamly.Internal.Data.Stream.Type (Stream)
70
65
71import qualified Data.Set as Set
66import qualified Data.Set as Set
72import qualified Streamly.Internal.Data.Stream.StreamK.Type as K
67import qualified Streamly.Internal.Data.Stream.StreamK.Type as K
@@ -76,8 +71,7 @@ import qualified Streamly.Internal.Data.Stream.StreamD.Type as D
76 (Stream(..), mapM, toStreamK, fromStreamK)
71 (Stream(..), mapM, toStreamK, fromStreamK)
77import qualified Streamly.Internal.Data.Stream.SVar.Generate as SVar
72import qualified Streamly.Internal.Data.Stream.SVar.Generate as SVar
78import qualified Streamly.Internal.Data.Stream.SVar.Eliminate as SVar
73import qualified Streamly.Internal.Data.Stream.SVar.Eliminate as SVar
79−import qualified Streamly.Internal.Data.Stream as Stream
74+import qualified Streamly.Internal.Data.Stream.Serial as Stream
80− (catMaybes, dropWhile, fromStreamK, repeat, sequence, takeWhile, toStreamK)
81
75
82import Streamly.Internal.Data.SVar
76import Streamly.Internal.Data.SVar
83import Prelude hiding (map)
77import Prelude hiding (map)
@@ -87,7 +81,7 @@ import Prelude hiding (map)
87
81
88--
82--
89-- $setup
83-- $setup
90−-- >>> import qualified Streamly.Data.Stream as Stream
84+-- >>> import qualified Streamly.Prelude as Stream
91-- >>> import Control.Concurrent (threadDelay)
85-- >>> import Control.Concurrent (threadDelay)
92-- >>> :{
86-- >>> :{
93-- delay n = do
87-- delay n = do
@@ -538,87 +532,3 @@ newCallbackStream = do
538 -- XXX we can return an SVar and then the consumer can unfold from the
532 -- XXX we can return an SVar and then the consumer can unfold from the
539 -- SVar?
533 -- SVar?
540 return (callback, D.toStreamK (SVar.fromSVarD sv))
534 return (callback, D.toStreamK (SVar.fromSVarD sv))
541−
542−------------------------------------------------------------------------------
543−-- Combinators
544−------------------------------------------------------------------------------
545−
546−{-# INLINE parallelFst #-}
547−parallelFst :: MonadAsync m => Stream m a -> Stream m a -> Stream m a
548−parallelFst m1 m2 =
549− Stream.fromStreamK
550− $ parallelFstK (Stream.toStreamK m1) (Stream.toStreamK m2)
551−
552−-- | Intersperse a monadic action into the input stream after every @n@
553−-- seconds.
554−--
555−-- >>> import qualified Streamly.Data.Fold as Fold
556−-- >>> import qualified Streamly.Internal.Data.Stream.Parallel as Parallel
557−-- >>> Stream.fold Fold.drain $ Parallel.interjectSuffix 1.05 (putChar ',') $ Stream.mapM (\x -> threadDelay 1000000 >> putChar x) $ Stream.fromList "hello"
558−-- h,e,l,l,o
559−--
560−-- /Pre-release/
561−{-# INLINE interjectSuffix #-}
562−interjectSuffix :: MonadAsync m => Double -> m a -> Stream m a -> Stream m a
563−interjectSuffix n f xs = xs `parallelFst` repeatM timed
564− where timed = liftIO (threadDelay (round $ n * 1000000)) >> f
565− repeatM = Stream.sequence . Stream.repeat
566−
567−-- XXX Notes from D.takeByTime (which was removed)
568−-- XXX using getTime in the loop can be pretty expensive especially for
569−-- computations where iterations are lightweight. We have the following
570−-- options:
571−--
572−-- 1) Run a timeout thread updating a flag asynchronously and check that
573−-- flag here, that way we can have a cheap termination check.
574−--
575−-- 2) Use COARSE clock to get time with lower resolution but more efficiently.
576−--
577−-- 3) Use rdtscp/rdtsc to get time directly from the processor, compute the
578−-- termination value of rdtsc in the beginning and then in each iteration just
579−-- get rdtsc and check if we should terminate.
580−
581−
582−-- | @takeInterval duration@ yields stream elements upto specified time
583−-- @duration@ in seconds. The duration starts when the stream is evaluated for
584−-- the first time, before the first element is yielded. The time duration is
585−-- checked before generating each element, if the duration has expired the
586−-- stream stops.
587−--
588−-- The total time taken in executing the stream is guaranteed to be /at least/
589−-- @duration@, however, because the duration is checked before generating an
590−-- element, the upper bound is indeterminate and depends on the time taken in
591−-- generating and processing the last element.
592−--
593−-- No element is yielded if the duration is zero. At least one element is
594−-- yielded if the duration is non-zero.
595−--
596−-- /Pre-release/
597−--
598−{-# INLINE takeInterval #-}
599−takeInterval :: MonadAsync m => Double -> Stream m a -> Stream m a
600−takeInterval d =
601− Stream.catMaybes
602− . Stream.takeWhile isNothing
603− . interjectSuffix d (return Nothing) . fmap Just
604−
605−-- | @dropInterval duration@ drops stream elements until specified @duration@ in
606−-- seconds has passed. The duration begins when the stream is evaluated for the
607−-- first time. The time duration is checked /after/ generating a stream element,
608−-- the element is yielded if the duration has expired otherwise it is dropped.
609−--
610−-- The time elapsed before starting to generate the first element is /at most/
611−-- @duration@, however, because the duration expiry is checked after the
612−-- element is generated, the lower bound is indeterminate and depends on the
613−-- time taken in generating an element.
614−--
615−-- All elements are yielded if the duration is zero.
616−--
617−-- /Pre-release/
618−--
619−{-# INLINE dropInterval #-}
620−dropInterval :: MonadAsync m => Double -> Stream m a -> Stream m a
621−dropInterval d =
622− Stream.catMaybes
623− . Stream.dropWhile isNothing
624− . interjectSuffix d (return Nothing) . fmap Just
src/Streamly/Internal/Data/Stream/SVar/Eliminate.hs+5−4
@@ -1,3 +1,4 @@
1+{-# OPTIONS_GHC -fno-warn-deprecations #-}
1-- |
2-- |
2-- Module : Streamly.Internal.Data.Stream.SVar.Eliminate
3-- Module : Streamly.Internal.Data.Stream.SVar.Eliminate
3-- Copyright : (c) 2017 Composewell Technologies
4-- Copyright : (c) 2017 Composewell Technologies
@@ -36,14 +37,14 @@ import Streamly.Internal.Control.ForkLifted (doFork)
36import Streamly.Internal.Data.Atomics (atomicModifyIORefCAS_)
37import Streamly.Internal.Data.Atomics (atomicModifyIORefCAS_)
37import Streamly.Internal.Data.Fold.SVar (write, writeLimited)
38import Streamly.Internal.Data.Fold.SVar (write, writeLimited)
38import Streamly.Internal.Data.Fold.Type (Fold(..))
39import Streamly.Internal.Data.Fold.Type (Fold(..))
39−import Streamly.Data.Stream (Stream)
40+import Streamly.Internal.Data.Stream.Serial (SerialT)
40import Streamly.Internal.Data.Time.Clock (Clock(Monotonic), getTime)
41import Streamly.Internal.Data.Time.Clock (Clock(Monotonic), getTime)
41
42
42import qualified Streamly.Internal.Data.Stream.StreamD.Type as D
43import qualified Streamly.Internal.Data.Stream.StreamD.Type as D
43 (Stream(..), Step(..), fold)
44 (Stream(..), Step(..), fold)
44import qualified Streamly.Internal.Data.Stream.StreamK.Type as K
45import qualified Streamly.Internal.Data.Stream.StreamK.Type as K
45 (Stream(..), mkStream, foldStream, foldStreamShared, nilM)
46 (Stream(..), mkStream, foldStream, foldStreamShared, nilM)
46−import qualified Streamly.Internal.Data.Stream.Type as Stream
47+import qualified Streamly.Internal.Data.Stream.Serial as Stream
47 (fromStreamK, toStreamK)
48 (fromStreamK, toStreamK)
48
49
49import Streamly.Internal.Data.SVar
50import Streamly.Internal.Data.SVar
@@ -210,7 +211,7 @@ fromProducer sv = K.mkStream $ \st yld sng stp -> do
210--
211--
211{-# INLINE newFoldSVar #-}
212{-# INLINE newFoldSVar #-}
212newFoldSVar :: MonadAsync m
213newFoldSVar :: MonadAsync m
213− => State K.Stream m a -> (Stream m a -> m b) -> m (SVar K.Stream m a)
214+ => State K.Stream m a -> (SerialT m a -> m b) -> m (SVar K.Stream m a)
214newFoldSVar stt f = do
215newFoldSVar stt f = do
215 -- Buffer size for the SVar is derived from the current state
216 -- Buffer size for the SVar is derived from the current state
216 sv <- newParallelVar StopAny (adaptState stt)
217 sv <- newParallelVar StopAny (adaptState stt)
@@ -372,7 +373,7 @@ pushToFold sv a = do
372--
373--
373{-# INLINE teeToSVar #-}
374{-# INLINE teeToSVar #-}
374teeToSVar :: MonadAsync m =>
375teeToSVar :: MonadAsync m =>
375− SVar K.Stream m a -> Stream m a -> Stream m a
376+ SVar K.Stream m a -> SerialT m a -> SerialT m a
376teeToSVar svr m = Stream.fromStreamK $ K.mkStream $ \st yld sng stp -> do
377teeToSVar svr m = Stream.fromStreamK $ K.mkStream $ \st yld sng stp -> do
377 K.foldStreamShared st yld sng stp (go False $ Stream.toStreamK m)
378 K.foldStreamShared st yld sng stp (go False $ Stream.toStreamK m)
378
379
src/Streamly/Internal/Data/Stream/SVar/Generate.hs+5−4
@@ -1,3 +1,4 @@
1+{-# OPTIONS_GHC -fno-warn-deprecations #-}
1#ifdef __HADDOCK_VERSION__
2#ifdef __HADDOCK_VERSION__
2#undef INSPECTION
3#undef INSPECTION
3#endif
4#endif
@@ -38,7 +39,7 @@ import Control.Monad.IO.Class (MonadIO(liftIO))
38import Data.IORef (newIORef, readIORef, mkWeakIORef, writeIORef)
39import Data.IORef (newIORef, readIORef, mkWeakIORef, writeIORef)
39import Data.Maybe (isNothing)
40import Data.Maybe (isNothing)
40import Streamly.Internal.Control.Concurrent (MonadAsync, askRunInIO)
41import Streamly.Internal.Control.Concurrent (MonadAsync, askRunInIO)
41−import Streamly.Internal.Data.Stream.Type (Stream)
42+import Streamly.Internal.Data.Stream.Serial (SerialT)
42import Streamly.Internal.Data.Time.Clock (Clock(Monotonic), getTime)
43import Streamly.Internal.Data.Time.Clock (Clock(Monotonic), getTime)
43import System.Mem (performMajorGC)
44import System.Mem (performMajorGC)
44
45
@@ -46,7 +47,7 @@ import qualified Streamly.Internal.Data.Stream.StreamD.Type as D
46 (Stream(..), Step(..))
47 (Stream(..), Step(..))
47import qualified Streamly.Internal.Data.Stream.StreamK.Type as K
48import qualified Streamly.Internal.Data.Stream.StreamK.Type as K
48 (Stream(..), foldStreamShared, mkStream, foldStream)
49 (Stream(..), foldStreamShared, mkStream, foldStream)
49−import qualified Streamly.Internal.Data.Stream.Type as Stream (fromStreamK)
50+import qualified Streamly.Internal.Data.Stream.Serial as Stream (fromStreamK)
50
51
51import Streamly.Internal.Data.SVar
52import Streamly.Internal.Data.SVar
52
53
@@ -90,7 +91,7 @@ import Test.Inspection (inspect, hasNoTypeClassesExcept)
90-- XXX this errors out for Parallel/Ahead SVars
91-- XXX this errors out for Parallel/Ahead SVars
91-- | Write a stream to an 'SVar' in a non-blocking manner. The stream can then
92-- | Write a stream to an 'SVar' in a non-blocking manner. The stream can then
92-- be read back from the SVar using 'fromSVar'.
93-- be read back from the SVar using 'fromSVar'.
93−toSVar :: MonadAsync m => SVar Stream m a -> Stream m a -> m ()
94+toSVar :: MonadAsync m => SVar SerialT m a -> SerialT m a -> m ()
94toSVar sv m = do
95toSVar sv m = do
95 runIn <- askRunInIO
96 runIn <- askRunInIO
96 liftIO $ enqueue sv (runIn, m)
97 liftIO $ enqueue sv (runIn, m)
@@ -185,7 +186,7 @@ inspect $ hasNoTypeClassesExcept 'fromStreamVar
185-- combinators.
186-- combinators.
186--
187--
187{-# INLINE fromSVar #-}
188{-# INLINE fromSVar #-}
188−fromSVar :: MonadAsync m => SVar K.Stream m a -> Stream m a
189+fromSVar :: MonadAsync m => SVar K.Stream m a -> SerialT m a
189fromSVar sv =
190fromSVar sv =
190 Stream.fromStreamK $ K.mkStream $ \st yld sng stp -> do
191 Stream.fromStreamK $ K.mkStream $ \st yld sng stp -> do
191 ref <- liftIO $ newIORef ()
192 ref <- liftIO $ newIORef ()
src/Streamly/Internal/Data/Stream/Serial.hs+172−101
@@ -12,13 +12,14 @@
12--
12--
13-- To run examples in this module:
13-- To run examples in this module:
14--
14--
15−-- >>> import qualified Streamly.Data.Stream as Stream
15+-- >>> import qualified Streamly.Prelude as Stream
16−-- >>> import qualified Streamly.Prelude as IsStream
17--
16--
18module Streamly.Internal.Data.Stream.Serial {-# DEPRECATED "Please use \"Streamly.Internal.Data.Stream\" from streamly-core package instead." #-}
17module Streamly.Internal.Data.Stream.Serial {-# DEPRECATED "Please use \"Streamly.Internal.Data.Stream\" from streamly-core package instead." #-}
19 (
18 (
20 -- * Serial appending stream
19 -- * Serial appending stream
21− SerialT
20+ SerialT(..)
21+ , toStreamK
22+ , fromStreamK
22 , Serial
23 , Serial
23 , serial
24 , serial
24
25
@@ -31,10 +32,10 @@ module Streamly.Internal.Data.Stream.Serial {-# DEPRECATED "Please use \"Streaml
31 , consMWSerial
32 , consMWSerial
32
33
33 -- * Construction
34 -- * Construction
34− , Stream.cons
35+ , cons
35− , Stream.consM
36+ , consM
36− , Stream.repeat
37+ , repeat
37− , Stream.unfoldrM
38+ , unfoldrM
38 , fromList
39 , fromList
39
40
40 -- * Elimination
41 -- * Elimination
@@ -42,7 +43,7 @@ module Streamly.Internal.Data.Stream.Serial {-# DEPRECATED "Please use \"Streaml
42
43
43 -- * Transformation
44 -- * Transformation
44 , map
45 , map
45− , Stream.mapM
46+ , mapM
46 )
47 )
47where
48where
48
49
@@ -64,18 +65,13 @@ import Text.Read
64 , readListPrecDefault)
65 , readListPrecDefault)
65import Streamly.Internal.BaseCompat ((#.))
66import Streamly.Internal.BaseCompat ((#.))
66import Streamly.Internal.Data.Maybe.Strict (Maybe'(..), toMaybe)
67import Streamly.Internal.Data.Maybe.Strict (Maybe'(..), toMaybe)
67−import Streamly.Data.Stream (Stream)
68+import Streamly.Internal.Data.Stream.StreamK.Type (Stream)
68
69
69−import qualified Streamly.Data.Fold as Fold
70−import qualified Streamly.Data.Stream as Stream
71−import qualified Streamly.Internal.Data.Stream as Stream
72− (toStreamK, fromStreamK, crossApply, crossApplySnd, crossApplyFst)
73import qualified Streamly.Internal.Data.Stream.Common as P
70import qualified Streamly.Internal.Data.Stream.Common as P
74−import qualified Streamly.Internal.Data.Stream.StreamD as D
71+import qualified Streamly.Internal.Data.Stream.StreamD.Generate as D
75− (fromStreamK, toStreamK, mapM)
72+import qualified Streamly.Internal.Data.Stream.StreamD.Transform as D
73+import qualified Streamly.Internal.Data.Stream.StreamD.Type as D
76import qualified Streamly.Internal.Data.Stream.StreamK.Type as K
74import qualified Streamly.Internal.Data.Stream.StreamK.Type as K
77− (Stream, mkStream, foldStream, cons, consM, nil, concatMapWith, fromPure
78− , bindWith, interleave, interleaveFst, interleaveMin, serial, fromEffect)
79
75
80import Prelude hiding (map, mapM, repeat, filter)
76import Prelude hiding (map, mapM, repeat, filter)
81
77
@@ -84,7 +80,6 @@ import Prelude hiding (map, mapM, repeat, filter)
84
80
85-- $setup
81-- $setup
86-- >>> :set -fno-warn-deprecations
82-- >>> :set -fno-warn-deprecations
87−-- >>> import qualified Streamly.Data.Stream as Stream
88-- >>> import qualified Streamly.Prelude as IsStream
83-- >>> import qualified Streamly.Prelude as IsStream
89
84
90{-# INLINABLE withLocal #-}
85{-# INLINABLE withLocal #-}
@@ -96,41 +91,99 @@ withLocal f m =
96 in K.foldStream st yieldk single (local f stp) m
91 in K.foldStream st yieldk single (local f stp) m
97
92
98------------------------------------------------------------------------------
93------------------------------------------------------------------------------
99−-- Applicative - orphan instances
94+-- SerialT
100------------------------------------------------------------------------------
95------------------------------------------------------------------------------
101
96
102−-- Note: we need to define all the typeclass operations because we want to
97+-- | For 'SerialT' streams:
103−-- INLINE them.
98+--
104−instance Monad m => Applicative (Stream m) where
99+-- @
105− {-# INLINE pure #-}
100+-- (<>) = 'Streamly.Prelude.serial' -- 'Semigroup'
106− pure = Stream.fromStreamK . K.fromPure
101+-- (>>=) = flip . 'Streamly.Prelude.concatMapWith' 'Streamly.Prelude.serial' -- 'Monad'
102+-- @
103+--
104+-- A single 'Monad' bind behaves like a @for@ loop:
105+--
106+-- >>> :{
107+-- IsStream.toList $ do
108+-- x <- IsStream.fromList [1,2] -- foreach x in stream
109+-- return x
110+-- :}
111+-- [1,2]
112+--
113+-- Nested monad binds behave like nested @for@ loops:
114+--
115+-- >>> :{
116+-- IsStream.toList $ do
117+-- x <- IsStream.fromList [1,2] -- foreach x in stream
118+-- y <- IsStream.fromList [3,4] -- foreach y in stream
119+-- return (x, y)
120+-- :}
121+-- [(1,3),(1,4),(2,3),(2,4)]
122+--
123+-- /Since: 0.2.0 ("Streamly")/
124+--
125+-- @since 0.8.0
126+newtype SerialT m a = SerialT {getSerialT :: Stream m a}
127+ -- XXX when deriving do we inherit an INLINE?
128+ deriving (Semigroup, Monoid)
107
129
108− {-# INLINE (<*>) #-}
130+-- | A serial IO stream of elements of type @a@. See 'SerialT' documentation
109− (<*>) = Stream.crossApply
131+-- for more details.
110− -- (<*>) = K.apSerial
132+--
133+-- /Since: 0.2.0 ("Streamly")/
134+--
135+-- @since 0.8.0
136+type Serial = SerialT IO
111
137
112− {-# INLINE liftA2 #-}
138+toStreamK :: SerialT m a -> Stream m a
113− liftA2 f x = (<*>) (fmap f x)
139+toStreamK = getSerialT
114
140
115− {-# INLINE (*>) #-}
141+fromStreamK :: Stream m a -> SerialT m a
116− (*>) = Stream.crossApplySnd
142+fromStreamK = SerialT
117− -- (*>) = K.apSerialDiscardFst
118
143
144+------------------------------------------------------------------------------
145+-- Generation
146+------------------------------------------------------------------------------
147+
148+infixr 5 `cons`
149+
119− {-# INLINE (<*) #-}
150+{-# INLINE cons #-}
120− (<*) = Stream.crossApplyFst
151+cons :: a -> SerialT m a -> SerialT m a
121− -- (<*) = K.apSerialDiscardSnd
152+cons x (SerialT ms) = SerialT $ K.cons x ms
153+
154+infixr 5 `consM`
155+
156+{-# INLINE consM #-}
157+{-# SPECIALIZE consM :: IO a -> SerialT IO a -> SerialT IO a #-}
158+consM :: Monad m => m a -> SerialT m a -> SerialT m a
159+consM m (SerialT ms) = SerialT $ K.consM m ms
160+
161+-- |
162+-- Generate an infinite stream by repeating a pure value.
163+--
164+{-# INLINE_NORMAL repeat #-}
165+repeat :: Monad m => a -> SerialT m a
166+repeat = SerialT . D.toStreamK . D.repeat
122
167
123------------------------------------------------------------------------------
168------------------------------------------------------------------------------
124−-- Monad - orphan instances
169+-- Combining
125------------------------------------------------------------------------------
170------------------------------------------------------------------------------
126
171
172+{-# INLINE serial #-}
173+serial :: SerialT m a -> SerialT m a -> SerialT m a
174+serial = (<>)
175+
176+------------------------------------------------------------------------------
177+-- Monad
178+------------------------------------------------------------------------------
179+
127−instance Monad m => Monad (Stream m) where
180+instance Monad m => Monad (SerialT m) where
128 return = pure
181 return = pure
129
182
130 -- Benchmarks better with StreamD bind and pure:
183 -- Benchmarks better with StreamD bind and pure:
131 -- toList, filterAllout, *>, *<, >> (~2x)
184 -- toList, filterAllout, *>, *<, >> (~2x)
132 --
185 --
133− -- pure = Stream . D.fromStreamD . D.fromPure
186+ -- pure = SerialT . D.fromStreamD . D.fromPure
134 -- m >>= f = D.fromStreamD $ D.concatMap (D.toStreamD . f) (D.toStreamD m)
187 -- m >>= f = D.fromStreamD $ D.concatMap (D.toStreamD . f) (D.toStreamD m)
135
188
136 -- Benchmarks better with CPS bind and pure:
189 -- Benchmarks better with CPS bind and pure:
@@ -138,75 +191,22 @@ instance Monad m => Monad (Stream m) where
138 -- n binds, breakAfterSome, filterAllIn, state transformer (~2x)
191 -- n binds, breakAfterSome, filterAllIn, state transformer (~2x)
139 --
192 --
140 {-# INLINE (>>=) #-}
193 {-# INLINE (>>=) #-}
141− (>>=) m f =
194+ (>>=) (SerialT m) f = SerialT $ K.bindWith K.append m (getSerialT . f)
142− Stream.fromStreamK
143− $ K.bindWith K.serial (Stream.toStreamK m) (Stream.toStreamK . f)
144
195
145 {-# INLINE (>>) #-}
196 {-# INLINE (>>) #-}
146 (>>) = (*>)
197 (>>) = (*>)
147
198
148−------------------------------------------------------------------------------
149−-- Transformers - orphan instances
150−------------------------------------------------------------------------------
151−
152−instance (MonadIO m) => MonadIO (Stream m) where
153− liftIO = lift . liftIO
154−
155−instance (MonadThrow m) => MonadThrow (Stream m) where
156− throwM = lift . throwM
157−
158−instance MonadTrans Stream where
199+instance MonadTrans SerialT where
159 {-# INLINE lift #-}
200 {-# INLINE lift #-}
160− lift = Stream.fromEffect
201+ lift = SerialT . K.fromEffect
161−
162−instance (MonadReader r m) => MonadReader r (Stream m) where
163− ask = lift ask
164−
165− local f m = Stream.fromStreamK $ withLocal f (Stream.toStreamK m)
166−
167−instance (MonadState s m) => MonadState s (Stream m) where
168− {-# INLINE get #-}
169− get = lift get
170−
171− {-# INLINE put #-}
172− put x = lift (put x)
173−
174− {-# INLINE state #-}
175− state k = lift (state k)
176
202
177------------------------------------------------------------------------------
203------------------------------------------------------------------------------
178−-- NFData - orphan instances
204+-- Other instances
179−------------------------------------------------------------------------------
180−
181−instance NFData a => NFData (Stream Identity a) where
182− {-# INLINE rnf #-}
183− rnf xs = runIdentity $ Stream.fold (Fold.foldl' (\_ x -> rnf x) ()) xs
184−
185−instance NFData1 (Stream Identity) where
186− {-# INLINE liftRnf #-}
187− liftRnf f xs = runIdentity $ Stream.fold (Fold.foldl' (\_ x -> f x) ()) xs
188−
189−------------------------------------------------------------------------------
190−-- SerialT
191−------------------------------------------------------------------------------
192−
193−type SerialT = Stream
194−
195−-- | A serial IO stream of elements of type @a@. See 'SerialT' documentation
196−-- for more details.
197−--
198−-- /Since: 0.2.0 ("Streamly")/
199−--
200−-- @since 0.8.0
201−type Serial = SerialT IO
202−
203−------------------------------------------------------------------------------
204−-- Combining
205------------------------------------------------------------------------------
205------------------------------------------------------------------------------
206
206
207−{-# INLINE serial #-}
207+{-# INLINE mapM #-}
208−serial :: SerialT m a -> SerialT m a -> SerialT m a
208+mapM :: Monad m => (a -> m b) -> SerialT m a -> SerialT m b
209−serial = (<>)
209+mapM f (SerialT m) = SerialT $ D.toStreamK $ D.mapM f $ D.fromStreamK m
210
210
211-- |
211-- |
212-- @
212-- @
@@ -223,7 +223,49 @@ serial = (<>)
223-- @since 0.4.0
223-- @since 0.4.0
224{-# INLINE map #-}
224{-# INLINE map #-}
225map :: Monad m => (a -> b) -> SerialT m a -> SerialT m b
225map :: Monad m => (a -> b) -> SerialT m a -> SerialT m b
226−map f = Stream.mapM (return . f)
226+map f = mapM (return . f)
227+
228+{-# INLINE apSerial #-}
229+apSerial :: Monad m => SerialT m (a -> b) -> SerialT m a -> SerialT m b
230+apSerial (SerialT m1) (SerialT m2) =
231+ SerialT $ D.toStreamK $ D.fromStreamK m1 `D.crossApply` D.fromStreamK m2
232+
233+{-# INLINE apSequence #-}
234+apSequence :: Monad m => SerialT m a -> SerialT m b -> SerialT m b
235+apSequence (SerialT m1) (SerialT m2) =
236+ SerialT $ D.toStreamK $ D.fromStreamK m1 `D.crossApplySnd` D.fromStreamK m2
237+
238+{-# INLINE apDiscardSnd #-}
239+apDiscardSnd :: Monad m => SerialT m a -> SerialT m b -> SerialT m a
240+apDiscardSnd (SerialT m1) (SerialT m2) =
241+ SerialT $ D.toStreamK $ D.fromStreamK m1 `D.crossApplyFst` D.fromStreamK m2
242+
243+-- Note: we need to define all the typeclass operations because we want to
244+-- INLINE them.
245+instance Monad m => Applicative (SerialT m) where
246+ {-# INLINE pure #-}
247+ pure = SerialT . K.fromPure
248+
249+ {-# INLINE (<*>) #-}
250+ (<*>) = apSerial
251+ -- (<*>) = K.apSerial
252+
253+ {-# INLINE liftA2 #-}
254+ liftA2 f x = (<*>) (fmap f x)
255+
256+ {-# INLINE (*>) #-}
257+ (*>) = apSequence
258+ -- (*>) = K.apSerialDiscardFst
259+
260+ {-# INLINE (<*) #-}
261+ (<*) = apDiscardSnd
262+ -- (<*) = K.apSerialDiscardSnd
263+
264+MONAD_COMMON_INSTANCES(SerialT,)
265+LIST_INSTANCES(SerialT)
266+NFDATA1_INSTANCE(SerialT)
267+FOLDABLE_INSTANCE(SerialT)
268+TRAVERSABLE_INSTANCE(SerialT)
227
269
228------------------------------------------------------------------------------
270------------------------------------------------------------------------------
229-- WSerialT
271-- WSerialT
@@ -267,12 +309,12 @@ map f = Stream.mapM (return . f)
267-- [(1,3),(2,3),(1,4),(2,4)]
309-- [(1,3),(2,3),(1,4),(2,4)]
268--
310--
269-- The @W@ in the name stands for @wide@ or breadth wise scheduling in
311-- The @W@ in the name stands for @wide@ or breadth wise scheduling in
270−-- contrast to the depth wise scheduling behavior of 'Stream'.
312+-- contrast to the depth wise scheduling behavior of 'SerialT'.
271--
313--
272-- /Since: 0.2.0 ("Streamly")/
314-- /Since: 0.2.0 ("Streamly")/
273--
315--
274-- @since 0.8.0
316-- @since 0.8.0
275−newtype WSerialT m a = WSerialT {getWSerialT :: K.Stream m a}
317+newtype WSerialT m a = WSerialT {getWSerialT :: Stream m a}
276
318
277instance MonadTrans WSerialT where
319instance MonadTrans WSerialT where
278 {-# INLINE lift #-}
320 {-# INLINE lift #-}
@@ -370,3 +412,32 @@ LIST_INSTANCES(WSerialT)
370NFDATA1_INSTANCE(WSerialT)
412NFDATA1_INSTANCE(WSerialT)
371FOLDABLE_INSTANCE(WSerialT)
413FOLDABLE_INSTANCE(WSerialT)
372TRAVERSABLE_INSTANCE(WSerialT)
414TRAVERSABLE_INSTANCE(WSerialT)
415+
416+------------------------------------------------------------------------------
417+-- Construction
418+------------------------------------------------------------------------------
419+
420+-- | Build a stream by unfolding a /monadic/ step function starting from a
421+-- seed. The step function returns the next element in the stream and the next
422+-- seed value. When it is done it returns 'Nothing' and the stream ends. For
423+-- example,
424+--
425+-- @
426+-- let f b =
427+-- if b > 3
428+-- then return Nothing
429+-- else print b >> return (Just (b, b + 1))
430+-- in drain $ unfoldrM f 0
431+-- @
432+-- @
433+-- 0
434+-- 1
435+-- 2
436+-- 3
437+-- @
438+--
439+-- /Pre-release/
440+--
441+{-# INLINE unfoldrM #-}
442+unfoldrM :: Monad m => (b -> m (Maybe (a, b))) -> b -> SerialT m a
443+unfoldrM step seed = SerialT $ D.toStreamK (D.unfoldrM step seed)
src/Streamly/Internal/Data/Stream/Time.hs+3−3
@@ -62,7 +62,7 @@ import Data.Proxy (Proxy(..))
62import Streamly.Data.Fold (Fold)
62import Streamly.Data.Fold (Fold)
63import Streamly.Internal.Data.Fold.Type (Fold (..))
63import Streamly.Internal.Data.Fold.Type (Fold (..))
64import Streamly.Internal.Data.IsMap (IsMap(..))
64import Streamly.Internal.Data.IsMap (IsMap(..))
65−import Streamly.Internal.Data.Stream.Type (Stream)
65+import Streamly.Internal.Data.Stream.StreamD.Type (Stream)
66import Streamly.Internal.Data.Time.Units
66import Streamly.Internal.Data.Time.Units
67 ( AbsTime
67 ( AbsTime
68 , MilliSecond64(..)
68 , MilliSecond64(..)
@@ -78,7 +78,7 @@ import qualified Streamly.Data.Stream as Stream
78import qualified Streamly.Data.Unfold as Unfold
78import qualified Streamly.Data.Unfold as Unfold
79import qualified Streamly.Internal.Data.Fold as Fold (Step(..))
79import qualified Streamly.Internal.Data.Fold as Fold (Step(..))
80import qualified Streamly.Internal.Data.IsMap as IsMap
80import qualified Streamly.Internal.Data.IsMap as IsMap
81−import qualified Streamly.Internal.Data.Stream as Stream
81+import qualified Streamly.Internal.Data.Stream.StreamD as Stream
82 ( scanlMAfter'
82 ( scanlMAfter'
83 , timeIndexed
83 , timeIndexed
84 , timestamped
84 , timestamped
@@ -392,7 +392,7 @@ ejectEntry :: (Monad m, IsMap f) =>
392 -> m (heap, f entry, Stream m (Key f, b), Int)
392 -> m (heap, f entry, Stream m (Key f, b), Int)
393ejectEntry extract hp mp out cnt acc key = do
393ejectEntry extract hp mp out cnt acc key = do
394 sess <- extract acc
394 sess <- extract acc
395− let out1 = (key, sess) `Stream.cons` out
395+ let out1 = Stream.cons (key, sess) out
396 let mp1 = IsMap.mapDelete key mp
396 let mp1 = IsMap.mapDelete key mp
397 return (hp, mp1, out1, cnt - 1)
397 return (hp, mp1, out1, cnt - 1)
398
398
src/Streamly/Internal/Data/Stream/Zip.hsnew file+135
@@ -0,0 +1,135 @@
1+{-# LANGUAGE UndecidableInstances #-}
2+{-# OPTIONS_GHC -Wno-deprecations #-}
3+
4+-- |
5+-- Module : Streamly.Internal.Data.Stream.Zip
6+-- Copyright : (c) 2017 Composewell Technologies
7+--
8+-- License : BSD3
9+-- Maintainer : streamly@composewell.com
10+-- Stability : experimental
11+-- Portability : GHC
12+--
13+-- To run examples in this module:
14+--
15+-- >>> import qualified Streamly.Prelude as Stream
16+--
17+module Streamly.Internal.Data.Stream.Zip
18+ (
19+ ZipSerialM (..)
20+ , ZipSerial
21+ , consMZip
22+ , zipWithK
23+ , zipWithMK
24+
25+ -- * Deprecated
26+ , ZipStream
27+ )
28+where
29+
30+import Control.Applicative (liftA2)
31+import Control.DeepSeq (NFData(..))
32+#if MIN_VERSION_deepseq(1,4,3)
33+import Control.DeepSeq (NFData1(..))
34+#endif
35+import Data.Foldable (Foldable(foldl'), fold)
36+import Data.Functor.Identity (Identity(..), runIdentity)
37+import Data.Maybe (fromMaybe)
38+import Data.Semigroup (Endo(..))
39+#if __GLASGOW_HASKELL__ < 808
40+import Data.Semigroup (Semigroup(..))
41+#endif
42+import GHC.Exts (IsList(..), IsString(..), oneShot)
43+import Text.Read
44+ ( Lexeme(Ident), lexP, parens, prec, readPrec, readListPrec
45+ , readListPrecDefault)
46+import Streamly.Internal.BaseCompat ((#.))
47+import Streamly.Internal.Data.Maybe.Strict (Maybe'(..), toMaybe)
48+import Streamly.Internal.Data.Stream.Serial (SerialT(..))
49+import Streamly.Internal.Data.Stream.StreamK.Type (Stream)
50+
51+import qualified Streamly.Internal.Data.Stream.Common as P
52+import qualified Streamly.Internal.Data.Stream.StreamK.Type as K
53+import qualified Streamly.Internal.Data.Stream.StreamD as D
54+import qualified Streamly.Internal.Data.Stream.Serial as Serial
55+
56+import Prelude hiding (map, repeat, zipWith)
57+
58+#include "Instances.hs"
59+
60+-- $setup
61+-- >>> import qualified Streamly.Prelude as Stream
62+-- >>> import Control.Concurrent (threadDelay)
63+-- >>> :{
64+-- delay n = do
65+-- threadDelay (n * 1000000) -- sleep for n seconds
66+-- putStrLn (show n ++ " sec") -- print "n sec"
67+-- return n -- IO Int
68+-- :}
69+
70+{-# INLINE zipWithMK #-}
71+zipWithMK :: Monad m =>
72+ (a -> b -> m c) -> Stream m a -> Stream m b -> Stream m c
73+zipWithMK f m1 m2 =
74+ D.toStreamK $ D.zipWithM f (D.fromStreamK m1) (D.fromStreamK m2)
75+
76+{-# INLINE zipWithK #-}
77+zipWithK :: Monad m
78+ => (a -> b -> c) -> Stream m a -> Stream m b -> Stream m c
79+zipWithK f = zipWithMK (\a b -> return (f a b))
80+
81+------------------------------------------------------------------------------
82+-- Serially Zipping Streams
83+------------------------------------------------------------------------------
84+
85+-- | For 'ZipSerialM' streams:
86+--
87+-- @
88+-- (<>) = 'Streamly.Prelude.serial'
89+-- (<*>) = 'Streamly.Prelude.serial.zipWith' id
90+-- @
91+--
92+-- Applicative evaluates the streams being zipped serially:
93+--
94+-- >>> s1 = Stream.fromFoldable [1, 2]
95+-- >>> s2 = Stream.fromFoldable [3, 4]
96+-- >>> s3 = Stream.fromFoldable [5, 6]
97+-- >>> Stream.toList $ Stream.fromZipSerial $ (,,) <$> s1 <*> s2 <*> s3
98+-- [(1,3,5),(2,4,6)]
99+--
100+-- /Since: 0.2.0 ("Streamly")/
101+--
102+-- @since 0.8.0
103+newtype ZipSerialM m a = ZipSerialM {getZipSerialM :: Stream m a}
104+ deriving (Semigroup, Monoid)
105+
106+-- |
107+-- @since 0.1.0
108+{-# DEPRECATED ZipStream "Please use 'ZipSerialM' instead." #-}
109+type ZipStream = ZipSerialM
110+
111+-- | An IO stream whose applicative instance zips streams serially.
112+--
113+-- /Since: 0.2.0 ("Streamly")/
114+--
115+-- @since 0.8.0
116+type ZipSerial = ZipSerialM IO
117+
118+consMZip :: Monad m => m a -> ZipSerialM m a -> ZipSerialM m a
119+consMZip m (ZipSerialM r) = ZipSerialM $ K.consM m r
120+
121+LIST_INSTANCES(ZipSerialM)
122+NFDATA1_INSTANCE(ZipSerialM)
123+
124+instance Monad m => Functor (ZipSerialM m) where
125+ {-# INLINE fmap #-}
126+ fmap f (ZipSerialM m) = ZipSerialM $ getSerialT $ fmap f (SerialT m)
127+
128+instance Monad m => Applicative (ZipSerialM m) where
129+ pure = ZipSerialM . getSerialT . Serial.repeat
130+
131+ {-# INLINE (<*>) #-}
132+ ZipSerialM m1 <*> ZipSerialM m2 = ZipSerialM $ zipWithK id m1 m2
133+
134+FOLDABLE_INSTANCE(ZipSerialM)
135+TRAVERSABLE_INSTANCE(ZipSerialM)
src/Streamly/Internal/Data/Stream/Zip/Concurrent.hs+2−2
@@ -18,10 +18,10 @@ module Streamly.Internal.Data.Stream.Zip.Concurrent
18 )
18 )
19where
19where
20
20
21−import Streamly.Internal.Data.Stream (Stream)
21+import Streamly.Internal.Data.Stream.StreamD (Stream)
22import Streamly.Internal.Data.Stream.Concurrent (MonadAsync, parZipWith)
22import Streamly.Internal.Data.Stream.Concurrent (MonadAsync, parZipWith)
23
23
24−import qualified Streamly.Internal.Data.Stream as Stream (repeat)
24+import qualified Streamly.Internal.Data.Stream.StreamD as Stream (repeat)
25import Prelude hiding (map, repeat, zipWith)
25import Prelude hiding (map, repeat, zipWith)
26
26
27-- $setup
27-- $setup
src/Streamly/Internal/Data/Stream/ZipAsync.hs+1−1
@@ -31,7 +31,7 @@ import qualified Streamly.Internal.Data.Stream.StreamD as D (fromStreamK)
31import qualified Streamly.Internal.Data.Stream.Serial as Serial
31import qualified Streamly.Internal.Data.Stream.Serial as Serial
32import qualified Streamly.Internal.Data.Stream.SVar.Eliminate as SVar
32import qualified Streamly.Internal.Data.Stream.SVar.Eliminate as SVar
33import qualified Streamly.Internal.Data.Stream.SVar.Generate as SVar
33import qualified Streamly.Internal.Data.Stream.SVar.Generate as SVar
34−import qualified Streamly.Internal.Data.Stream as Stream
34+import qualified Streamly.Internal.Data.Stream.Serial as Stream
35 (fromStreamK, toStreamK)
35 (fromStreamK, toStreamK)
36import Streamly.Internal.Data.SVar
36import Streamly.Internal.Data.SVar
37
37
src/Streamly/Internal/FileSystem/Event.hs+1−1
@@ -48,7 +48,7 @@ where
48import Data.List.NonEmpty (NonEmpty)
48import Data.List.NonEmpty (NonEmpty)
49import Data.Word (Word8)
49import Data.Word (Word8)
50import Streamly.Internal.Data.Array (Array)
50import Streamly.Internal.Data.Array (Array)
51−import Streamly.Internal.Data.Stream (Stream)
51+import Streamly.Internal.Data.Stream.StreamD (Stream)
52
52
53#if defined(CABAL_OS_DARWIN)
53#if defined(CABAL_OS_DARWIN)
54import Streamly.Internal.FileSystem.Event.Darwin (Event)
54import Streamly.Internal.FileSystem.Event.Darwin (Event)
src/Streamly/Internal/FileSystem/Event/Linux.hs+2−2
@@ -171,7 +171,7 @@ import Foreign.Storable (peek, peekByteOff, sizeOf)
171import GHC.IO.Device (IODeviceType(Stream))
171import GHC.IO.Device (IODeviceType(Stream))
172import GHC.IO.FD (fdFD, mkFD)
172import GHC.IO.FD (fdFD, mkFD)
173import GHC.IO.Handle.FD (mkHandleFromFD)
173import GHC.IO.Handle.FD (mkHandleFromFD)
174−import Streamly.Internal.Data.Stream (Stream)
174+import Streamly.Internal.Data.Stream.StreamD (Stream)
175import Streamly.Internal.Data.Parser (Parser)
175import Streamly.Internal.Data.Parser (Parser)
176import Streamly.Internal.Data.Array.Type (Array(..), byteLength)
176import Streamly.Internal.Data.Array.Type (Array(..), byteLength)
177import System.Directory (doesDirectoryExist)
177import System.Directory (doesDirectoryExist)
@@ -184,7 +184,7 @@ import qualified Streamly.Internal.Data.Array as A
184import qualified Streamly.Data.Fold as FL
184import qualified Streamly.Data.Fold as FL
185import qualified Streamly.Internal.Data.Parser as PR
185import qualified Streamly.Internal.Data.Parser as PR
186 (takeEQ, fromEffect, fromFold)
186 (takeEQ, fromEffect, fromFold)
187−import qualified Streamly.Internal.Data.Stream as S
187+import qualified Streamly.Internal.Data.Stream.StreamD as S
188import qualified Streamly.Internal.FileSystem.Dir as Dir
188import qualified Streamly.Internal.FileSystem.Dir as Dir
189import qualified Streamly.Internal.FileSystem.Handle as FH
189import qualified Streamly.Internal.FileSystem.Handle as FH
190import qualified Streamly.Internal.Unicode.Stream as U
190import qualified Streamly.Internal.Unicode.Stream as U
src/Streamly/Internal/FileSystem/FD.hs+4−4
@@ -131,7 +131,7 @@ import qualified GHC.IO.Device as RawIO
131import Streamly.Internal.Data.Array.Type
131import Streamly.Internal.Data.Array.Type
132 (Array(..), byteLength, unsafeFreeze, asPtrUnsafe)
132 (Array(..), byteLength, unsafeFreeze, asPtrUnsafe)
133import Streamly.Internal.System.IO (defaultChunkSize)
133import Streamly.Internal.System.IO (defaultChunkSize)
134−import Streamly.Internal.Data.Stream.Type (Stream)
134+import Streamly.Internal.Data.Stream.StreamD.Type (Stream)
135#if !defined(mingw32_HOST_OS)
135#if !defined(mingw32_HOST_OS)
136{-
136{-
137import Streamly.Internal.Data.Stream.IsStream.Type (toStreamD)
137import Streamly.Internal.Data.Stream.IsStream.Type (toStreamD)
@@ -148,7 +148,7 @@ import qualified Streamly.Data.Fold as FL
148import qualified Streamly.Internal.Data.Array.Mut as MArray
148import qualified Streamly.Internal.Data.Array.Mut as MArray
149 (Array(..), newPinnedBytes, asPtrUnsafe)
149 (Array(..), newPinnedBytes, asPtrUnsafe)
150import qualified Streamly.Internal.Data.Stream.Chunked as AS
150import qualified Streamly.Internal.Data.Stream.Chunked as AS
151−import qualified Streamly.Internal.Data.Stream as S
151+import qualified Streamly.Internal.Data.Stream.StreamD as S
152import qualified Streamly.Internal.Data.Stream.StreamD.Type as D
152import qualified Streamly.Internal.Data.Stream.StreamD.Type as D
153 (Stream(..), Step(..))
153 (Stream(..), Step(..))
154import qualified Streamly.Internal.Data.Stream.StreamK.Type as K (mkStream)
154import qualified Streamly.Internal.Data.Stream.StreamK.Type as K (mkStream)
@@ -296,7 +296,7 @@ _readArraysOfUpto size h = S.fromStreamK go
296{-# INLINE_NORMAL readArraysOfUpto #-}
296{-# INLINE_NORMAL readArraysOfUpto #-}
297readArraysOfUpto :: (MonadIO m)
297readArraysOfUpto :: (MonadIO m)
298 => Int -> Handle -> Stream m (Array Word8)
298 => Int -> Handle -> Stream m (Array Word8)
299−readArraysOfUpto size h = S.fromStreamD (D.Stream step ())
299+readArraysOfUpto size h = D.Stream step ()
300 where
300 where
301 {-# INLINE_LATE step #-}
301 {-# INLINE_LATE step #-}
302 step _ _ = do
302 step _ _ = do
@@ -357,7 +357,7 @@ read = AS.concat . readArrays
357-- @since 0.7.0
357-- @since 0.7.0
358{-# INLINE writeArrays #-}
358{-# INLINE writeArrays #-}
359writeArrays :: (MonadIO m, Unbox a) => Handle -> Stream m (Array a) -> m ()
359writeArrays :: (MonadIO m, Unbox a) => Handle -> Stream m (Array a) -> m ()
360−writeArrays h = S.fold (FL.drainBy (liftIO . writeArray h))
360+writeArrays h = S.fold (FL.drainMapM (liftIO . writeArray h))
361
361
362-- | Write a stream of arrays to a handle after coalescing them in chunks of
362-- | Write a stream of arrays to a handle after coalescing them in chunks of
363-- specified size. The chunk size is only a maximum and the actual writes could
363-- specified size. The chunk size is only a maximum and the actual writes could
src/Streamly/Internal/Network/Inet/TCP.hs+9−4
@@ -110,6 +110,7 @@ import Streamly.Internal.Data.Array.Type (Array(..), writeNUnsafe)
110import Streamly.Internal.Data.Fold.Type (Fold(..))
110import Streamly.Internal.Data.Fold.Type (Fold(..))
111import Streamly.Data.Stream (Stream)
111import Streamly.Data.Stream (Stream)
112import Streamly.Internal.Data.Tuple.Strict (Tuple'(..))
112import Streamly.Internal.Data.Tuple.Strict (Tuple'(..))
113+import Streamly.Internal.Data.Unboxed (Unbox)
113import Streamly.Internal.Data.Unfold.Type (Unfold(..))
114import Streamly.Internal.Data.Unfold.Type (Unfold(..))
114import Streamly.Internal.Network.Socket (SockSpec(..), accept, acceptor)
115import Streamly.Internal.Network.Socket (SockSpec(..), accept, acceptor)
115import Streamly.Internal.System.IO (defaultChunkSize)
116import Streamly.Internal.System.IO (defaultChunkSize)
@@ -120,10 +121,10 @@ import qualified Network.Socket as Net
120import qualified Streamly.Data.Array as A
121import qualified Streamly.Data.Array as A
121import qualified Streamly.Data.Fold as FL
122import qualified Streamly.Data.Fold as FL
122import qualified Streamly.Data.Unfold as UF
123import qualified Streamly.Data.Unfold as UF
124+import qualified Streamly.Internal.Data.Array.Type as A
123import qualified Streamly.Internal.Data.Unfold as UF (first, bracketIO)
125import qualified Streamly.Internal.Data.Unfold as UF (first, bracketIO)
124−import qualified Streamly.Internal.Data.Stream.Chunked as AS
125import qualified Streamly.Internal.Data.Fold.Type as FL (Step(..), reduce)
126import qualified Streamly.Internal.Data.Fold.Type as FL (Step(..), reduce)
126−import qualified Streamly.Internal.Data.Stream as S
127+import qualified Streamly.Internal.Data.Stream.StreamD as S
127import qualified Streamly.Internal.Data.Stream.Exception.Lifted as S
128import qualified Streamly.Internal.Data.Stream.Exception.Lifted as S
128import qualified Streamly.Internal.Network.Socket as ISK
129import qualified Streamly.Internal.Network.Socket as ISK
129
130
@@ -314,13 +315,17 @@ reader :: (MonadCatch m, MonadAsync m)
314 => Unfold m ((Word8, Word8, Word8, Word8), PortNumber) Word8
315 => Unfold m ((Word8, Word8, Word8, Word8), PortNumber) Word8
315reader = UF.many A.reader (usingConnection ISK.chunkReader)
316reader = UF.many A.reader (usingConnection ISK.chunkReader)
316
317
318+{-# INLINE concatChunks #-}
319+concatChunks :: (Monad m, Unbox a) => Stream m (Array a) -> Stream m a
320+concatChunks = S.unfoldMany A.reader
321+
317-- | Read a stream from the supplied IPv4 host address and port number.
322-- | Read a stream from the supplied IPv4 host address and port number.
318--
323--
319-- /Pre-release/
324-- /Pre-release/
320{-# INLINE read #-}
325{-# INLINE read #-}
321read :: (MonadCatch m, MonadAsync m)
326read :: (MonadCatch m, MonadAsync m)
322 => (Word8, Word8, Word8, Word8) -> PortNumber -> Stream m Word8
327 => (Word8, Word8, Word8, Word8) -> PortNumber -> Stream m Word8
323−read addr port = AS.concat $ withConnection addr port ISK.readChunks
328+read addr port = concatChunks $ withConnection addr port ISK.readChunks
324
329
325-------------------------------------------------------------------------------
330-------------------------------------------------------------------------------
326-- Writing
331-- Writing
@@ -380,7 +385,7 @@ putBytesWithBufferOf
380 -> PortNumber
385 -> PortNumber
381 -> Stream m Word8
386 -> Stream m Word8
382 -> m ()
387 -> m ()
383−putBytesWithBufferOf n addr port m = putChunks addr port $ AS.arraysOf n m
388+putBytesWithBufferOf n addr port m = putChunks addr port $ A.arraysOf n m
384
389
385-- | Like 'write' but provides control over the write buffer. Output will
390-- | Like 'write' but provides control over the write buffer. Output will
386-- be written to the IO device as soon as we collect the specified number of
391-- be written to the IO device as soon as we collect the specified number of
src/Streamly/Internal/Network/Socket.hs+10−7
@@ -89,7 +89,7 @@ import qualified Network.Socket as Net
89import Streamly.Internal.Data.Array.Type (Array(..))
89import Streamly.Internal.Data.Array.Type (Array(..))
90import Streamly.Internal.Data.Stream.Chunked (lpackArraysChunksOf)
90import Streamly.Internal.Data.Stream.Chunked (lpackArraysChunksOf)
91import Streamly.Internal.Data.Fold (Fold)
91import Streamly.Internal.Data.Fold (Fold)
92−import Streamly.Internal.Data.Stream.Type (Stream)
92+import Streamly.Internal.Data.Stream.StreamD.Type (Stream)
93import Streamly.Internal.Data.Unfold.Type (Unfold(..))
93import Streamly.Internal.Data.Unfold.Type (Unfold(..))
94-- import Streamly.String (encodeUtf8, decodeUtf8, foldLines)
94-- import Streamly.String (encodeUtf8, decodeUtf8, foldLines)
95import Streamly.Internal.System.IO (defaultChunkSize)
95import Streamly.Internal.System.IO (defaultChunkSize)
@@ -97,11 +97,10 @@ import Streamly.Internal.System.IO (defaultChunkSize)
97import qualified Streamly.Data.Array as A (reader, length, writeN)
97import qualified Streamly.Data.Array as A (reader, length, writeN)
98import qualified Streamly.Data.Fold as FL
98import qualified Streamly.Data.Fold as FL
99import qualified Streamly.Internal.Data.Array.Type as A
99import qualified Streamly.Internal.Data.Array.Type as A
100− (unsafeFreeze, asPtrUnsafe, byteLength, writeNUnsafe)
100+ (unsafeFreeze, asPtrUnsafe, byteLength, writeNUnsafe, arraysOf)
101import qualified Streamly.Internal.Data.Array.Mut as MArray
101import qualified Streamly.Internal.Data.Array.Mut as MArray
102 (Array(..), newPinnedBytes, asPtrUnsafe)
102 (Array(..), newPinnedBytes, asPtrUnsafe)
103−import qualified Streamly.Internal.Data.Stream.Chunked as AS
103+import qualified Streamly.Internal.Data.Stream.StreamD as S
104−import qualified Streamly.Internal.Data.Stream as S
105import qualified Streamly.Internal.Data.Stream.StreamD.Type as D
104import qualified Streamly.Internal.Data.Stream.StreamD.Type as D
106 (Stream(..), Step(..))
105 (Stream(..), Step(..))
107import qualified Streamly.Data.Unfold as UF
106import qualified Streamly.Data.Unfold as UF
@@ -345,7 +344,7 @@ _readChunksUptoWith f size h = S.fromStreamK go
345{-# INLINE_NORMAL readChunksWith #-}
344{-# INLINE_NORMAL readChunksWith #-}
346readChunksWith :: MonadIO m => Int -> Socket -> Stream m (Array Word8)
345readChunksWith :: MonadIO m => Int -> Socket -> Stream m (Array Word8)
347-- readChunksWith = _readChunksUptoWith readChunk
346-- readChunksWith = _readChunksUptoWith readChunk
348−readChunksWith size h = S.fromStreamD (D.Stream step ())
347+readChunksWith size h = D.Stream step ()
349 where
348 where
350 {-# INLINE_LATE step #-}
349 {-# INLINE_LATE step #-}
351 step _ _ = do
350 step _ _ = do
@@ -403,12 +402,16 @@ chunkReader = UF.first defaultChunkSize chunkReaderWith
403-- Read File to Stream
402-- Read File to Stream
404-------------------------------------------------------------------------------
403-------------------------------------------------------------------------------
405
404
405+{-# INLINE concatChunks #-}
406+concatChunks :: (Monad m, Unbox a) => Stream m (Array a) -> Stream m a
407+concatChunks = S.unfoldMany A.reader
408+
406-- | Generate a byte stream from a socket using a buffer of the given size.
409-- | Generate a byte stream from a socket using a buffer of the given size.
407--
410--
408-- /Pre-release/
411-- /Pre-release/
409{-# INLINE readWith #-}
412{-# INLINE readWith #-}
410readWith :: MonadIO m => Int -> Socket -> Stream m Word8
413readWith :: MonadIO m => Int -> Socket -> Stream m Word8
411−readWith size = AS.concat . readChunksWith size
414+readWith size = concatChunks . readChunksWith size
412
415
413-- | Generate a byte stream from a socket.
416-- | Generate a byte stream from a socket.
414--
417--
@@ -492,7 +495,7 @@ writeChunksWithBufferOf = writeChunksWith
492--
495--
493{-# INLINE putBytesWith #-}
496{-# INLINE putBytesWith #-}
494putBytesWith :: MonadIO m => Int -> Socket -> Stream m Word8 -> m ()
497putBytesWith :: MonadIO m => Int -> Socket -> Stream m Word8 -> m ()
495−putBytesWith n h m = putChunks h $ AS.arraysOf n m
498+putBytesWith n h m = putChunks h $ A.arraysOf n m
496
499
497-- | Write a byte stream to a socket. Accumulates the input in chunks of
500-- | Write a byte stream to a socket. Accumulates the input in chunks of
498-- specified number of bytes before writing.
501-- specified number of bytes before writing.
src/Streamly/Internal/Unicode/Char.hs+2−3
@@ -35,10 +35,9 @@ where
35
35
36import Data.Char (isAsciiUpper, isAsciiLower, chr, ord)
36import Data.Char (isAsciiUpper, isAsciiLower, chr, ord)
37import Unicode.Char (DecomposeMode(..))
37import Unicode.Char (DecomposeMode(..))
38−import Streamly.Internal.Data.Stream (fromStreamD, toStreamD)
39import Streamly.Internal.Data.Stream.StreamD (Stream(..), Step (..))
38import Streamly.Internal.Data.Stream.StreamD (Stream(..), Step (..))
40
39
41−import qualified Streamly.Internal.Data.Stream as Stream (Stream)
40+import qualified Streamly.Internal.Data.Stream.StreamD as Stream (Stream)
42
41
43import qualified Unicode.Char as Char
42import qualified Unicode.Char as Char
44
43
@@ -324,4 +323,4 @@ normalize ::
324 => NormalizationMode
323 => NormalizationMode
325 -> Stream.Stream m Char
324 -> Stream.Stream m Char
326 -> Stream.Stream m Char
325 -> Stream.Stream m Char
327−normalize mode = fromStreamD . normalizeD mode . toStreamD
326+normalize = normalizeD
src/Streamly/Prelude.hs+6
@@ -905,6 +905,12 @@ module Streamly.Prelude
905 -- * Type Synonyms
905 -- * Type Synonyms
906 , MonadAsync
906 , MonadAsync
907
907
908+ -- * Converting from/to Stream/StreamK types
909+ , fromStream
910+ , toStream
911+ , fromStreamK
912+ , toStreamK
913+
908 -- * Stream Type Adapters
914 -- * Stream Type Adapters
909 -- $adapters
915 -- $adapters
910 , IsStream ()
916 , IsStream ()
streamly.cabal+1
@@ -419,6 +419,7 @@ library
419 , Streamly.Internal.Data.Stream.SVar.Eliminate
419 , Streamly.Internal.Data.Stream.SVar.Eliminate
420
420
421 , Streamly.Internal.Data.Stream.Serial
421 , Streamly.Internal.Data.Stream.Serial
422+ , Streamly.Internal.Data.Stream.Zip
422 , Streamly.Internal.Data.Stream.Async
423 , Streamly.Internal.Data.Stream.Async
423 , Streamly.Internal.Data.Stream.Parallel
424 , Streamly.Internal.Data.Stream.Parallel
424 , Streamly.Internal.Data.Stream.Ahead
425 , Streamly.Internal.Data.Stream.Ahead
targets/Targets.hs+89−74
@@ -3,6 +3,10 @@ module Targets
3 )
3 )
4where
4where
5
5
6+-- Special tags
7+-- noTest
8+-- noBench
9+-- testDevOnly
6targets :: [(String, [String])]
10targets :: [(String, [String])]
7targets =
11targets =
8 [ -- Base streams
12 [ -- Base streams
@@ -19,10 +23,14 @@ targets =
19 ]
23 ]
20 )
24 )
21
25
26+{-
27+ -- XXX Need devOnly flag support in BenchRunner
22 , ("Data.Stream.ToStreamK",
28 , ("Data.Stream.ToStreamK",
23 [ "noTest"
29 [ "noTest"
30+ , "devOnly"
24 ]
31 ]
25 )
32 )
33+-}
26
34
27 -- Streams
35 -- Streams
28 , ("Data.Stream",
36 , ("Data.Stream",
@@ -33,6 +41,12 @@ targets =
33 , "noTest"
41 , "noTest"
34 ]
42 ]
35 )
43 )
44+ , ("Data.Stream.StreamDK",
45+ [ "prelude_serial_grp"
46+ , "infinite_grp"
47+ , "noTest"
48+ ]
49+ )
36 , ("Data.Stream.Concurrent",
50 , ("Data.Stream.Concurrent",
37 [ "prelude_concurrent_grp"
51 [ "prelude_concurrent_grp"
38 , "infinite_grp"
52 , "infinite_grp"
@@ -66,78 +80,79 @@ targets =
66 , "infinite_grp"
80 , "infinite_grp"
67 ]
81 ]
68 )
82 )
83+ -- Enabled only when use-prelude flag is set
69− , ("Prelude.Serial",
84+ -- , ("Prelude.Serial",
70− [ "prelude_serial_grp"
85+ -- [ "prelude_serial_grp"
71− , "infinite_grp"
86+ -- , "infinite_grp"
72− , "serial_wserial_cmp"
87+ -- , "serial_wserial_cmp"
73− , "noBench"
88+ -- , "noBench"
74− ]
89+ -- ]
75− )
90+ -- )
76− , ("Prelude.Top",
91+ -- , ("Prelude.Top",
77− [ "prelude_serial_grp"
92+ -- [ "prelude_serial_grp"
78− , "infinite_grp"
93+ -- , "infinite_grp"
79− , "noBench"
94+ -- , "noBench"
80− ]
95+ -- ]
81− )
96+ -- )
82− , ("Prelude.WSerial",
97+ -- , ("Prelude.WSerial",
83− [ "prelude_serial_grp"
98+ -- [ "prelude_serial_grp"
84− , "infinite_grp"
99+ -- , "infinite_grp"
85− , "serial_wserial_cmp"
100+ -- , "serial_wserial_cmp"
86− ]
101+ -- ]
87− )
102+ -- )
88− , ("Prelude.Merge",
103+ -- , ("Prelude.Merge",
89− [ "prelude_serial_grp"
104+ -- [ "prelude_serial_grp"
90− , "infinite_grp"
105+ -- , "infinite_grp"
91− , "noTest"
106+ -- , "noTest"
92− ]
107+ -- ]
93− )
108+ -- )
94− , ("Prelude.ZipSerial",
109+ -- , ("Prelude.ZipSerial",
95− [ "prelude_serial_grp"
110+ -- [ "prelude_serial_grp"
96− , "infinite_grp"
111+ -- , "infinite_grp"
97− ]
112+ -- ]
98− )
113+ -- )
99− , ("Prelude.Async",
114+ -- , ("Prelude.Async",
100− [ "prelude_concurrent_grp"
115+ -- [ "prelude_concurrent_grp"
101− , "infinite_grp"
116+ -- , "infinite_grp"
102− , "concurrent_cmp"
117+ -- , "concurrent_cmp"
103− , "serial_async_cmp"
118+ -- , "serial_async_cmp"
104− ]
119+ -- ]
105− )
120+ -- )
106− , ("Prelude.WAsync",
121+ -- , ("Prelude.WAsync",
107− [ "prelude_concurrent_grp"
122+ -- [ "prelude_concurrent_grp"
108− , "infinite_grp"
123+ -- , "infinite_grp"
109− , "concurrent_cmp"
124+ -- , "concurrent_cmp"
110− ]
125+ -- ]
111− )
126+ -- )
112− , ("Prelude.Ahead",
127+ -- , ("Prelude.Ahead",
113− [ "prelude_concurrent_grp"
128+ -- [ "prelude_concurrent_grp"
114− , "infinite_grp"
129+ -- , "infinite_grp"
115− , "concurrent_cmp"
130+ -- , "concurrent_cmp"
116− ]
131+ -- ]
117− )
132+ -- )
118− , ("Prelude.Parallel",
133+ -- , ("Prelude.Parallel",
119− [ "prelude_concurrent_grp"
134+ -- [ "prelude_concurrent_grp"
120− , "infinite_grp"
135+ -- , "infinite_grp"
121− , "concurrent_cmp"
136+ -- , "concurrent_cmp"
122− ]
137+ -- ]
123− )
138+ -- )
124− , ("Prelude.ZipAsync",
139+ -- , ("Prelude.ZipAsync",
125− [ "prelude_concurrent_grp"
140+ -- [ "prelude_concurrent_grp"
126− , "infinite_grp"
141+ -- , "infinite_grp"
127− ]
142+ -- ]
128− )
143+ -- )
129− , ("Prelude.Concurrent", [ "prelude_other_grp" ])
144+ -- , ("Prelude.Concurrent", [ "prelude_other_grp" ])
130− , ("Prelude.Rate",
145+ -- , ("Prelude.Rate",
131− [ "prelude_other_grp"
146+ -- [ "prelude_other_grp"
132− , "infinite_grp"
147+ -- , "infinite_grp"
133− , "testDevOnly"
148+ -- , "testDevOnly"
134− ]
149+ -- ]
135− )
150+ -- )
136− , ("Prelude.Adaptive",
151+ -- , ("Prelude.Adaptive",
137− [ "prelude_other_grp"
152+ -- [ "prelude_other_grp"
138− , "noTest"
153+ -- , "noTest"
139− ]
154+ -- ]
140− )
155+ -- )
141
156
142 -- Arrays
157 -- Arrays
143 , ("Data.Array.Generic",
158 , ("Data.Array.Generic",
@@ -185,8 +200,8 @@ targets =
185 , ("Unicode.Char", ["testDevOnly"])
200 , ("Unicode.Char", ["testDevOnly"])
186
201
187 -- test only, no benchmarks
202 -- test only, no benchmarks
188− , ("Prelude", ["prelude_other_grp", "noBench"])
203+ -- , ("Prelude", ["prelude_other_grp", "noBench"])
189− , ("Prelude.Fold", ["prelude_other_grp", "noBench"])
204+ -- , ("Prelude.Fold", ["prelude_other_grp", "noBench"])
190 , ("FileSystem.Event", ["noBench"])
205 , ("FileSystem.Event", ["noBench"])
191 , ("Network.Socket", ["noBench"])
206 , ("Network.Socket", ["noBench"])
192 , ("Network.Inet.TCP", ["noBench"])
207 , ("Network.Inet.TCP", ["noBench"])