on master help sign in
Add fromFoldableM
3b64278Harendra Kumar
Changelog.md+1
@@ -1,6 +1,7 @@
1## Unreleased
1## Unreleased
2
2
3* Add concurrent lookahead stream type `Ahead`
3* Add concurrent lookahead stream type `Ahead`
4+* Add `fromFoldableM` to create a stream from a container of monadic actions
4
5
5## 0.2.0
6## 0.2.0
6
7
benchmark/Linear.hs+9−2
@@ -15,13 +15,16 @@ import Gauge
15
15
16-- We need a monadic bind here to make sure that the function f does not get
16-- We need a monadic bind here to make sure that the function f does not get
17-- completely optimized out by the compiler in some cases.
17-- completely optimized out by the compiler in some cases.
18−benchIO :: (NFData b) => String -> (Ops.Stream m Int -> IO b) -> Benchmark
18+benchIO :: NFData b => String -> (Ops.Stream m Int -> IO b) -> Benchmark
19benchIO name f = bench name $ nfIO $ randomRIO (1,1000) >>= f . Ops.source
19benchIO name f = bench name $ nfIO $ randomRIO (1,1000) >>= f . Ops.source
20
20
21+benchSrcIO :: String -> (Int -> Ops.Stream IO Int) -> Benchmark
22+benchSrcIO name f = bench name $ nfIO $ randomRIO (1,1000) >>= Ops.toNull . f
23+
21benchIOAppend :: (NFData b) => String -> (Int -> IO b) -> Benchmark
24benchIOAppend :: (NFData b) => String -> (Int -> IO b) -> Benchmark
22benchIOAppend name f = bench name $ nfIO $ randomRIO (1,1000) >>= f
25benchIOAppend name f = bench name $ nfIO $ randomRIO (1,1000) >>= f
23
26
24−_benchId :: (NFData b) => String -> (Ops.Stream m Int -> Identity b) -> Benchmark
27+_benchId :: NFData b => String -> (Ops.Stream m Int -> Identity b) -> Benchmark
25_benchId name f = bench name $ nf (runIdentity . f) (Ops.source 10)
28_benchId name f = bench name $ nf (runIdentity . f) (Ops.source 10)
26
29
27main :: IO ()
30main :: IO ()
@@ -29,6 +32,10 @@ main = do
29 defaultMain
32 defaultMain
30 [ bgroup "elimination"
33 [ bgroup "elimination"
31 [ benchIO "toNull" Ops.toNull
34 [ benchIO "toNull" Ops.toNull
35+ , benchSrcIO "fromFoldable" Ops.sourceFromFoldable
36+ , benchSrcIO "fromFoldableM" Ops.sourceFromFoldableM
37+ , benchSrcIO "foldMapWith" Ops.sourceFoldMapWith
38+ , benchSrcIO "unfoldrM" Ops.sourceUnfoldrM
32 , benchIO "toList" Ops.toList
39 , benchIO "toList" Ops.toList
33 , benchIO "fold" Ops.foldl
40 , benchIO "fold" Ops.foldl
34 , benchIO "last" Ops.last
41 , benchIO "last" Ops.last
benchmark/LinearOps.hs+27−2
@@ -9,7 +9,7 @@ module LinearOps where
9
9
10import Prelude
10import Prelude
11 (Monad, Int, (+), ($), (.), return, fmap, even, (>), (<=),
11 (Monad, Int, (+), ($), (.), return, fmap, even, (>), (<=),
12− subtract, undefined, Maybe, Monoid, foldMap)
12+ subtract, undefined, Maybe(..), Monoid, foldMap)
13
13
14import qualified Streamly as S
14import qualified Streamly as S
15import qualified Streamly.Prelude as S
15import qualified Streamly.Prelude as S
@@ -61,8 +61,33 @@ last :: Monad m => Stream m Int -> m (Maybe Int)
61
61
62type Stream m a = S.SerialT m a
62type Stream m a = S.SerialT m a
63
63
64+{-# INLINE source #-}
64source :: Int -> Stream m Int
65source :: Int -> Stream m Int
66+source n = S.unfoldr step n
67+ where
68+ step cnt =
69+ if cnt > n + value
70+ then Nothing
71+ else (Just (cnt, cnt + 1))
72+
73+sourceFromFoldable :: Int -> Stream m Int
65−source n = S.fromFoldable [n..n+value]
74+sourceFromFoldable n = S.fromFoldable [n..n+value]
75+
76+{-# INLINE sourceFromFoldableM #-}
77+sourceFromFoldableM :: Monad m => Int -> Stream m Int
78+sourceFromFoldableM n = S.fromFoldableM (Prelude.fmap return [n..n+value])
79+
80+sourceFoldMapWith :: Monad m => Int -> Stream m Int
81+sourceFoldMapWith n = S.foldMapWith S.serial return [n..n+value]
82+
83+{-# INLINE sourceUnfoldrM #-}
84+sourceUnfoldrM :: Monad m => Int -> Stream m Int
85+sourceUnfoldrM n = S.unfoldrM step n
86+ where
87+ step cnt =
88+ if cnt > n + value
89+ then return Nothing
90+ else return (Just (cnt, cnt + 1))
66
91
67{-# INLINE runStream #-}
92{-# INLINE runStream #-}
68runStream :: Monad m => Stream m a -> m ()
93runStream :: Monad m => Stream m a -> m ()
benchmark/NestedOps.hs+6−1
@@ -29,7 +29,12 @@ type Stream m a = S.SerialT m a
29
29
30{-# INLINE source #-}
30{-# INLINE source #-}
31source :: S.IsStream t => Int -> Int -> t m Int
31source :: S.IsStream t => Int -> Int -> t m Int
32−source start n = S.fromFoldable [start..start+n]
32+source start n = S.unfoldr step start
33+ where
34+ step cnt =
35+ if cnt > start + n
36+ then Nothing
37+ else (Just (cnt, cnt + 1))
33
38
34{-# INLINE runStream #-}
39{-# INLINE runStream #-}
35runStream :: Monad m => Stream m a -> m ()
40runStream :: Monad m => Stream m a -> m ()
src/Streamly/Core.hs+11−8
@@ -228,21 +228,22 @@ newtype Stream m a =
228nil :: Stream m a
228nil :: Stream m a
229nil = Stream $ \_ stp _ _ -> stp
229nil = Stream $ \_ stp _ _ -> stp
230
230
231+-- | faster than consM because there is no bind.
231−once :: Monad m => m a -> Stream m a
232+cons :: a -> Stream m a -> Stream m a
232−once m = Stream $ \_ _ single _ -> m >>= single
233+cons a r = Stream $ \_ _ _ yld -> yld a r
233
234
234−{-# INLINE singleton #-}
235−-- | Same as @once . return@
235+-- | Same as @once . return@ but may be faster because there is no bind
236singleton :: a -> Stream m a
236singleton :: a -> Stream m a
237singleton a = Stream $ \_ _ single _ -> single a
237singleton a = Stream $ \_ _ single _ -> single a
238
238
239+{-# INLINE once #-}
240+once :: Monad m => m a -> Stream m a
241+once m = Stream $ \_ _ single _ -> m >>= single
242+
243+{-# INLINE consM #-}
239consM :: Monad m => m a -> Stream m a -> Stream m a
244consM :: Monad m => m a -> Stream m a -> Stream m a
240consM m r = Stream $ \_ _ _ yld -> m >>= \a -> yld a r
245consM m r = Stream $ \_ _ _ yld -> m >>= \a -> yld a r
241
246
242−-- | Same as @consM . return@
243−cons :: a -> Stream m a -> Stream m a
244−cons a r = Stream $ \_ _ _ yld -> yld a r
245−
246repeat :: a -> Stream m a
247repeat :: a -> Stream m a
247repeat a = let x = cons a x in x
248repeat a = let x = cons a x in x
248
249
@@ -252,6 +253,7 @@ repeat a = let x = cons a x in x
252
253
253-- | Concatenates two streams sequentially i.e. the first stream is
254-- | Concatenates two streams sequentially i.e. the first stream is
254-- exhausted completely before yielding any element from the second stream.
255-- exhausted completely before yielding any element from the second stream.
256+{-# INLINE serial #-}
255serial :: Stream m a -> Stream m a -> Stream m a
257serial :: Stream m a -> Stream m a -> Stream m a
256serial m1 m2 = go m1
258serial m1 m2 = go m1
257 where
259 where
@@ -276,6 +278,7 @@ instance Monoid (Stream m a) where
276-- Interleave
278-- Interleave
277------------------------------------------------------------------------------
279------------------------------------------------------------------------------
278
280
281+{-# INLINE wSerial #-}
279wSerial :: Stream m a -> Stream m a -> Stream m a
282wSerial :: Stream m a -> Stream m a -> Stream m a
280wSerial m1 m2 = Stream $ \_ stp sng yld -> do
283wSerial m1 m2 = Stream $ \_ stp sng yld -> do
281 let stop = (runStream m2) Nothing stp sng yld
284 let stop = (runStream m2) Nothing stp sng yld
src/Streamly/Prelude.hs+13−2
@@ -55,6 +55,7 @@ module Streamly.Prelude
55 , iterate
55 , iterate
56 , iterateM
56 , iterateM
57 , fromFoldable
57 , fromFoldable
58+ , fromFoldableM
58
59
59 -- * Deconstruction
60 -- * Deconstruction
60 , uncons
61 , uncons
@@ -145,6 +146,7 @@ import Streamly.Streams
145-- | Build a Stream by unfolding pure steps starting from a seed.
146-- | Build a Stream by unfolding pure steps starting from a seed.
146--
147--
147-- @since 0.1.0
148-- @since 0.1.0
149+{-# INLINE unfoldr #-}
148unfoldr :: IsStream t => (b -> Maybe (a, b)) -> b -> t m a
150unfoldr :: IsStream t => (b -> Maybe (a, b)) -> b -> t m a
149unfoldr step = fromStream . go
151unfoldr step = fromStream . go
150 where
152 where
@@ -156,6 +158,7 @@ unfoldr step = fromStream . go
156-- | Build a Stream by unfolding monadic steps starting from a seed.
158-- | Build a Stream by unfolding monadic steps starting from a seed.
157--
159--
158-- @since 0.1.0
160-- @since 0.1.0
161+{-# INLINE unfoldrM #-}
159unfoldrM :: (IsStream t, Monad m) => (b -> m (Maybe (a, b))) -> b -> t m a
162unfoldrM :: (IsStream t, Monad m) => (b -> m (Maybe (a, b))) -> b -> t m a
160unfoldrM step = fromStream . go
163unfoldrM step = fromStream . go
161 where
164 where
@@ -165,13 +168,20 @@ unfoldrM step = fromStream . go
165 Nothing -> stp
168 Nothing -> stp
166 Just (a, b) -> yld a (go b)
169 Just (a, b) -> yld a (go b)
167
170
168−-- | Construct a stream from a 'Foldable' container.
171+-- | Construct a stream from a 'Foldable' containing pure values.
169--
172--
170-- @since 0.2.0
173-- @since 0.2.0
171{-# INLINE fromFoldable #-}
174{-# INLINE fromFoldable #-}
172fromFoldable :: (IsStream t, Foldable f) => f a -> t m a
175fromFoldable :: (IsStream t, Foldable f) => f a -> t m a
173fromFoldable = Prelude.foldr cons nil
176fromFoldable = Prelude.foldr cons nil
174
177
178+-- | Construct a stream from a 'Foldable' containing monadic actions.
179+--
180+-- @since 0.3.0
181+{-# INLINE fromFoldableM #-}
182+fromFoldableM :: (IsStream t, Monad m, Foldable f) => f (m a) -> t m a
183+fromFoldableM = Prelude.foldr consM nil
184+
175-- | Same as 'fromFoldable'.
185-- | Same as 'fromFoldable'.
176--
186--
177-- @since 0.1.0
187-- @since 0.1.0
@@ -294,7 +304,8 @@ foldrM step acc m = go (toStream m)
294-- @since 0.2.0
304-- @since 0.2.0
295{-# INLINE scanx #-}
305{-# INLINE scanx #-}
296scanx :: IsStream t => (x -> a -> x) -> x -> (x -> b) -> t m a -> t m b
306scanx :: IsStream t => (x -> a -> x) -> x -> (x -> b) -> t m a -> t m b
307+scanx step begin done m =
297−scanx step begin done m = cons (done begin) $ fromStream $ go (toStream m) begin
308+ cons (done begin) $ fromStream $ go (toStream m) begin
298 where
309 where
299 go m1 !acc = Stream $ \_ stp sng yld ->
310 go m1 !acc = Stream $ \_ stp sng yld ->
300 let single a = sng (done $ step acc a)
311 let single a = sng (done $ step acc a)
src/Streamly/Streams.hs+1−1
@@ -190,7 +190,7 @@ infixr 5 |:
190infixr 5 `cons`
190infixr 5 `cons`
191
191
192-- | Construct a stream by adding a pure value at the head of an existing
192-- | Construct a stream by adding a pure value at the head of an existing
193−-- stream. Same as @consM . return@. For example:
193+-- stream. For pure values it can be faster than 'consM'. For example:
194--
194--
195-- @
195-- @
196-- > toList $ 1 \`cons` 2 \`cons` 3 \`cons` nil
196-- > toList $ 1 \`cons` 2 \`cons` 3 \`cons` nil