on master help sign in
Merge pull request #95 from Veladus/approved-prelude-functions

Approved prelude functions

commit9b87957f4fbed7bce92b10f9506941220aa4fea8 authorHarendra Kumar <harendra.kumar@gmail.com> dateTue 24 Jul 2018, 23:37 (8 years ago) parent2af3833cd0cb16
4 files changed+225−12
Changelog.md+7 src/Streamly/Prelude.hs+93−1 src/Streamly/Streams/StreamK.hs+87−1 test/Prop.hs+38−10
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+
18## 0.4.1
29
310### Bug Fixes
src/Streamly/Prelude.hs+93−1
@@ -82,8 +82,10 @@ module Streamly.Prelude
8282 -- * Elimination
8383 -- ** General Folds
8484 , foldr
85+ , foldr1
8586 , foldrM
8687 , foldl'
88+ , foldl1'
8789 , foldlM'
8890 , foldx
8991 , foldxM
@@ -93,15 +95,27 @@ module Streamly.Prelude
9395 , head
9496 , tail
9597 , last
98+ , init
9699 , elem
97100 , notElem
98101 , length
99102 , all
100103 , any
104+ , and
105+ , or
101106 , maximum
102107 , minimum
103108 , sum
104109 , product
110+ , lookup
111+ , find
112+
113+ -- *** Indices
114+ , findIndices
115+ , findIndex
116+ , elemIndices
117+ , elemIndex
118+
105119
106120 -- ** Map and Fold
107121 , mapM_
@@ -139,6 +153,9 @@ module Streamly.Prelude
139153 -- ** Reordering
140154 , reverse
141155
156+ -- ** Inserting
157+ , intersperseM
158+
142159 -- * Zipping
143160 , zipWith
144161 , zipWithM
@@ -160,7 +177,7 @@ import Prelude
160177 hiding (filter, drop, dropWhile, take, takeWhile, zipWith, foldr,
161178 foldl, map, mapM, mapM_, sequence, all, any, sum, product, elem,
162179 notElem, maximum, minimum, head, last, tail, length, null,
163− reverse, iterate)
180+ reverse, iterate, init, and, or, lookup, foldr1)
164181import qualified Prelude
165182import qualified System.IO as IO
166183
@@ -450,6 +467,12 @@ foldr :: Monad m => (a -> b -> b) -> b -> SerialT m a -> m b
450467-- foldr step acc m = S.foldr step acc $ S.fromStreamK (toStream m)
451468foldr f = foldrM (\a b -> return (f a b))
452469
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+
453476-- | Strict left fold with an extraction function. Like the standard strict
454477-- left fold, but applies a user supplied extraction function (the third
455478-- argument) to the folded value at the end. This is designed to work with the
@@ -473,6 +496,17 @@ foldl = foldx
473496foldl' :: Monad m => (b -> a -> b) -> b -> SerialT m a -> m b
474497foldl' step begin m = S.foldl' step begin $ toStreamS m
475498
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+
476510-- XXX replace the recursive "go" with explicit continuations.
477511-- | Like 'foldx', but with a monadic step function.
478512--
@@ -517,6 +551,11 @@ head m = K.head m
517551tail :: (IsStream t, Monad m) => SerialT m a -> m (Maybe (t m a))
518552tail m = K.tail (K.adapt m)
519553
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+
520559-- | Extract the last element of the stream, if any.
521560--
522561-- @since 0.1.1
@@ -559,6 +598,16 @@ all p m = S.all p (toStreamS m)
559598any :: Monad m => (a -> Bool) -> SerialT m a -> m Bool
560599any p m = S.any p (toStreamS m)
561600
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+
562611-- | Determine the sum of all elements of a stream of numbers
563612--
564613-- @since 0.1.0
@@ -587,6 +636,39 @@ minimum m = S.minimum (toStreamS m)
587636maximum :: (Monad m, Ord a) => SerialT m a -> m (Maybe a)
588637maximum m = S.maximum (toStreamS m)
589638
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+
590672------------------------------------------------------------------------------
591673-- Map and Fold
592674------------------------------------------------------------------------------
@@ -812,6 +894,16 @@ reverse m = fromStream $ go K.nil (toStream m)
812894 yieldk a r = runIt $ go (a `K.cons` rev) r
813895 in K.unStream rest (rstState st) stop single yieldk
814896
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+
815907------------------------------------------------------------------------------
816908-- Zipping
817909------------------------------------------------------------------------------
src/Streamly/Streams/StreamK.hs+87−1
@@ -71,6 +71,7 @@ module Streamly.Streams.StreamK
7171 , foldStream
7272 , foldr
7373 , foldrM
74+ , foldr1
7475 , foldl'
7576 , foldlM'
7677 , foldx
@@ -81,6 +82,7 @@ module Streamly.Streams.StreamK
8182 , null
8283 , head
8384 , tail
85+ , init
8486 , elem
8587 , notElem
8688 , all
@@ -88,6 +90,9 @@ module Streamly.Streams.StreamK
8890 , last
8991 , minimum
9092 , maximum
93+ , findIndices
94+ , lookup
95+ , find
9196
9297 -- ** Map and Fold
9398 , mapM_
@@ -113,6 +118,9 @@ module Streamly.Streams.StreamK
113118 , mapM
114119 , sequence
115120
121+ -- ** Inserting
122+ , intersperseM
123+
116124 -- ** Map and Filter
117125 , mapMaybe
118126
@@ -141,7 +149,8 @@ import Data.Semigroup (Semigroup(..))
141149import Prelude
142150 hiding (foldl, foldr, last, map, mapM, mapM_, repeat, sequence,
143151 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)
145154import qualified Prelude
146155
147156import Streamly.SVar
@@ -485,6 +494,20 @@ foldrM step acc m = go (toStream m)
485494 yieldk a r = go r >>= step a
486495 in (unStream m1) defState stop single yieldk
487496
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+
488511-- | Strict left fold with an extraction function. Like the standard strict
489512-- left fold, but applies a user supplied extraction function (the third
490513-- argument) to the folded value at the end. This is designed to work with the
@@ -570,6 +593,20 @@ tail m =
570593 yieldk _ r = return $ Just $ fromStream r
571594 in unStream (toStream m) defState stop single yieldk
572595
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+
573610{-# INLINE elem #-}
574611elem :: (IsStream t, Monad m, Eq a) => a -> t m a -> m Bool
575612elem e m = go (toStream m)
@@ -659,6 +696,39 @@ maximum m = go Nothing (toStream m)
659696 else go (Just res) r
660697 in unStream m1 defState stop single yieldk
661698
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+
662732------------------------------------------------------------------------------
663733-- Map and Fold
664734------------------------------------------------------------------------------
@@ -798,6 +868,22 @@ sequence m = go (toStream m)
798868 yieldk ma r = unStream (toStream $ ma |: go r) st stp sng yld
799869 in (unStream m1) (rstState st) stp single yieldk
800870
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+
801887-------------------------------------------------------------------------------
802888-- Map and Filter
803889-------------------------------------------------------------------------------
test/Prop.hs+38−10
@@ -9,7 +9,8 @@ import Control.Applicative (ZipList(..))
99import Control.Concurrent (MVar, takeMVar, putMVar, newEmptyMVar)
1010import Control.Monad (replicateM, replicateM_)
1111import 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')
1314import Data.Maybe (mapMaybe)
1415import GHC.Word (Word8)
1516
@@ -63,11 +64,12 @@ constructWithReplicateM op thr buf len = withMaxSuccess maxTestCount $
6364 equals (==) stream list
6465
6566transformFromList
66− :: ([Int] -> t IO Int)
67− -> ([Int] -> [Int] -> Bool)
68− -> ([Int] -> [Int])
69− -> (t IO Int -> SerialT IO Int)
70− -> [Int]
67+ :: Show b =>
68+ ([a] -> t IO a)
69+ -> ([b] -> [b] -> Bool)
70+ -> ([a] -> [b])
71+ -> (t IO a -> SerialT IO b)
72+ -> [a]
7173 -> Property
7274transformFromList constr eq listOp op a =
7375 monadicIO $ do
@@ -264,10 +266,10 @@ foldFromList constr op eq a = transformFromList constr eq id op a
264266
265267eliminateOp
266268 :: (Show a, Eq a)
267− => ([Int] -> t IO Int)
268− -> ([Int] -> a)
269− -> (t IO Int -> IO a)
270− -> [Int]
269+ => ([s] -> t IO s)
270+ -> ([s] -> a)
271+ -> (t IO s -> IO a)
272+ -> [s]
271273 -> Property
272274eliminateOp constr listOp op a =
273275 monadicIO $ do
@@ -347,6 +349,12 @@ transformOps constr desc t eq = do
347349 prop (desc ++ " scan") $ transform (scanl' (+) 0) $ t . (S.scanl' (+) 0)
348350 prop (desc ++ " reverse") $ transform reverse $ t . S.reverse
349351
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+
350358concurrentOps
351359 :: IsStream t
352360 => ([Word8] -> t IO Word8)
@@ -432,6 +440,9 @@ transformCombineOpsCommon constr desc t eq = do
432440 (S.scanlM' (\_ a -> return a) 0)
433441 prop (desc ++ " reverse") $ transform reverse t S.reverse
434442
443+ prop (desc ++ " intersperseM") $
444+ transform (intersperse 3) t (S.intersperseM $ return 3)
445+
435446transformCombineOpsOrdered
436447 :: (IsStream t, Semigroup (t IO Int))
437448 => ([Int] -> t IO Int)
@@ -472,6 +483,10 @@ eliminationOps constr desc t = do
472483 prop (desc ++ " null") $ eliminateOp constr null $ S.null . t
473484 prop (desc ++ " foldl") $
474485 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
475490 prop (desc ++ " all") $ eliminateOp constr (all even) $ (S.all even) . t
476491 prop (desc ++ " any") $ eliminateOp constr (any even) $ (S.any even) . t
477492 prop (desc ++ " length") $ eliminateOp constr length $ S.length . t
@@ -481,6 +496,14 @@ eliminationOps constr desc t = do
481496 prop (desc ++ " maximum") $ eliminateOp constr (wrapMaybe maximum) $ S.maximum . t
482497 prop (desc ++ " minimum") $ eliminateOp constr (wrapMaybe minimum) $ S.minimum . t
483498
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+
484507-- head/tail/last may depend on the order in case of parallel streams
485508-- so we test these only for serial streams.
486509serialEliminationOps
@@ -496,6 +519,11 @@ serialEliminationOps constr desc t = do
496519 Nothing -> return Nothing
497520 Just s -> S.toList s >>= return . Just
498521 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
499527
500528transformOpsWord8
501529 :: ([Word8] -> t IO Word8)