on master help sign in
Add maximumBy and minimumBy.
commit3186bd283fb4e5988da64b7fb7b79be48a2f9c05 authorPranay Sashank <pranaysashank@gmail.com> dateThu 15 Nov 2018, 10:45 (8 years ago) parent5e38a57
6 files changed+118−3
benchmark/Linear.hs+2 benchmark/LinearOps.hs+7−1 src/Streamly/Prelude.hs+14−1 src/Streamly/Streams/StreamD.hs+40 src/Streamly/Streams/StreamK.hs+42 test/Prop.hs+13−1
benchmark/Linear.hs+2
@@ -119,7 +119,9 @@ main =
119119 , benchIOSink "findIndex" Ops.findIndex
120120 , benchIOSink "elemIndex" Ops.elemIndex
121121 , benchIOSink "maximum" Ops.maximum
122+ , benchIOSink "maximumBy" Ops.maximumBy
122123 , benchIOSink "minimum" Ops.minimum
124+ , benchIOSink "minimumBy" Ops.minimumBy
123125 , benchIOSink "sum" Ops.sum
124126 , benchIOSink "product" Ops.product
125127 ]
benchmark/LinearOps.hs+7−1
@@ -17,7 +17,7 @@ import Data.Maybe (fromJust)
1717import Prelude
1818 (Monad, Int, (+), ($), (.), return, fmap, even, (>), (<=), (==), (<=),
1919 subtract, undefined, Maybe(..), odd, Bool, not, (>>=), mapM_, curry,
20− maxBound, div, IO)
20+ maxBound, div, IO, compare)
2121import qualified Prelude as P
2222import qualified Data.Foldable as F
2323import qualified GHC.Exts as GHC
@@ -146,6 +146,10 @@ toList, foldr, foldrM :: Monad m => Stream m Int -> m [Int]
146146last, minimum, maximum, find, findIndex, elemIndex, foldl1', foldr1
147147 :: Monad m => Stream m Int -> m (Maybe Int)
148148
149+{-# INLINE minimumBy #-}
150+{-# INLINE maximumBy #-}
151+minimumBy, maximumBy :: Monad m => Stream m Int -> m (Maybe Int)
152+
149153{-# INLINE foldl' #-}
150154{-# INLINE length #-}
151155{-# INLINE sum #-}
@@ -213,6 +217,8 @@ maximum = S.maximum
213217minimum = S.minimum
214218sum = S.sum
215219product = S.product
220+minimumBy = S.minimumBy compare
221+maximumBy = S.maximumBy compare
216222
217223-------------------------------------------------------------------------------
218224-- Transformation
src/Streamly/Prelude.hs+14−1
@@ -144,7 +144,9 @@ module Streamly.Prelude
144144 -- Full folds - need to go through all elements
145145 , length
146146 , maximum
147+ , maximumBy
147148 , minimum
149+ , minimumBy
148150 , sum
149151 , product
150152
@@ -706,13 +708,24 @@ product = foldl' (*) 1
706708minimum :: (Monad m, Ord a) => SerialT m a -> m (Maybe a)
707709minimum m = S.minimum (toStreamS m)
708710
711+-- | Non-overloaded version of minimum.
712+--
713+{-# INLINE minimumBy #-}
714+minimumBy :: Monad m => (a -> a -> Ordering) -> SerialT m a -> m (Maybe a)
715+minimumBy cmp m = S.minimumBy cmp (toStreamS m)
716+
709717-- | Determine the maximum element in a stream.
710718--
711−-- @since 0.1.0
712719{-# INLINE maximum #-}
713720maximum :: (Monad m, Ord a) => SerialT m a -> m (Maybe a)
714721maximum m = S.maximum (toStreamS m)
715722
723+-- | Non-overloaded version of maximum.
724+--
725+{-# INLINE maximumBy #-}
726+maximumBy :: Monad m => (a -> a -> Ordering) -> SerialT m a -> m (Maybe a)
727+maximumBy cmp m = S.maximumBy cmp (toStreamS m)
728+
716729-- | Looks the element at the given index.
717730--
718731{-# INLINE (!!) #-}
src/Streamly/Streams/StreamD.hs+40
@@ -82,7 +82,9 @@ module Streamly.Streams.StreamD
8282 , all
8383 , any
8484 , maximum
85+ , maximumBy
8586 , minimum
87+ , minimumBy
8688 , findIndices
8789 , lookup
8890 , find
@@ -465,6 +467,25 @@ maximum (Stream step state) = go Nothing state
465467 Skip s -> go (Just acc) s
466468 Stop -> return (Just acc)
467469
470+{-# INLINE_NORMAL maximumBy #-}
471+maximumBy :: Monad m => (a -> a -> Ordering) -> Stream m a -> m (Maybe a)
472+maximumBy cmp (Stream step state) = go Nothing state
473+ where
474+ go Nothing st = do
475+ r <- step defState st
476+ case r of
477+ Yield x s -> go (Just x) s
478+ Skip s -> go Nothing s
479+ Stop -> return Nothing
480+ go (Just acc) st = do
481+ r <- step defState st
482+ case r of
483+ Yield x s -> case cmp acc x of
484+ GT -> go (Just acc) s
485+ _ -> go (Just x) s
486+ Skip s -> go (Just acc) s
487+ Stop -> return (Just acc)
488+
468489{-# INLINE_NORMAL minimum #-}
469490minimum :: (Monad m, Ord a) => Stream m a -> m (Maybe a)
470491minimum (Stream step state) = go Nothing state
@@ -484,6 +505,25 @@ minimum (Stream step state) = go Nothing state
484505 Skip s -> go (Just acc) s
485506 Stop -> return (Just acc)
486507
508+{-# INLINE_NORMAL minimumBy #-}
509+minimumBy :: Monad m => (a -> a -> Ordering) -> Stream m a -> m (Maybe a)
510+minimumBy cmp (Stream step state) = go Nothing state
511+ where
512+ go Nothing st = do
513+ r <- step defState st
514+ case r of
515+ Yield x s -> go (Just x) s
516+ Skip s -> go Nothing s
517+ Stop -> return Nothing
518+ go (Just acc) st = do
519+ r <- step defState st
520+ case r of
521+ Yield x s -> case cmp acc x of
522+ GT -> go (Just x) s
523+ _ -> go (Just acc) s
524+ Skip s -> go (Just acc) s
525+ Stop -> return (Just acc)
526+
487527{-# INLINE_NORMAL (!!) #-}
488528(!!) :: (Monad m) => Stream m a -> Int -> m (Maybe a)
489529(Stream step state) !! i = go i state
src/Streamly/Streams/StreamK.hs+42
@@ -90,7 +90,9 @@ module Streamly.Streams.StreamK
9090 , any
9191 , last
9292 , minimum
93+ , minimumBy
9394 , maximum
95+ , maximumBy
9496 , findIndices
9597 , lookup
9698 , find
@@ -712,6 +714,26 @@ minimum m = go Nothing (toStream m)
712714 else go (Just a) r
713715 in unStream m1 defState stop single yieldk
714716
717+{-# INLINE minimumBy #-}
718+minimumBy :: (IsStream t, Monad m) => (a -> a -> Ordering) -> t m a -> m (Maybe a)
719+minimumBy cmp m = go Nothing (toStream m)
720+ where
721+ go Nothing m1 =
722+ let stop = return Nothing
723+ single a = return (Just a)
724+ yieldk a r = go (Just a) r
725+ in unStream m1 defState stop single yieldk
726+
727+ go (Just res) m1 =
728+ let stop = return (Just res)
729+ single a = case cmp res a of
730+ GT -> return (Just a)
731+ _ -> return (Just res)
732+ yieldk a r = case cmp res a of
733+ GT -> go (Just a) r
734+ _ -> go (Just res) r
735+ in unStream m1 defState stop single yieldk
736+
715737{-# INLINE maximum #-}
716738maximum :: (IsStream t, Monad m, Ord a) => t m a -> m (Maybe a)
717739maximum m = go Nothing (toStream m)
@@ -734,6 +756,26 @@ maximum m = go Nothing (toStream m)
734756 else go (Just res) r
735757 in unStream m1 defState stop single yieldk
736758
759+{-# INLINE maximumBy #-}
760+maximumBy :: (IsStream t, Monad m) => (a -> a -> Ordering) -> t m a -> m (Maybe a)
761+maximumBy cmp m = go Nothing (toStream m)
762+ where
763+ go Nothing m1 =
764+ let stop = return Nothing
765+ single a = return (Just a)
766+ yieldk a r = go (Just a) r
767+ in unStream m1 defState stop single yieldk
768+
769+ go (Just res) m1 =
770+ let stop = return (Just res)
771+ single a = case cmp res a of
772+ GT -> return (Just res)
773+ _ -> return (Just a)
774+ yieldk a r = case cmp res a of
775+ GT -> go (Just res) r
776+ _ -> go (Just a) r
777+ in unStream m1 defState stop single yieldk
778+
737779{-# INLINE (!!) #-}
738780(!!) :: (IsStream t, Monad m) => t m a -> Int -> m (Maybe a)
739781m !! i = go i (toStream m)
test/Prop.hs+13−1
@@ -13,7 +13,8 @@ import Data.Function ((&))
1313import Data.IORef (readIORef, modifyIORef, newIORef)
1414import Data.List
1515 (sort, foldl', scanl', findIndices, findIndex, elemIndices,
16− elemIndex, find, insertBy, intersperse, foldl1', (\\))
16+ elemIndex, find, insertBy, intersperse, foldl1', (\\),
17+ maximumBy, minimumBy)
1718import Data.Maybe (mapMaybe)
1819import GHC.Word (Word8)
1920
@@ -550,6 +551,17 @@ eliminationOps constr desc t = do
550551 prop (desc <> " maximum") $ eliminateOp constr (wrapMaybe maximum) $ S.maximum . t
551552 prop (desc <> " minimum") $ eliminateOp constr (wrapMaybe minimum) $ S.minimum . t
552553
554+ prop (desc <> " maximumBy compare") $
555+ eliminateOp constr (wrapMaybe $ maximumBy compare) $ S.maximumBy compare . t
556+ prop (desc <> " maximumBy flip compare") $
557+ eliminateOp constr (wrapMaybe $ maximumBy $ flip compare) $
558+ S.maximumBy (flip compare) . t
559+ prop (desc <> " minimumBy compare") $
560+ eliminateOp constr (wrapMaybe $ minimumBy compare) $ S.minimumBy compare . t
561+ prop (desc <> " minimumBy flip compare") $
562+ eliminateOp constr (wrapMaybe $ minimumBy $ flip compare) $
563+ S.minimumBy (flip compare) . t
564+
553565 prop (desc <> " findIndex") $ eliminateOp constr (findIndex odd) $ S.findIndex odd . t
554566 prop (desc <> " elemIndex") $ eliminateOp constr (elemIndex 3) $ S.elemIndex 3 . t
555567