1{-# LANGUAGE ConstraintKinds #-}
3{-# LANGUAGE FlexibleContexts #-}
4{-# LANGUAGE ScopedTypeVariables #-}
7-- Module : Stream.Common
8-- Copyright : (c) 2018 Composewell Technologies
9-- License : BSD-3-Clause
10-- Maintainer : streamly@composewell.com
13{-# OPTIONS_GHC -Wno-deprecations #-}
34 -- Benchmark stream generation
41 -- Benchmark stream elimination
46 -- Benchmarking functions
68 , transformComposeMapM
74import Control.Applicative (liftA2)
75import Control.DeepSeq (NFData)
76import Control.Exception (try)
77import GHC.Exception (ErrorCall)
78import System.Random (randomRIO)
80import qualified Streamly.Internal.Data.Fold as Fold
81import qualified Streamly.Internal.Data.Pipe as Pipe
84import Streamly.Prelude (foldl', scanl')
85import qualified Streamly.Internal.Data.Stream.IsStream as Stream
86import qualified Streamly.Prelude as Stream
87import qualified Streamly.Prelude as StreamK
88import Streamly.Benchmark.Prelude
89 ( composeN, sourceConcatMapId, benchIOSink
93import Streamly.Internal.Data.Stream (Stream)
94import qualified Streamly.Internal.Data.Stream as D
96import Streamly.Internal.Data.StreamK (StreamK)
97import qualified Streamly.Internal.Data.Stream as Stream
98import qualified Streamly.Internal.Data.StreamK as StreamK
100import qualified Streamly.Internal.Data.Stream as Stream
101import qualified Streamly.Internal.Data.Stream as StreamK
106import Prelude hiding (Foldable(..), mapM, replicate)
109toStream :: Applicative m => StreamK m a -> Stream m a
110toStream = StreamK.toStream
112fromStream :: Monad m => Stream m a -> StreamK m a
113fromStream = StreamK.fromStream
123type Stream = Stream.SerialT
124type MonadAsync m = Stream.MonadAsync m
128type MonadAsync = Monad
131mkCross :: StreamK m a -> StreamK.CrossStreamK m a
132mkCross = StreamK.mkCross
134unCross :: StreamK.CrossStreamK m a -> StreamK m a
135unCross = StreamK.unCross
137mkCross :: Stream m a -> Stream.CrossStream m a
138mkCross = Stream.mkCross
140unCross :: Stream.CrossStream m a -> Stream m a
141unCross = Stream.unCross
147append :: Monad m => Stream m a -> Stream m a -> Stream m a
148append = Stream.serial
151append :: StreamK m a -> StreamK m a -> StreamK m a
152append = StreamK.append
154append :: Monad m => Stream m a -> Stream m a -> Stream m a
155append = Stream.append
159{-# INLINE append2 #-}
160append2 :: Monad m => Stream m a -> Stream m a -> Stream m a
162append2 = Stream.append
168drain :: Monad m => Stream m a -> m ()
170toList :: Monad m => Stream m a -> m [a]
173toList = Stream.toList
175drain = Stream.fold Fold.drain
176toList = Stream.fold Fold.toList
179{-# INLINE fromListM #-}
180fromListM :: MonadAsync m => [m a] -> Stream m a
182fromListM = Stream.fromListM
184fromListM = Stream.sequence . Stream.fromList
187{-# INLINE fromFoldableM #-}
188fromFoldableM :: MonadAsync m => [m a] -> Stream m a
190fromFoldableM = Stream.fromFoldableM
192fromFoldableM = Stream.sequence . toStream . StreamK.fromFoldable
195{-# INLINE sourceUnfoldrM #-}
196sourceUnfoldrM :: MonadAsync m => Int -> Int -> Stream m Int
197sourceUnfoldrM count start = Stream.unfoldrM step start
202 if cnt > start + count
204 else return (Just (cnt, cnt + 1))
206{-# INLINE sourceUnfoldr #-}
207sourceUnfoldr :: Monad m => Int -> Int -> Stream m Int
208sourceUnfoldr count start = Stream.unfoldr step start
213 if cnt > start + count
215 else Just (cnt, cnt + 1)
217{-# INLINE sourceUnfoldrAction #-}
218sourceUnfoldrAction :: (Monad m1, Monad m) => Int -> Int -> Stream m (m1 Int)
219sourceUnfoldrAction value n = Stream.unfoldr step n
226 else Just (return cnt, cnt + 1)
228{-# INLINE sourceFromFoldable #-}
229sourceFromFoldable :: Monad m => Int -> Int -> Stream m Int
230sourceFromFoldable value n = toStream $ StreamK.fromFoldable [n..n+value]
233{-# INLINE benchIOSink #-}
236 => Int -> String -> (Stream IO Int -> IO b) -> Benchmark
237benchIOSink value name f =
238 bench name $ nfIO $ randomRIO (1,1) >>= f . sourceUnfoldrM value
241-- | Takes a source, and uses it with a default drain/fold method.
242{-# INLINE benchIOSrc #-}
245 -> (Int -> Stream IO a)
248 bench name $ nfIO $ randomRIO (1,1) >>= drain . f
250{-# NOINLINE benchIO #-}
251benchIO :: (NFData b) => String -> (Int -> IO b) -> Benchmark
252benchIO name f = bench name $ nfIO $ randomRIO (1,1) >>= f
256{-# INLINE concatStreamsWith #-}
258 :: (StreamK IO Int -> StreamK IO Int -> StreamK IO Int)
263concatStreamsWith op outer inner n =
264 drain $ toStream $ StreamK.concatMapWith op
265 (fromStream . sourceUnfoldrM inner)
266 (fromStream $ sourceUnfoldrM outer n)
268{-# INLINE mergeMapWith #-}
270 :: (StreamK IO Int -> StreamK IO Int -> StreamK IO Int)
275mergeMapWith op outer inner n =
276 drain $ toStream $ StreamK.mergeMapWith op
277 (fromStream . sourceUnfoldrM inner)
278 (fromStream $ sourceUnfoldrM outer n)
281{-# INLINE sourceConcatMapId #-}
282sourceConcatMapId :: (Monad m)
283 => Int -> Int -> Stream m (Stream m Int)
284sourceConcatMapId value n =
285 Stream.fromList $ fmap (D.fromEffect . return) [n..n+value]
288{-# INLINE apDiscardFst #-}
289apDiscardFst :: MonadAsync m =>
291apDiscardFst linearCount start = drain $ toStream $ unCross $
292 mkCross (fromStream $ sourceUnfoldrM nestedCount2 start)
293 *> mkCross (fromStream $ sourceUnfoldrM nestedCount2 start)
297 nestedCount2 = round (fromIntegral linearCount**(1/2::Double))
299{-# INLINE apDiscardSnd #-}
300apDiscardSnd :: MonadAsync m => Int -> Int -> m ()
301apDiscardSnd linearCount start = drain $ toStream $ unCross $
302 mkCross (fromStream $ sourceUnfoldrM nestedCount2 start)
303 <* mkCross (fromStream $ sourceUnfoldrM nestedCount2 start)
307 nestedCount2 = round (fromIntegral linearCount**(1/2::Double))
309{-# INLINE apLiftA2 #-}
310apLiftA2 :: MonadAsync m => Int -> Int -> m ()
311apLiftA2 linearCount start = drain $ toStream $ unCross $
312 liftA2 (+) (mkCross (fromStream $ sourceUnfoldrM nestedCount2 start))
313 (mkCross (fromStream $ sourceUnfoldrM nestedCount2 start))
317 nestedCount2 = round (fromIntegral linearCount**(1/2::Double))
319{-# INLINE toNullAp #-}
320toNullAp :: MonadAsync m => Int -> Int -> m ()
321toNullAp linearCount start = drain $ toStream $ unCross $
322 (+) <$> mkCross (fromStream $ sourceUnfoldrM nestedCount2 start)
323 <*> mkCross (fromStream $ sourceUnfoldrM nestedCount2 start)
327 nestedCount2 = round (fromIntegral linearCount**(1/2::Double))
329{-# INLINE monadThen #-}
330monadThen :: MonadAsync m => Int -> Int -> m ()
331monadThen linearCount start = drain $ toStream $ unCross $ do
332 mkCross (fromStream $ sourceUnfoldrM nestedCount2 start) >>
333 mkCross (fromStream $ sourceUnfoldrM nestedCount2 start)
337 nestedCount2 = round (fromIntegral linearCount**(1/2::Double))
339{-# INLINE toNullM #-}
340toNullM :: MonadAsync m => Int -> Int -> m ()
341toNullM linearCount start = drain $ toStream $ unCross $ do
342 x <- mkCross (fromStream $ sourceUnfoldrM nestedCount2 start)
343 y <- mkCross (fromStream $ sourceUnfoldrM nestedCount2 start)
348 nestedCount2 = round (fromIntegral linearCount**(1/2::Double))
350{-# INLINE toNullM3 #-}
351toNullM3 :: MonadAsync m => Int -> Int -> m ()
352toNullM3 linearCount start = drain $ toStream $ unCross $ do
353 x <- mkCross (fromStream $ sourceUnfoldrM nestedCount3 start)
354 y <- mkCross (fromStream $ sourceUnfoldrM nestedCount3 start)
355 z <- mkCross (fromStream $ sourceUnfoldrM nestedCount3 start)
358 nestedCount3 = round (fromIntegral linearCount**(1/3::Double))
360{-# INLINE filterAllOutM #-}
361filterAllOutM :: MonadAsync m => Int -> Int -> m ()
362filterAllOutM linearCount start = drain $ toStream $ unCross $ do
363 x <- mkCross (fromStream $ sourceUnfoldrM nestedCount2 start)
364 y <- mkCross (fromStream $ sourceUnfoldrM nestedCount2 start)
368 else mkCross StreamK.nil
370 nestedCount2 = round (fromIntegral linearCount**(1/2::Double))
372{-# INLINE filterAllInM #-}
373filterAllInM :: MonadAsync m => Int -> Int -> m ()
374filterAllInM linearCount start = drain $ toStream $ unCross $ do
375 x <- mkCross (fromStream $ sourceUnfoldrM nestedCount2 start)
376 y <- mkCross (fromStream $ sourceUnfoldrM nestedCount2 start)
380 else mkCross StreamK.nil
382 nestedCount2 = round (fromIntegral linearCount**(1/2::Double))
384{-# INLINE filterSome #-}
385filterSome :: MonadAsync m => Int -> Int -> m ()
386filterSome linearCount start = drain $ toStream $ unCross $ do
387 x <- mkCross (fromStream $ sourceUnfoldrM nestedCount2 start)
388 y <- mkCross (fromStream $ sourceUnfoldrM nestedCount2 start)
392 else mkCross StreamK.nil
394 nestedCount2 = round (fromIntegral linearCount**(1/2::Double))
396{-# INLINE breakAfterSome #-}
397breakAfterSome :: Int -> Int -> IO ()
398breakAfterSome linearCount start = do
399 (_ :: Either ErrorCall ()) <- try $ drain $ toStream $ unCross $ do
400 x <- mkCross (fromStream $ sourceUnfoldrM nestedCount2 start)
401 y <- mkCross (fromStream $ sourceUnfoldrM nestedCount2 start)
408 nestedCount2 = round (fromIntegral linearCount**(1/2::Double))
410{-# INLINE toListM #-}
411toListM :: MonadAsync m => Int -> Int -> m [Int]
412toListM linearCount start = toList $ toStream $ unCross $ do
413 x <- mkCross (fromStream $ sourceUnfoldrM nestedCount2 start)
414 y <- mkCross (fromStream $ sourceUnfoldrM nestedCount2 start)
417 nestedCount2 = round (fromIntegral linearCount**(1/2::Double))
419-- Taking a specified number of elements is very expensive in logict so we have
420-- a test to measure the same.
421{-# INLINE toListSome #-}
422toListSome :: MonadAsync m => Int -> Int -> m [Int]
423toListSome linearCount start =
424 toList $ Stream.take 10000 $ toStream $ unCross $ do
425 x <- mkCross (fromStream $ sourceUnfoldrM nestedCount2 start)
426 y <- mkCross (fromStream $ sourceUnfoldrM nestedCount2 start)
429 nestedCount2 = round (fromIntegral linearCount**(1/2::Double))
432{-# INLINE composeN #-}
436 -> (Stream m Int -> Stream m Int)
443 3 -> drain . f . f . f
444 4 -> drain . f . f . f . f
454mapN n = composeN n $ fmap (+ 1)
462mapM n = composeN n $ Stream.mapM return
465foldl' :: Monad m => (b -> a -> b) -> b -> Stream m a -> m b
466foldl' f z = Stream.fold (Fold.foldl' f z)
468scanl' :: Monad m => (b -> a -> b) -> b -> Stream m a -> Stream m b
469scanl' f z = Stream.scan (Fold.foldl' f z)
472{-# INLINE transformMapM #-}
478transformMapM n = composeN n $ Stream.transform (Pipe.mapM return)
480{-# INLINE transformComposeMapM #-}
481transformComposeMapM ::
486transformComposeMapM n =
489 (Pipe.mapM (\x -> return (x + 1)) `Pipe.compose`
490 Pipe.mapM (\x -> return (x + 2)))
492{-# INLINE transformTeeMapM #-}
501 (Pipe.mapM (\x -> return (x + 1)) `Pipe.tee`
502 Pipe.mapM (\x -> return (x + 2)))
504{-# INLINE transformZipMapM #-}
515 (Pipe.mapM (\x -> return (x + 1)))
516 (Pipe.mapM (\x -> return (x + 2))))
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list