on master help sign in
add mapMaybe and mapMaybeM
e46d341Xiaokui Shu
Changelog.md+1
@@ -26,6 +26,7 @@
26 concurrently when used at appropriate stream types.
26 concurrently when used at appropriate stream types.
27* Added concurrent function application operators to run stages of a
27* Added concurrent function application operators to run stages of a
28 stream processing function application pipeline concurrently.
28 stream processing function application pipeline concurrently.
29+* Added two functions `mapMaybe` and `mapMaybeM`.
29
30
30## 0.2.0
31## 0.2.0
31
32
src/Streamly/Prelude.hs+29
@@ -100,12 +100,14 @@ module Streamly.Prelude
100 , takeWhile
100 , takeWhile
101 , drop
101 , drop
102 , dropWhile
102 , dropWhile
103+ , mapMaybe
103
104
104 -- * Reordering
105 -- * Reordering
105 , reverse
106 , reverse
106
107
107 -- * Mapping
108 -- * Mapping
108 , mapM
109 , mapM
110+ , mapMaybeM
109 , sequence
111 , sequence
110
112
111 -- * Zipping
113 -- * Zipping
@@ -129,6 +131,7 @@ where
129import Control.Monad (void)
131import Control.Monad (void)
130import Control.Monad.IO.Class (MonadIO(..))
132import Control.Monad.IO.Class (MonadIO(..))
131import Data.Semigroup (Semigroup(..))
133import Data.Semigroup (Semigroup(..))
134+import Data.Maybe (isJust, fromJust)
132import Prelude hiding (filter, drop, dropWhile, take,
135import Prelude hiding (filter, drop, dropWhile, take,
133 takeWhile, zipWith, foldr, foldl,
136 takeWhile, zipWith, foldr, foldl,
134 mapM, mapM_, sequence, all, any,
137 mapM, mapM_, sequence, all, any,
@@ -570,6 +573,24 @@ dropWhile p m = fromStream $ go (toStream m)
570 | otherwise = yld a r
573 | otherwise = yld a r
571 in (S.runStream m1) ctx stp single yield
574 in (S.runStream m1) ctx stp single yield
572
575
576+-- | Map + filter: compute a stream of b from a stream of a and filter out
577+-- elements that are mapped to Nothing. It is similar to 'mapMaybe' in
578+-- 'Data.Maybe' but applies to streams instead of list.
579+--
580+-- @since 0.2.1
581+{-# INLINE mapMaybe #-}
582+mapMaybe :: (IsStream t) => (a -> Maybe b) -> t m a -> t m b
583+mapMaybe f m = go (toStream m)
584+ where
585+ go m1 = fromStream $ Stream $ \_ stp sng yld ->
586+ let single a = case f a of
587+ Just b -> sng b
588+ Nothing -> stp
589+ yield a r = case f a of
590+ Just b -> yld b (toStream $ go r)
591+ Nothing -> (S.runStream r) Nothing stp single yield
592+ in (S.runStream m1) Nothing stp single yield
593+
573-- | Determine whether all elements of a stream satisfy a predicate.
594-- | Determine whether all elements of a stream satisfy a predicate.
574--
595--
575-- @since 0.1.0
596-- @since 0.1.0
@@ -750,6 +771,14 @@ mapM f m = go (toStream m)
750 yield a r = S.runStream (toStream (f a |: (go r))) svr stp sng yld
771 yield a r = S.runStream (toStream (f a |: (go r))) svr stp sng yld
751 in (S.runStream m1) Nothing stp single yield
772 in (S.runStream m1) Nothing stp single yield
752
773
774+-- | Monadic version mapMaybe.
775+--
776+-- @since 0.2.1
777+{-# INLINE mapMaybeM #-}
778+mapMaybeM :: (IsStream t, MonadAsync m, Functor (t m))
779+ => (a -> m (Maybe b)) -> t m a -> t m b
780+mapMaybeM f = fmap fromJust . filter isJust . mapM f
781+
753-- XXX this can utilize parallel mapping if we implement it as runStream . mapM
782-- XXX this can utilize parallel mapping if we implement it as runStream . mapM
754-- | Apply a monadic action to each element of the stream and discard the
783-- | Apply a monadic action to each element of the stream and discard the
755-- output of the action.
784-- output of the action.
test/Prop.hs+4
@@ -9,6 +9,7 @@ import Control.Applicative (ZipList(..))
9import Control.Concurrent (MVar, takeMVar, putMVar, newEmptyMVar)
9import Control.Concurrent (MVar, takeMVar, putMVar, newEmptyMVar)
10import Control.Monad (replicateM, replicateM_)
10import Control.Monad (replicateM, replicateM_)
11import Data.List (sort, foldl', scanl')
11import Data.List (sort, foldl', scanl')
12+import Data.Maybe (mapMaybe)
12import GHC.Word (Word8)
13import GHC.Word (Word8)
13
14
14import Test.Hspec.QuickCheck (prop)
15import Test.Hspec.QuickCheck (prop)
@@ -295,6 +296,9 @@ transformOps constr desc t eq = do
295 prop (desc ++ " takeWhile > 0") $
296 prop (desc ++ " takeWhile > 0") $
296 transform (takeWhile (> 0)) $ t . (A.takeWhile (> 0))
297 transform (takeWhile (> 0)) $ t . (A.takeWhile (> 0))
297
298
299+ let f x = if odd x then Just (x + 100) else Nothing
300+ prop (desc ++ " mapMaybe") $ transform (mapMaybe f) $ t . (A.mapMaybe f)
301+
298 prop (desc ++ " drop maxBound") $
302 prop (desc ++ " drop maxBound") $
299 transform (drop maxBound) $ t . (A.drop maxBound)
303 transform (drop maxBound) $ t . (A.drop maxBound)
300 prop (desc ++ " drop 0") $ transform (drop 0) $ t . (A.drop 0)
304 prop (desc ++ " drop 0") $ transform (drop 0) $ t . (A.drop 0)