on master help sign in
Add concatMap, concatMapM, generateM, generate, findM to Prelude.
commit5bb0a49a9ad00a1d6a6ef55f32996184a1cad84e authorPranay Sashank <pranaysashank@gmail.com> dateWed 21 Nov 2018, 13:24 (8 years ago) parentb2c86b1
4 files changed+108−15
src/Streamly/Prelude.hs+33−1 src/Streamly/Streams/StreamD.hs+58−7 src/Streamly/Streams/StreamK.hs+14−7 test/Prop.hs+3
src/Streamly/Prelude.hs+33−1
@@ -91,6 +91,8 @@ module Streamly.Prelude
9191 -- ** Generate From
9292 -- | Convert an input structure, container or source into a stream. All of
9393 -- these can be expressed in terms of primitives.
94+ , generate
95+ , generateM
9496 , P.fromList
9597 , fromListM
9698 , K.fromFoldable
@@ -137,6 +139,7 @@ module Streamly.Prelude
137139 , elemIndex
138140 , notElem
139141 , lookup
142+ , findM
140143 , find
141144 , findIndex
142145 , all
@@ -146,6 +149,8 @@ module Streamly.Prelude
146149 , eqBy
147150 , cmpBy
148151 , (!!)
152+ , concatMapM
153+ , concatMap
149154
150155 -- Full folds - need to go through all elements
151156 , length
@@ -258,7 +263,7 @@ import Prelude
258263 foldl, mapM, mapM_, sequence, all, any, sum, product, elem,
259264 notElem, maximum, minimum, head, last, tail, length, null,
260265 reverse, iterate, init, and, or, lookup, foldr1, (!!),
261− splitAt, scanl, scanl1, replicate)
266+ splitAt, scanl, scanl1, replicate, concatMap)
262267import qualified Prelude
263268import qualified System.IO as IO
264269
@@ -403,6 +408,19 @@ yield = K.yield
403408yieldM :: (Monad m, IsStream t) => m a -> t m a
404409yieldM = K.yieldM
405410
411+-- | Generate a stream of given length, from a given pure
412+-- function of its indices.
413+{-# INLINE generate #-}
414+generate :: (IsStream t, Monad m) => Int -> (Int -> a) -> t m a
415+generate n = fromStreamD . D.generate n
416+
417+-- | Generate a stream of given length, from a given monadic
418+-- function of its indices.
419+--
420+{-# INLINE generateM #-}
421+generateM :: (IsStream t, Monad m) => Int -> (Int -> m a) -> t m a
422+generateM n = fromStreamD . D.generateM n
423+
406424-- | Generate a stream by performing a monadic action @n@ times. Can be
407425-- expressed as @stimes n (yieldM m)@.
408426--
@@ -769,6 +787,12 @@ lookup a m = S.lookup a (toStreamS m)
769787find :: Monad m => (a -> Bool) -> SerialT m a -> m (Maybe a)
770788find p m = S.find p (toStreamS m)
771789
790+-- | Like 'find' but with a monadic predicate.
791+--
792+{-# INLINE findM #-}
793+findM :: Monad m => (a -> m Bool) -> SerialT m a -> m (Maybe a)
794+findM p m = S.findM p (toStreamS m)
795+
772796-- | Find all the indices where the element in the stream satisfies the given
773797-- predicate.
774798--
@@ -800,6 +824,14 @@ elemIndices a = findIndices (==a)
800824elemIndex :: (Monad m, Eq a) => a -> SerialT m a -> m (Maybe Int)
801825elemIndex a = findIndex (==a)
802826
827+{-# INLINE concatMap #-}
828+concatMap :: Monad m => (a -> SerialT m b) -> SerialT m a -> SerialT m b
829+concatMap f m = fromStreamD $ D.concatMap (toStreamD . f) (toStreamD m)
830+
831+{-# INLINE concatMapM #-}
832+concatMapM :: Monad m => (a -> m (SerialT m b)) -> SerialT m a -> SerialT m b
833+concatMapM f m = fromStreamD $ D.concatMapM (fmap toStreamD . f) (toStreamD m)
834+
803835------------------------------------------------------------------------------
804836-- Substreams
805837------------------------------------------------------------------------------
src/Streamly/Streams/StreamD.hs+58−7
@@ -58,6 +58,8 @@ module Streamly.Streams.StreamD
5858 -- | Direct style stream does not support @fromFoldable@.
5959 , yield
6060 , yieldM
61+ , generate
62+ , generateM
6163 , fromList
6264 , fromListM
6365 , fromStreamK
@@ -87,8 +89,11 @@ module Streamly.Streams.StreamD
8789 , minimumBy
8890 , findIndices
8991 , lookup
92+ , findM
9093 , find
9194 , (!!)
95+ , concatMapM
96+ , concatMap
9297
9398 -- ** Substreams
9499 , isPrefixOf
@@ -162,7 +167,7 @@ import Prelude
162167 hiding (map, mapM, mapM_, repeat, foldr, last, take, filter,
163168 takeWhile, drop, dropWhile, all, any, maximum, minimum, elem,
164169 notElem, null, head, tail, zipWith, lookup, foldr1, sequence,
165− (!!), scanl, scanl1)
170+ (!!), scanl, scanl1, concatMap)
166171
167172import Streamly.SVar (MonadAsync, State(..), defState, rstState)
168173
@@ -285,6 +290,20 @@ yieldM m = Stream step True
285290 step _ True = m >>= \x -> return $ Yield x False
286291 step _ False = return Stop
287292
293+{-# INLINE generate #-}
294+generate :: Monad m => Int -> (Int -> a) -> Stream m a
295+generate n gen = generateM n (return . gen)
296+
297+{-# INLINE_NORMAL generateM #-}
298+generateM :: Monad m => Int -> (Int -> m a) -> Stream m a
299+generateM n gen = n `seq` Stream step 0
300+ where
301+ {-# INLINE_LATE step #-}
302+ step _ i | i < n = do
303+ x <- gen i
304+ return $ Yield x (i+1)
305+ | otherwise = return Stop
306+
288307-- XXX we need the MonadAsync constraint because of a rewrite rule.
289308-- | Convert a list of monadic actions to a 'Stream'
290309{-# INLINE_LATE fromListM #-}
@@ -562,17 +581,23 @@ lookup e (Stream step state) = go state
562581 Skip s -> go s
563582 Stop -> return Nothing
564583
565−{-# INLINE_NORMAL find #-}
566−find :: Monad m => (a -> Bool) -> Stream m a -> m (Maybe a)
567−find p (Stream step state) = go state
584+{-# INLINE_NORMAL findM #-}
585+findM :: Monad m => (a -> m Bool) -> Stream m a -> m (Maybe a)
586+findM p (Stream step state) = go SPEC state
568587 where
569− go st = do
588+ go !_ st = do
570589 r <- step defState st
571590 case r of
572− Yield x s -> if p x then return (Just x) else go s
573− Skip s -> go s
591+ Yield x s -> do
592+ b <- p x
593+ if b then return (Just x) else go SPEC s
594+ Skip s -> go SPEC s
574595 Stop -> return Nothing
575596
597+{-# INLINE find #-}
598+find :: Monad m => (a -> Bool) -> Stream m a -> m (Maybe a)
599+find p = findM (return . p)
600+
576601{-# INLINE_NORMAL findIndices #-}
577602findIndices :: Monad m => (a -> Bool) -> Stream m a -> Stream m Int
578603findIndices p (Stream step state) = Stream step' (state, 0)
@@ -585,6 +610,32 @@ findIndices p (Stream step state) = Stream step' (state, 0)
585610 Skip s -> Skip (s, i+1)
586611 Stop -> Stop
587612
613+{-# INLINE concatMap #-}
614+concatMap :: Monad m => (a -> Stream m b) -> Stream m a -> Stream m b
615+concatMap f = concatMapM (return . f)
616+
617+{-# INLINE_NORMAL concatMapM #-}
618+concatMapM :: Monad m => (a -> m (Stream m b)) -> Stream m a -> Stream m b
619+concatMapM f (Stream step state) = Stream step' (Left state)
620+ where
621+ step' gst (Left st) = do
622+ r <- step (rstState gst) st
623+ case r of
624+ Yield a s -> do
625+ b_stream <- f a
626+ return $ Skip (Right (b_stream, s))
627+ Skip s -> return $ Skip (Left s)
628+ Stop -> return Stop
629+
630+ step' _ (Right (Stream inner_step inner_st, st)) = do
631+ r <- inner_step defState inner_st
632+ case r of
633+ Yield b inner_s ->
634+ return $ Yield b (Right (Stream inner_step inner_s, st))
635+ Skip inner_s ->
636+ return $ Skip (Right (Stream inner_step inner_s, st))
637+ Stop -> return $ Skip (Left st)
638+
588639------------------------------------------------------------------------------
589640-- Substreams
590641------------------------------------------------------------------------------
src/Streamly/Streams/StreamK.hs+14−7
@@ -95,6 +95,7 @@ module Streamly.Streams.StreamK
9595 , maximumBy
9696 , findIndices
9797 , lookup
98+ , findM
9899 , find
99100 , (!!)
100101
@@ -802,17 +803,23 @@ lookup e m = go (toStream m)
802803 | otherwise = go x
803804 in unStream m1 defState (return Nothing) single yieldk
804805
805−{-# INLINE find #-}
806−find :: (IsStream t, Monad m) => (a -> Bool) -> t m a -> m (Maybe a)
807−find p m = go (toStream m)
806+{-# INLINE findM #-}
807+findM :: (IsStream t, Monad m) => (a -> m Bool) -> t m a -> m (Maybe a)
808+findM p m = go (toStream m)
808809 where
809810 go m1 =
810− let single a | p a = return $ Just a
811− | otherwise = return Nothing
812− yieldk a x | p a = return $ Just a
813− | otherwise = go x
811+ let single a = do
812+ b <- p a
813+ if b then return $ Just a else return Nothing
814+ yieldk a x = do
815+ b <- p a
816+ if b then return $ Just a else go x
814817 in unStream m1 defState (return Nothing) single yieldk
815818
819+{-# INLINE find #-}
820+find :: (IsStream t, Monad m) => (a -> Bool) -> t m a -> m (Maybe a)
821+find p = findM (return . p)
822+
816823{-# INLINE findIndices #-}
817824findIndices :: IsStream t => (a -> Bool) -> t m a -> t m Int
818825findIndices p = fromStream . go 0 . toStream
test/Prop.hs+3
@@ -404,6 +404,9 @@ transformOps constr desc eq t = do
404404 prop (desc <> " deleteBy (==) 4") $
405405 transform (deleteBy (==) 4) $ t . S.deleteBy (==) 4
406406
407+ prop (desc <> " concatMap") $ transform (concatMap (const [1..10])) $
408+ t . (\g -> adapt (S.concatMap (const (S.fromList [1..10])) (adapt g)))
409+
407410concurrentOps
408411 :: IsStream t
409412 => ([Word8] -> t IO Word8)