on master help sign in
Add scanl1, scanl1M, scanl1', scanl1M', scanl, scanlM to StreamD.
commit7f82af409c2439b7750da677c424ada95714dbcd authorPranay Sashank <pranaysashank@gmail.com> dateThu 15 Nov 2018, 12:51 (8 years ago) parent3186bd2
5 files changed+152−7
benchmark/Linear.hs+4 benchmark/LinearOps.hs+11−4 src/Streamly/Prelude.hs+44−1 src/Streamly/Streams/StreamD.hs+79−1 test/Prop.hs+14−1
benchmark/Linear.hs+4
@@ -127,6 +127,7 @@ main =
127127 ]
128128 , bgroup "transformation"
129129 [ benchIOSink "scan" (Ops.scan 1)
130+ , benchIOSink "scanl1" (Ops.scanl1 1)
130131 , benchIOSink "map" (Ops.map 1)
131132 , benchIOSink "fmap" (Ops.fmap 1)
132133 , benchIOSink "mapM" (Ops.mapM serially 1)
@@ -140,6 +141,7 @@ main =
140141 ]
141142 , bgroup "transformationX4"
142143 [ benchIOSink "scan" (Ops.scan 4)
144+ , benchIOSink "scanl1" (Ops.scanl1 4)
143145 , benchIOSink "map" (Ops.map 4)
144146 , benchIOSink "fmap" (Ops.fmap 4)
145147 , benchIOSink "mapM" (Ops.mapM serially 4)
@@ -194,11 +196,13 @@ main =
194196 , benchIOSink "filter-drop" (Ops.filterDrop 4)
195197 , benchIOSink "filter-take" (Ops.filterTake 4)
196198 , benchIOSink "filter-scan" (Ops.filterScan 4)
199+ , benchIOSink "filter-scanl1" (Ops.filterScanl1 4)
197200 , benchIOSink "filter-map" (Ops.filterMap 4)
198201 ]
199202 , bgroup "iterated"
200203 [ benchIOSrc serially "mapM" Ops.iterateMapM
201204 , benchIOSrc serially "scan(1/100)" Ops.iterateScan
205+ , benchIOSrc serially "scanl1(1/100)" Ops.iterateScanl1
202206 , benchIOSrc serially "filterEven" Ops.iterateFilterEven
203207 , benchIOSrc serially "takeAll" Ops.iterateTakeAll
204208 , benchIOSrc serially "dropOne" Ops.iterateDropOne
benchmark/LinearOps.hs+11−4
@@ -254,6 +254,7 @@ composeN' n f =
254254 _ -> undefined
255255
256256{-# INLINE scan #-}
257+{-# INLINE scanl1 #-}
257258{-# INLINE map #-}
258259{-# INLINE fmap #-}
259260{-# INLINE mapMaybe #-}
@@ -271,7 +272,7 @@ composeN' n f =
271272{-# INLINE dropWhileFalse #-}
272273{-# INLINE findIndices #-}
273274{-# INLINE elemIndices #-}
274−scan, map, fmap, mapMaybe, filterEven, filterAllOut,
275+scan, scanl1, map, fmap, mapMaybe, filterEven, filterAllOut,
275276 filterAllIn, takeOne, takeAll, takeWhileTrue, takeWhileMTrue, dropOne,
276277 dropAll, dropWhileTrue, dropWhileMTrue, dropWhileFalse,
277278 findIndices, elemIndices
@@ -290,6 +291,7 @@ sequence :: (S.IsStream t, S.MonadAsync m)
290291 => (t m Int -> S.SerialT m Int) -> t m (m Int) -> m ()
291292
292293scan n = composeN n $ S.scanl' (+) 0
294+scanl1 n = composeN n $ S.scanl1' (+)
293295fmap n = composeN n $ Prelude.fmap (+1)
294296map n = composeN n $ S.map (+1)
295297mapM t n = composeN' n $ t . S.mapM return
@@ -332,18 +334,21 @@ iterateSource g i n = f i (sourceUnfoldrMN iterStreamLen n)
332334
333335{-# INLINE iterateMapM #-}
334336{-# INLINE iterateScan #-}
337+{-# INLINE iterateScanl1 #-}
335338{-# INLINE iterateFilterEven #-}
336339{-# INLINE iterateTakeAll #-}
337340{-# INLINE iterateDropOne #-}
338341{-# INLINE iterateDropWhileFalse #-}
339342{-# INLINE iterateDropWhileTrue #-}
340−iterateMapM, iterateScan, iterateFilterEven, iterateTakeAll, iterateDropOne,
341− iterateDropWhileFalse, iterateDropWhileTrue
343+iterateMapM, iterateScan, iterateScanl1, iterateFilterEven, iterateTakeAll,
344+ iterateDropOne, iterateDropWhileFalse, iterateDropWhileTrue
342345 :: S.MonadAsync m
343346 => Int -> Stream m Int
344347
345348-- this is quadratic
346349iterateScan = iterateSource (S.scanl' (+) 0) (maxIters `div` 10)
350+-- so is this
351+iterateScanl1 = iterateSource (S.scanl1' (+)) (maxIters `div` 10)
347352
348353iterateMapM = iterateSource (S.mapM return) maxIters
349354iterateFilterEven = iterateSource (S.filter even) maxIters
@@ -412,9 +417,10 @@ cmpBy src = S.cmpBy P.compare src src
412417{-# INLINE filterDrop #-}
413418{-# INLINE filterTake #-}
414419{-# INLINE filterScan #-}
420+{-# INLINE filterScanl1 #-}
415421{-# INLINE filterMap #-}
416422scanMap, dropMap, dropScan, takeDrop, takeScan, takeMap, filterDrop,
417− filterTake, filterScan, filterMap
423+ filterTake, filterScan, filterScanl1, filterMap
418424 :: Monad m => Int -> Stream m Int -> m ()
419425
420426scanMap n = composeN n $ S.map (subtract 1) . S.scanl' (+) 0
@@ -426,6 +432,7 @@ takeMap n = composeN n $ S.map (subtract 1) . S.take maxValue
426432filterDrop n = composeN n $ S.drop 1 . S.filter (<= maxValue)
427433filterTake n = composeN n $ S.take maxValue . S.filter (<= maxValue)
428434filterScan n = composeN n $ S.scanl' (+) 0 . S.filter (<= maxBound)
435+filterScanl1 n = composeN n $ S.scanl1' (+) . S.filter (<= maxBound)
429436filterMap n = composeN n $ S.map (subtract 1) . S.filter (<= maxValue)
430437
431438-------------------------------------------------------------------------------
src/Streamly/Prelude.hs+44−1
@@ -169,6 +169,12 @@ module Streamly.Prelude
169169 -- transformation like map can be expressed in terms of this.
170170 , scanl'
171171 , scanlM'
172+ , scanlM
173+ , scanl
174+ , scanl1M'
175+ , scanl1'
176+ , scanl1M
177+ , scanl1
172178 , scanx
173179
174180 -- ** Mapping
@@ -243,7 +249,7 @@ import Prelude
243249 foldl, mapM, mapM_, sequence, all, any, sum, product, elem,
244250 notElem, maximum, minimum, head, last, tail, length, null,
245251 reverse, iterate, init, and, or, lookup, foldr1, (!!),
246− splitAt)
252+ splitAt, scanl, scanl1)
247253import qualified Prelude
248254import qualified System.IO as IO
249255
@@ -851,6 +857,43 @@ scanlM' step begin m = fromStreamD $ D.scanlM' step begin $ toStreamD m
851857scanl' :: (IsStream t, Monad m) => (b -> a -> b) -> b -> t m a -> t m b
852858scanl' step z m = fromStreamS $ S.scanl' step z $ toStreamS m
853859
860+-- | Like 'scanlM'' but with a non-strict accumulator.
861+--
862+{-# INLINE scanlM #-}
863+scanlM :: (IsStream t, Monad m) => (b -> a -> m b) -> b -> t m a -> t m b
864+scanlM step begin m = fromStreamD $ D.scanlM step begin $ toStreamD m
865+
866+-- | Like 'scanl'' but with a non-strict accumulator.
867+{-# INLINE scanl #-}
868+scanl :: (IsStream t, Monad m) => (b -> a -> b) -> b -> t m a -> t m b
869+scanl step z m = fromStreamD $ D.scanl step z $ toStreamD m
870+
871+-- | Left scan with a monadic step function. Uses the first element of
872+-- the stream as the starting value. Returns an empty stream if the
873+-- given stream is empty.
874+--
875+{-# INLINE scanl1M #-}
876+scanl1M :: (IsStream t, Monad m) => (a -> a -> m a) -> t m a -> t m a
877+scanl1M step m = fromStreamD $ D.scanl1M step $ toStreamD m
878+
879+-- | Like 'scanl1M' but with a strict accumulator.
880+--
881+{-# INLINE scanl1M' #-}
882+scanl1M' :: (IsStream t, Monad m) => (a -> a -> m a) -> t m a -> t m a
883+scanl1M' step m = fromStreamD $ D.scanl1M' step $ toStreamD m
884+
885+-- | Left scan, uses the first element of the stream as the starting
886+-- value. Returns an empty stream if the given stream is empty.
887+{-# INLINE scanl1 #-}
888+scanl1 :: (IsStream t, Monad m) => (a -> a -> a) -> t m a -> t m a
889+scanl1 step m = fromStreamD $ D.scanl1 step $ toStreamD m
890+
891+-- | Like 'scanl1'' but with a strict accumulator.
892+--
893+{-# INLINE scanl1' #-}
894+scanl1' :: (IsStream t, Monad m) => (a -> a -> a) -> t m a -> t m a
895+scanl1' step m = fromStreamD $ D.scanl1' step $ toStreamD m
896+
854897------------------------------------------------------------------------------
855898-- Transformation by Filtering
856899------------------------------------------------------------------------------
src/Streamly/Streams/StreamD.hs+79−1
@@ -103,6 +103,12 @@ module Streamly.Streams.StreamD
103103 -- ** By folding (scans)
104104 , scanlM'
105105 , scanl'
106+ , scanlM
107+ , scanl
108+ , scanl1M'
109+ , scanl1'
110+ , scanl1M
111+ , scanl1
106112
107113 -- * Filtering
108114 , filter
@@ -148,7 +154,7 @@ import Prelude
148154 hiding (map, mapM, mapM_, repeat, foldr, last, take, filter,
149155 takeWhile, drop, dropWhile, all, any, maximum, minimum, elem,
150156 notElem, null, head, tail, zipWith, lookup, foldr1, sequence,
151− (!!))
157+ (!!), scanl, scanl1)
152158
153159import Streamly.SVar (MonadAsync, State(..), defState, rstState)
154160
@@ -630,6 +636,20 @@ postscanlM' fstep begin (Stream step state) =
630636 Skip s -> return $ Skip (s, acc)
631637 Stop -> return Stop
632638
639+{-# INLINE_NORMAL postscanlM #-}
640+postscanlM :: Monad m => (b -> a -> m b) -> b -> Stream m a -> Stream m b
641+postscanlM fstep begin (Stream step state) = Stream step' (state, begin)
642+ where
643+ {-# INLINE_LATE step' #-}
644+ step' gst (st, acc) = do
645+ r <- step (rstState gst) st
646+ case r of
647+ Yield x s -> do
648+ y <- fstep acc x
649+ return (Yield y (s, y))
650+ Skip s -> return $ Skip (s, acc)
651+ Stop -> return Stop
652+
633653{-# INLINE_NORMAL scanlM' #-}
634654scanlM' :: Monad m => (b -> a -> m b) -> b -> Stream m a -> Stream m b
635655scanlM' fstep begin s = begin `seq` (begin `cons` postscanlM' fstep begin s)
@@ -638,6 +658,64 @@ scanlM' fstep begin s = begin `seq` (begin `cons` postscanlM' fstep begin s)
638658scanl' :: Monad m => (b -> a -> b) -> b -> Stream m a -> Stream m b
639659scanl' f = scanlM' (\a b -> return (f a b))
640660
661+{-# INLINE_NORMAL scanlM #-}
662+scanlM :: Monad m => (b -> a -> m b) -> b -> Stream m a -> Stream m b
663+scanlM fstep begin s = begin `cons` postscanlM fstep begin s
664+
665+{-# INLINE scanl #-}
666+scanl :: Monad m => (b -> a -> b) -> b -> Stream m a -> Stream m b
667+scanl f = scanlM (\a b -> return (f a b))
668+
669+{-# INLINE_NORMAL scanl1M #-}
670+scanl1M :: Monad m => (a -> a -> m a) -> Stream m a -> Stream m a
671+scanl1M fstep (Stream step state) = Stream step' (state, Nothing)
672+ where
673+ {-# INLINE_LATE step' #-}
674+ step' gst (st, Nothing) = do
675+ r <- step (rstState gst) st
676+ case r of
677+ Yield x s -> return $ Yield x (s, Just x)
678+ Skip s -> return $ Skip (s, Nothing)
679+ Stop -> return Stop
680+
681+ step' gst (st, Just acc) = do
682+ r <- step (rstState gst) st
683+ case r of
684+ Yield y s -> do
685+ z <- fstep acc y
686+ return $ Yield z (s, Just z)
687+ Skip s -> return $ Skip (s, Just acc)
688+ Stop -> return Stop
689+
690+{-# INLINE scanl1 #-}
691+scanl1 :: Monad m => (a -> a -> a) -> Stream m a -> Stream m a
692+scanl1 f = scanl1M (\x y -> return (f x y))
693+
694+{-# INLINE_NORMAL scanl1M' #-}
695+scanl1M' :: Monad m => (a -> a -> m a) -> Stream m a -> Stream m a
696+scanl1M' fstep (Stream step state) = Stream step' (state, Nothing)
697+ where
698+ {-# INLINE_LATE step' #-}
699+ step' gst (st, Nothing) = do
700+ r <- step (rstState gst) st
701+ case r of
702+ Yield x s -> x `seq` return $ Yield x (s, Just x)
703+ Skip s -> return $ Skip (s, Nothing)
704+ Stop -> return Stop
705+
706+ step' gst (st, Just acc) = acc `seq` do
707+ r <- step (rstState gst) st
708+ case r of
709+ Yield y s -> do
710+ z <- fstep acc y
711+ z `seq` return $ Yield z (s, Just z)
712+ Skip s -> return $ Skip (s, Just acc)
713+ Stop -> return Stop
714+
715+{-# INLINE scanl1' #-}
716+scanl1' :: Monad m => (a -> a -> a) -> Stream m a -> Stream m a
717+scanl1' f = scanl1M' (\x y -> return (f x y))
718+
641719-------------------------------------------------------------------------------
642720-- Filtering
643721-------------------------------------------------------------------------------
test/Prop.hs+14−1
@@ -464,10 +464,23 @@ transformCombineOpsCommon constr desc eq t = do
464464 prop (desc <> " mapM (+1)") $
465465 transform (fmap (+1)) t (S.mapM (\x -> return (x + 1)))
466466
467− prop (desc <> " scan") $ transform (scanl' (flip const) 0) t
467+ prop (desc <> " scanl'") $ transform (scanl' (flip const) 0) t
468468 (S.scanl' (flip const) 0)
469469 prop (desc <> " scanlM'") $ transform (scanl' (flip const) 0) t
470470 (S.scanlM' (\_ a -> return a) 0)
471+ prop (desc <> " scanl") $ transform (scanl' (flip const) 0) t
472+ (S.scanl' (flip const) 0)
473+ prop (desc <> " scanlM") $ transform (scanl (flip const) 0) t
474+ (S.scanlM (\_ a -> return a) 0)
475+ prop (desc <> " scanl1") $ transform (scanl1 (flip const)) t
476+ (S.scanl1 (flip const))
477+ prop (desc <> " scanl1M") $ transform (scanl1 (flip const)) t
478+ (S.scanl1M (\_ a -> return a))
479+ prop (desc <> " scanl1'") $ transform (scanl1 (flip const)) t
480+ (S.scanl1' (flip const))
481+ prop (desc <> " scanl1M'") $ transform (scanl1 (flip const)) t
482+ (S.scanl1M' (\_ a -> return a))
483+
471484 prop (desc <> " reverse") $ transform reverse t S.reverse
472485
473486 prop (desc <> " intersperseM") $