on master help sign in
Merge pull request #76 from subbyte/master

mapMaybe and mapMaybeM Implemented

commit4c00da9ab4604e2e26c6e4a81b87b32e660baaa5 authorHarendra Kumar <harendra.kumar@gmail.com> dateWed 30 May 2018, 05:24 (8 years ago) parent54419aae46d341
3 files changed+34
Changelog.md+1 src/Streamly/Prelude.hs+29 test/Prop.hs+4
Changelog.md+1
@@ -24,6 +24,7 @@
2424 concurrently when used at appropriate stream types.
2525* Added concurrent function application operators to run stages of a
2626 stream processing function application pipeline concurrently.
27+* Added two functions `mapMaybe` and `mapMaybeM`.
2728
2829## 0.2.0
2930
src/Streamly/Prelude.hs+29
@@ -100,12 +100,14 @@ module Streamly.Prelude
100100 , takeWhile
101101 , drop
102102 , dropWhile
103+ , mapMaybe
103104
104105 -- * Reordering
105106 , reverse
106107
107108 -- * Mapping
108109 , mapM
110+ , mapMaybeM
109111 , sequence
110112
111113 -- * Zipping
@@ -129,6 +131,7 @@ where
129131import Control.Monad (void)
130132import Control.Monad.IO.Class (MonadIO(..))
131133import Data.Semigroup (Semigroup(..))
134+import Data.Maybe (isJust, fromJust)
132135import Prelude hiding (filter, drop, dropWhile, take,
133136 takeWhile, zipWith, foldr, foldl,
134137 mapM, mapM_, sequence, all, any,
@@ -577,6 +580,24 @@ dropWhile p m = fromStream $ go (toStream m)
577580 | otherwise = yld a r
578581 in (S.runStream m1) ctx stp single yield
579582
583+-- | Map + filter: compute a stream of b from a stream of a and filter out
584+-- elements that are mapped to Nothing. It is similar to 'mapMaybe' in
585+-- 'Data.Maybe' but applies to streams instead of list.
586+--
587+-- @since 0.2.1
588+{-# INLINE mapMaybe #-}
589+mapMaybe :: (IsStream t) => (a -> Maybe b) -> t m a -> t m b
590+mapMaybe f m = go (toStream m)
591+ where
592+ go m1 = fromStream $ Stream $ \_ stp sng yld ->
593+ let single a = case f a of
594+ Just b -> sng b
595+ Nothing -> stp
596+ yield a r = case f a of
597+ Just b -> yld b (toStream $ go r)
598+ Nothing -> (S.runStream r) Nothing stp single yield
599+ in (S.runStream m1) Nothing stp single yield
600+
580601-- | Determine whether all elements of a stream satisfy a predicate.
581602--
582603-- @since 0.1.0
@@ -757,6 +778,14 @@ mapM f m = go (toStream m)
757778 yield a r = S.runStream (toStream (f a |: (go r))) svr stp sng yld
758779 in (S.runStream m1) Nothing stp single yield
759780
781+-- | Monadic version mapMaybe.
782+--
783+-- @since 0.2.1
784+{-# INLINE mapMaybeM #-}
785+mapMaybeM :: (IsStream t, MonadAsync m, Functor (t m))
786+ => (a -> m (Maybe b)) -> t m a -> t m b
787+mapMaybeM f = fmap fromJust . filter isJust . mapM f
788+
760789-- XXX this can utilize parallel mapping if we implement it as runStream . mapM
761790-- | Apply a monadic action to each element of the stream and discard the
762791-- output of the action.
test/Prop.hs+4
@@ -9,6 +9,7 @@ import Control.Applicative (ZipList(..))
99import Control.Concurrent (MVar, takeMVar, putMVar, newEmptyMVar)
1010import Control.Monad (replicateM, replicateM_)
1111import Data.List (sort, foldl', scanl')
12+import Data.Maybe (mapMaybe)
1213import GHC.Word (Word8)
1314
1415import Test.Hspec.QuickCheck (prop)
@@ -295,6 +296,9 @@ transformOps constr desc t eq = do
295296 prop (desc ++ " takeWhile > 0") $
296297 transform (takeWhile (> 0)) $ t . (A.takeWhile (> 0))
297298
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+
298302 prop (desc ++ " drop maxBound") $
299303 transform (drop maxBound) $ t . (A.drop maxBound)
300304 prop (desc ++ " drop 0") $ transform (drop 0) $ t . (A.drop 0)