on master help sign in
Merge pull request #95 from Veladus/approved-prelude-functions
9b87957Harendra Kumar
Changelog.md+7
@@ -1,3 +1,10 @@
1+## Unreleased
2+
3+### Enhancements
4+
5+* Add `foldl1'`, `foldr1`, `intersperseM`, `find`, `lookup`, `and`, `or`,
6+ `findIndices`, `findIndex`, `elemIndices`, `elemIndex`, `init` to Prelude
7+
1## 0.4.1
8## 0.4.1
2
9
3### Bug Fixes
10### Bug Fixes
src/Streamly/Prelude.hs+93−1
@@ -82,8 +82,10 @@ module Streamly.Prelude
82 -- * Elimination
82 -- * Elimination
83 -- ** General Folds
83 -- ** General Folds
84 , foldr
84 , foldr
85+ , foldr1
85 , foldrM
86 , foldrM
86 , foldl'
87 , foldl'
88+ , foldl1'
87 , foldlM'
89 , foldlM'
88 , foldx
90 , foldx
89 , foldxM
91 , foldxM
@@ -93,15 +95,27 @@ module Streamly.Prelude
93 , head
95 , head
94 , tail
96 , tail
95 , last
97 , last
98+ , init
96 , elem
99 , elem
97 , notElem
100 , notElem
98 , length
101 , length
99 , all
102 , all
100 , any
103 , any
104+ , and
105+ , or
101 , maximum
106 , maximum
102 , minimum
107 , minimum
103 , sum
108 , sum
104 , product
109 , product
110+ , lookup
111+ , find
112+
113+ -- *** Indices
114+ , findIndices
115+ , findIndex
116+ , elemIndices
117+ , elemIndex
118+
105
119
106 -- ** Map and Fold
120 -- ** Map and Fold
107 , mapM_
121 , mapM_
@@ -139,6 +153,9 @@ module Streamly.Prelude
139 -- ** Reordering
153 -- ** Reordering
140 , reverse
154 , reverse
141
155
156+ -- ** Inserting
157+ , intersperseM
158+
142 -- * Zipping
159 -- * Zipping
143 , zipWith
160 , zipWith
144 , zipWithM
161 , zipWithM
@@ -160,7 +177,7 @@ import Prelude
160 hiding (filter, drop, dropWhile, take, takeWhile, zipWith, foldr,
177 hiding (filter, drop, dropWhile, take, takeWhile, zipWith, foldr,
161 foldl, map, mapM, mapM_, sequence, all, any, sum, product, elem,
178 foldl, map, mapM, mapM_, sequence, all, any, sum, product, elem,
162 notElem, maximum, minimum, head, last, tail, length, null,
179 notElem, maximum, minimum, head, last, tail, length, null,
163− reverse, iterate)
180+ reverse, iterate, init, and, or, lookup, foldr1)
164import qualified Prelude
181import qualified Prelude
165import qualified System.IO as IO
182import qualified System.IO as IO
166
183
@@ -450,6 +467,12 @@ foldr :: Monad m => (a -> b -> b) -> b -> SerialT m a -> m b
450-- foldr step acc m = S.foldr step acc $ S.fromStreamK (toStream m)
467-- foldr step acc m = S.foldr step acc $ S.fromStreamK (toStream m)
451foldr f = foldrM (\a b -> return (f a b))
468foldr f = foldrM (\a b -> return (f a b))
452
469
470+-- | Right fold, for non-empty streams, using first element as the starting
471+-- value. Returns 'Nothing' if the stream is empty.
472+{-# INLINE foldr1 #-}
473+foldr1 :: Monad m => (a -> a -> a) -> SerialT m a -> m (Maybe a)
474+foldr1 = K.foldr1
475+
453-- | Strict left fold with an extraction function. Like the standard strict
476-- | Strict left fold with an extraction function. Like the standard strict
454-- left fold, but applies a user supplied extraction function (the third
477-- left fold, but applies a user supplied extraction function (the third
455-- argument) to the folded value at the end. This is designed to work with the
478-- argument) to the folded value at the end. This is designed to work with the
@@ -473,6 +496,17 @@ foldl = foldx
473foldl' :: Monad m => (b -> a -> b) -> b -> SerialT m a -> m b
496foldl' :: Monad m => (b -> a -> b) -> b -> SerialT m a -> m b
474foldl' step begin m = S.foldl' step begin $ toStreamS m
497foldl' step begin m = S.foldl' step begin $ toStreamS m
475
498
499+-- | Strict left fold, for non-empty streams, using first element as the
500+-- starting value. Returns 'Nothing' if the stream is empty.
501+foldl1' :: Monad m => (a -> a -> a) -> (a -> b) -> SerialT m a -> m (Maybe b)
502+foldl1' step done m = do
503+ r <- uncons m
504+ case r of
505+ Nothing -> return Nothing
506+ Just (h, t) -> do
507+ res <- foldl' step h t
508+ return $ Just $ done res
509+
476-- XXX replace the recursive "go" with explicit continuations.
510-- XXX replace the recursive "go" with explicit continuations.
477-- | Like 'foldx', but with a monadic step function.
511-- | Like 'foldx', but with a monadic step function.
478--
512--
@@ -517,6 +551,11 @@ head m = K.head m
517tail :: (IsStream t, Monad m) => SerialT m a -> m (Maybe (t m a))
551tail :: (IsStream t, Monad m) => SerialT m a -> m (Maybe (t m a))
518tail m = K.tail (K.adapt m)
552tail m = K.tail (K.adapt m)
519
553
554+-- | Extract all but the last element of the stream, if any.
555+{-# INLINE init #-}
556+init :: (IsStream t, Monad m) => SerialT m a -> m (Maybe (t m a))
557+init m = K.init (K.adapt m)
558+
520-- | Extract the last element of the stream, if any.
559-- | Extract the last element of the stream, if any.
521--
560--
522-- @since 0.1.1
561-- @since 0.1.1
@@ -559,6 +598,16 @@ all p m = S.all p (toStreamS m)
559any :: Monad m => (a -> Bool) -> SerialT m a -> m Bool
598any :: Monad m => (a -> Bool) -> SerialT m a -> m Bool
560any p m = S.any p (toStreamS m)
599any p m = S.any p (toStreamS m)
561
600
601+-- | Determines if all elements of a boolean stream are True.
602+{-# INLINE and #-}
603+and :: Monad m => SerialT m Bool -> m Bool
604+and = all (==True)
605+
606+-- | Determines wheter at least one element of a boolean stream is True.
607+{-# INLINE or #-}
608+or :: Monad m => SerialT m Bool -> m Bool
609+or = any (==True)
610+
562-- | Determine the sum of all elements of a stream of numbers
611-- | Determine the sum of all elements of a stream of numbers
563--
612--
564-- @since 0.1.0
613-- @since 0.1.0
@@ -587,6 +636,39 @@ minimum m = S.minimum (toStreamS m)
587maximum :: (Monad m, Ord a) => SerialT m a -> m (Maybe a)
636maximum :: (Monad m, Ord a) => SerialT m a -> m (Maybe a)
588maximum m = S.maximum (toStreamS m)
637maximum m = S.maximum (toStreamS m)
589
638
639+-- | Looks the given key up, treating the given stream as an association list.
640+{-# INLINE lookup #-}
641+lookup :: (Monad m, Eq a) => a -> SerialT m (a, b) -> m (Maybe b)
642+lookup = K.lookup
643+
644+-- | Returns the first element of the stream satisfying the given predicate,
645+-- if any.
646+{-# INLINE find #-}
647+find :: Monad m => (a -> Bool) -> SerialT m a -> m (Maybe a)
648+find = K.find
649+
650+-- | Finds all the indices of elements satisfying the given predicate.
651+{-# INLINE findIndices #-}
652+findIndices :: IsStream t => (a -> Bool) -> t m a -> t m Int
653+findIndices = K.findIndices
654+
655+-- | Gives the index of the first stream element satisfying the given
656+-- preficate.
657+{-# INLINE findIndex #-}
658+findIndex :: Monad m => (a -> Bool) -> SerialT m a -> m (Maybe Int)
659+findIndex p = head . findIndices p
660+
661+-- | Finds the index of all elements in the stream which are equal to the
662+-- given.
663+{-# INLINE elemIndices #-}
664+elemIndices :: (IsStream t, Eq a) => a -> t m a -> t m Int
665+elemIndices a = findIndices (==a)
666+
667+-- | Gives the first index of an element in the stream, which equals the given.
668+{-# INLINE elemIndex #-}
669+elemIndex :: (Monad m, Eq a) => a -> SerialT m a -> m (Maybe Int)
670+elemIndex a = findIndex (==a)
671+
590------------------------------------------------------------------------------
672------------------------------------------------------------------------------
591-- Map and Fold
673-- Map and Fold
592------------------------------------------------------------------------------
674------------------------------------------------------------------------------
@@ -812,6 +894,16 @@ reverse m = fromStream $ go K.nil (toStream m)
812 yieldk a r = runIt $ go (a `K.cons` rev) r
894 yieldk a r = runIt $ go (a `K.cons` rev) r
813 in K.unStream rest (rstState st) stop single yieldk
895 in K.unStream rest (rstState st) stop single yieldk
814
896
897+------------------------------------------------------------------------------
898+-- Transformation by Inserting
899+------------------------------------------------------------------------------
900+
901+-- | Generate a stream by performing the monadic action inbetween all elements
902+-- of the given stream.
903+{-# INLINE intersperseM #-}
904+intersperseM :: (IsStream t, MonadAsync m) => m a -> t m a -> t m a
905+intersperseM = K.intersperseM
906+
815------------------------------------------------------------------------------
907------------------------------------------------------------------------------
816-- Zipping
908-- Zipping
817------------------------------------------------------------------------------
909------------------------------------------------------------------------------
src/Streamly/Streams/StreamK.hs+87−1
@@ -71,6 +71,7 @@ module Streamly.Streams.StreamK
71 , foldStream
71 , foldStream
72 , foldr
72 , foldr
73 , foldrM
73 , foldrM
74+ , foldr1
74 , foldl'
75 , foldl'
75 , foldlM'
76 , foldlM'
76 , foldx
77 , foldx
@@ -81,6 +82,7 @@ module Streamly.Streams.StreamK
81 , null
82 , null
82 , head
83 , head
83 , tail
84 , tail
85+ , init
84 , elem
86 , elem
85 , notElem
87 , notElem
86 , all
88 , all
@@ -88,6 +90,9 @@ module Streamly.Streams.StreamK
88 , last
90 , last
89 , minimum
91 , minimum
90 , maximum
92 , maximum
93+ , findIndices
94+ , lookup
95+ , find
91
96
92 -- ** Map and Fold
97 -- ** Map and Fold
93 , mapM_
98 , mapM_
@@ -113,6 +118,9 @@ module Streamly.Streams.StreamK
113 , mapM
118 , mapM
114 , sequence
119 , sequence
115
120
121+ -- ** Inserting
122+ , intersperseM
123+
116 -- ** Map and Filter
124 -- ** Map and Filter
117 , mapMaybe
125 , mapMaybe
118
126
@@ -141,7 +149,8 @@ import Data.Semigroup (Semigroup(..))
141import Prelude
149import Prelude
142 hiding (foldl, foldr, last, map, mapM, mapM_, repeat, sequence,
150 hiding (foldl, foldr, last, map, mapM, mapM_, repeat, sequence,
143 take, filter, all, any, takeWhile, drop, dropWhile, minimum,
151 take, filter, all, any, takeWhile, drop, dropWhile, minimum,
144− maximum, elem, notElem, null, head, tail, zipWith)
152+ maximum, elem, notElem, null, head, tail, init, zipWith, lookup,
153+ foldr1)
145import qualified Prelude
154import qualified Prelude
146
155
147import Streamly.SVar
156import Streamly.SVar
@@ -485,6 +494,20 @@ foldrM step acc m = go (toStream m)
485 yieldk a r = go r >>= step a
494 yieldk a r = go r >>= step a
486 in (unStream m1) defState stop single yieldk
495 in (unStream m1) defState stop single yieldk
487
496
497+{-# INLINE foldr1 #-}
498+foldr1 :: (IsStream t, Monad m) => (a -> a -> a) -> t m a -> m (Maybe a)
499+foldr1 step m = do
500+ r <- uncons m
501+ case r of
502+ Nothing -> return Nothing
503+ Just (h, t) -> go h (toStream t) >>= return . Just
504+ where
505+ go p m1 =
506+ let stp = return p
507+ single a = return $ step a p
508+ yieldk a r = go a r >>= return . (step p)
509+ in unStream m1 defState stp single yieldk
510+
488-- | Strict left fold with an extraction function. Like the standard strict
511-- | Strict left fold with an extraction function. Like the standard strict
489-- left fold, but applies a user supplied extraction function (the third
512-- left fold, but applies a user supplied extraction function (the third
490-- argument) to the folded value at the end. This is designed to work with the
513-- argument) to the folded value at the end. This is designed to work with the
@@ -570,6 +593,20 @@ tail m =
570 yieldk _ r = return $ Just $ fromStream r
593 yieldk _ r = return $ Just $ fromStream r
571 in unStream (toStream m) defState stop single yieldk
594 in unStream (toStream m) defState stop single yieldk
572
595
596+{-# INLINE init #-}
597+init :: (IsStream t, Monad m) => t m a -> m (Maybe (t m a))
598+init m = go1 (toStream m)
599+ where
600+ go1 m1 = do
601+ r <- uncons m1
602+ case r of
603+ Nothing -> return Nothing
604+ Just (h, t) -> return . Just . fromStream $ go h t
605+ go p m1 = Stream $ \_ stp sng yld ->
606+ let single _ = sng p
607+ yieldk a x = yld p $ go a x
608+ in unStream m1 defState stp single yieldk
609+
573{-# INLINE elem #-}
610{-# INLINE elem #-}
574elem :: (IsStream t, Monad m, Eq a) => a -> t m a -> m Bool
611elem :: (IsStream t, Monad m, Eq a) => a -> t m a -> m Bool
575elem e m = go (toStream m)
612elem e m = go (toStream m)
@@ -659,6 +696,39 @@ maximum m = go Nothing (toStream m)
659 else go (Just res) r
696 else go (Just res) r
660 in unStream m1 defState stop single yieldk
697 in unStream m1 defState stop single yieldk
661
698
699+{-# INLINE lookup #-}
700+lookup :: (IsStream t, Monad m, Eq a) => a -> t m (a, b) -> m (Maybe b)
701+lookup e m = go (toStream m)
702+ where
703+ go m1 =
704+ let single (a, b) | a == e = return $ Just b
705+ | otherwise = return Nothing
706+ yieldk (a, b) x | a == e = return $ Just b
707+ | otherwise = go x
708+ in unStream m1 defState (return Nothing) single yieldk
709+
710+{-# INLINE find #-}
711+find :: (IsStream t, Monad m) => (a -> Bool) -> t m a -> m (Maybe a)
712+find p m = go (toStream m)
713+ where
714+ go m1 =
715+ let single a | p a = return $ Just a
716+ | otherwise = return Nothing
717+ yieldk a x | p a = return $ Just a
718+ | otherwise = go x
719+ in unStream m1 defState (return Nothing) single yieldk
720+
721+{-# INLINE findIndices #-}
722+findIndices :: IsStream t => (a -> Bool) -> t m a -> t m Int
723+findIndices p = fromStream . go 0 . toStream
724+ where
725+ go offset m1 = Stream $ \st stp sng yld ->
726+ let single a | p a = sng offset
727+ | otherwise = stp
728+ yieldk a x | p a = yld offset $ go (offset + 1) x
729+ | otherwise = unStream (go (offset + 1) x) st stp sng yld
730+ in unStream m1 (rstState st) stp single yieldk
731+
662------------------------------------------------------------------------------
732------------------------------------------------------------------------------
663-- Map and Fold
733-- Map and Fold
664------------------------------------------------------------------------------
734------------------------------------------------------------------------------
@@ -798,6 +868,22 @@ sequence m = go (toStream m)
798 yieldk ma r = unStream (toStream $ ma |: go r) st stp sng yld
868 yieldk ma r = unStream (toStream $ ma |: go r) st stp sng yld
799 in (unStream m1) (rstState st) stp single yieldk
869 in (unStream m1) (rstState st) stp single yieldk
800
870
871+-------------------------------------------------------------------------------
872+-- Inserting
873+-------------------------------------------------------------------------------
874+
875+{-# INLINE intersperseM #-}
876+intersperseM :: (IsStream t, MonadAsync m) => m a -> t m a -> t m a
877+intersperseM a m = fromStream $ prependingStart (toStream m)
878+ where
879+ prependingStart m1 = Stream $ \st stp sng yld ->
880+ let yieldk i x = unStream (return i |: go x) st stp sng yld
881+ in unStream m1 (rstState st) stp sng yieldk
882+ go m2 = fromStream $ Stream $ \st stp sng yld ->
883+ let single i = unStream (a |: yield i) st stp sng yld
884+ yieldk i x = unStream (a |: return i |: go x) st stp sng yld
885+ in unStream m2 (rstState st) stp single yieldk
886+
801-------------------------------------------------------------------------------
887-------------------------------------------------------------------------------
802-- Map and Filter
888-- Map and Filter
803-------------------------------------------------------------------------------
889-------------------------------------------------------------------------------
test/Prop.hs+38−10
@@ -9,7 +9,8 @@ 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.IORef (readIORef, modifyIORef, newIORef)
11import Data.IORef (readIORef, modifyIORef, newIORef)
12−import Data.List (sort, foldl', scanl')
12+import Data.List (sort, foldl', scanl', findIndices, findIndex, elemIndices,
13+ elemIndex, find, intersperse, foldl1')
13import Data.Maybe (mapMaybe)
14import Data.Maybe (mapMaybe)
14import GHC.Word (Word8)
15import GHC.Word (Word8)
15
16
@@ -63,11 +64,12 @@ constructWithReplicateM op thr buf len = withMaxSuccess maxTestCount $
63 equals (==) stream list
64 equals (==) stream list
64
65
65transformFromList
66transformFromList
67+ :: Show b =>
66− :: ([Int] -> t IO Int)
68+ ([a] -> t IO a)
67− -> ([Int] -> [Int] -> Bool)
69+ -> ([b] -> [b] -> Bool)
68− -> ([Int] -> [Int])
70+ -> ([a] -> [b])
69− -> (t IO Int -> SerialT IO Int)
71+ -> (t IO a -> SerialT IO b)
70− -> [Int]
72+ -> [a]
71 -> Property
73 -> Property
72transformFromList constr eq listOp op a =
74transformFromList constr eq listOp op a =
73 monadicIO $ do
75 monadicIO $ do
@@ -264,10 +266,10 @@ foldFromList constr op eq a = transformFromList constr eq id op a
264
266
265eliminateOp
267eliminateOp
266 :: (Show a, Eq a)
268 :: (Show a, Eq a)
267− => ([Int] -> t IO Int)
269+ => ([s] -> t IO s)
268− -> ([Int] -> a)
270+ -> ([s] -> a)
269− -> (t IO Int -> IO a)
271+ -> (t IO s -> IO a)
270− -> [Int]
272+ -> [s]
271 -> Property
273 -> Property
272eliminateOp constr listOp op a =
274eliminateOp constr listOp op a =
273 monadicIO $ do
275 monadicIO $ do
@@ -347,6 +349,12 @@ transformOps constr desc t eq = do
347 prop (desc ++ " scan") $ transform (scanl' (+) 0) $ t . (S.scanl' (+) 0)
349 prop (desc ++ " scan") $ transform (scanl' (+) 0) $ t . (S.scanl' (+) 0)
348 prop (desc ++ " reverse") $ transform reverse $ t . S.reverse
350 prop (desc ++ " reverse") $ transform reverse $ t . S.reverse
349
351
352+ prop (desc ++ " findIndices") $ transform (findIndices odd) $ t . (S.findIndices odd)
353+ prop (desc ++ " elemIndices") $ transform (elemIndices 3) $ t . (S.elemIndices 3)
354+
355+ prop (desc ++ " intersperseM") $ transform (intersperse 3) $ t . (S.intersperseM (return 3))
356+
357+
350concurrentOps
358concurrentOps
351 :: IsStream t
359 :: IsStream t
352 => ([Word8] -> t IO Word8)
360 => ([Word8] -> t IO Word8)
@@ -432,6 +440,9 @@ transformCombineOpsCommon constr desc t eq = do
432 (S.scanlM' (\_ a -> return a) 0)
440 (S.scanlM' (\_ a -> return a) 0)
433 prop (desc ++ " reverse") $ transform reverse t S.reverse
441 prop (desc ++ " reverse") $ transform reverse t S.reverse
434
442
443+ prop (desc ++ " intersperseM") $
444+ transform (intersperse 3) t (S.intersperseM $ return 3)
445+
435transformCombineOpsOrdered
446transformCombineOpsOrdered
436 :: (IsStream t, Semigroup (t IO Int))
447 :: (IsStream t, Semigroup (t IO Int))
437 => ([Int] -> t IO Int)
448 => ([Int] -> t IO Int)
@@ -472,6 +483,10 @@ eliminationOps constr desc t = do
472 prop (desc ++ " null") $ eliminateOp constr null $ S.null . t
483 prop (desc ++ " null") $ eliminateOp constr null $ S.null . t
473 prop (desc ++ " foldl") $
484 prop (desc ++ " foldl") $
474 eliminateOp constr (foldl' (+) 0) $ (S.foldl' (+) 0) . t
485 eliminateOp constr (foldl' (+) 0) $ (S.foldl' (+) 0) . t
486+ prop (desc ++ " foldl1") $
487+ eliminateOp constr (wrapMaybe $ foldl1' (+)) $ (S.foldl1' (+) id) . t
488+ prop (desc ++ " foldr1") $
489+ eliminateOp constr (wrapMaybe $ foldr1 (+)) $ (S.foldr1 (+)) . t
475 prop (desc ++ " all") $ eliminateOp constr (all even) $ (S.all even) . t
490 prop (desc ++ " all") $ eliminateOp constr (all even) $ (S.all even) . t
476 prop (desc ++ " any") $ eliminateOp constr (any even) $ (S.any even) . t
491 prop (desc ++ " any") $ eliminateOp constr (any even) $ (S.any even) . t
477 prop (desc ++ " length") $ eliminateOp constr length $ S.length . t
492 prop (desc ++ " length") $ eliminateOp constr length $ S.length . t
@@ -481,6 +496,14 @@ eliminationOps constr desc t = do
481 prop (desc ++ " maximum") $ eliminateOp constr (wrapMaybe maximum) $ S.maximum . t
496 prop (desc ++ " maximum") $ eliminateOp constr (wrapMaybe maximum) $ S.maximum . t
482 prop (desc ++ " minimum") $ eliminateOp constr (wrapMaybe minimum) $ S.minimum . t
497 prop (desc ++ " minimum") $ eliminateOp constr (wrapMaybe minimum) $ S.minimum . t
483
498
499+ prop (desc ++ " findIndex") $ eliminateOp constr (findIndex odd) $ (S.findIndex odd) . t
500+ prop (desc ++ " elemIndex") $ eliminateOp constr (elemIndex 3) $ (S.elemIndex 3) . t
501+
502+ prop (desc ++ " find") $ eliminateOp constr (find even) $ (S.find even) . t
503+ prop (desc ++ " lookup") $
504+ eliminateOp constr (lookup 3 . flip zip [1..]) $
505+ S.lookup 3 . S.zipWith (\a b -> (b, a)) (S.fromList [(1::Int)..]) . t
506+
484-- head/tail/last may depend on the order in case of parallel streams
507-- head/tail/last may depend on the order in case of parallel streams
485-- so we test these only for serial streams.
508-- so we test these only for serial streams.
486serialEliminationOps
509serialEliminationOps
@@ -496,6 +519,11 @@ serialEliminationOps constr desc t = do
496 Nothing -> return Nothing
519 Nothing -> return Nothing
497 Just s -> S.toList s >>= return . Just
520 Just s -> S.toList s >>= return . Just
498 prop (desc ++ " last") $ eliminateOp constr (wrapMaybe last) $ S.last . t
521 prop (desc ++ " last") $ eliminateOp constr (wrapMaybe last) $ S.last . t
522+ prop (desc ++ " init") $ eliminateOp constr (wrapMaybe init) $ \x -> do
523+ r <- S.init (t x)
524+ case r of
525+ Nothing -> return Nothing
526+ Just s -> S.toList s >>= return . Just
499
527
500transformOpsWord8
528transformOpsWord8
501 :: ([Word8] -> t IO Word8)
529 :: ([Word8] -> t IO Word8)