on master help sign in
rename fold functions to make them consistent with base/Foldable
commita34b1f31ad1a0eea6515392abcc52cf8714bb6e1 authorHarendra Kumar <harendra.kumar@gmail.com> dateSun 15 Apr 2018, 18:13 (9 years ago) parent408fef1
4 files changed+93−32
Changelog.md+16−6 benchmark/BenchmarkOps.hs+3−3 src/Streamly/Prelude.hs+71−20 test/Prop.hs+3−3
Changelog.md+16−6
@@ -4,12 +4,22 @@
44* Change the type of `foldrM` to make it consistent with `foldrM` in base
55
66### Deprecations
7−* Deprecate `StreamT`, rename to `SerialT`
8−* Deprecate `runStreamT`, rename to `runSerialT`
9−* Deprecate `ZipStream`, rename to `ZipSerial`
10−* Deprecate `runZipStream`, rename to `runZipSerial`
11−* Deprecate `Streaming`, rename to `IsStream`
12−* Deprecate `runStreaming`, rename to `runStream`
7+* Deprecate and rename the following symbols:
8+ * `StreamT` to `SerialT`
9+ * `runStreamT` to `runSerialT`
10+ * `ZipStream` to `ZipSerial`
11+ * `runZipStream` to `runZipSerial`
12+ * `Streaming` to `IsStream`
13+ * `runStreaming` to `runStream`
14+ * `scan` to `scanx`
15+ * `foldl` to `foldx`
16+ * `foldlM` to `foldxM`
17+
18+### Enhancements
19+* Add the following functions:
20+ * `scanl'` strict left scan
21+ * `foldl'` strict left fold
22+ * `foldlM'` strict left fold with a monadic fold function
1323
1424## 0.1.2
1525
benchmark/BenchmarkOps.hs+3−3
@@ -8,7 +8,7 @@
88module BenchmarkOps where
99
1010import Prelude
11− (Monad, Int, (+), id, ($), (.), return, fmap, even, (>), (<=),
11+ (Monad, Int, (+), ($), (.), return, fmap, even, (>), (<=),
1212 subtract, undefined, Maybe)
1313
1414import qualified Streamly as S
@@ -73,7 +73,7 @@ runStream = S.runSerialT
7373
7474toNull = runStream
7575toList = S.toList
76−foldl = S.foldl (+) 0 id
76+foldl = S.foldl' (+) 0
7777last = S.last
7878
7979-------------------------------------------------------------------------------
@@ -84,7 +84,7 @@ last = S.last
8484transform :: Monad m => Stream m a -> m ()
8585transform = runStream
8686
87−scan = transform . S.scan (+) 0 id
87+scan = transform . S.scanl' (+) 0
8888map = transform . fmap (+1)
8989mapM = transform . S.mapM return
9090filterEven = transform . S.filter even
src/Streamly/Prelude.hs+71−20
@@ -31,9 +31,12 @@ module Streamly.Prelude
3131 -- ** General Folds
3232 , foldr
3333 , foldrM
34− , scan
35− , foldl
36− , foldlM
34+ , foldl'
35+ , foldlM'
36+ , scanl'
37+ , scanx
38+ , foldx
39+ , foldxM
3740 , uncons
3841
3942 -- ** Special Folds
@@ -76,6 +79,10 @@ module Streamly.Prelude
7679 , fromHandle
7780 , toHandle
7881
82+ -- * Deprecated
83+ , scan
84+ , foldl
85+ , foldlM
7986 )
8087where
8188
@@ -154,9 +161,12 @@ fromHandle h = fromStream go
154161-- Elimination
155162------------------------------------------------------------------------------
156163
157−-- Parallel variants of folds?
158−
159−-- | Right fold.
164+-- | Lazy right associative fold. For example, to fold a stream into a list:
165+--
166+-- @
167+-- >> runIdentity $ foldr (:) [] (serially $ each [1,2,3])
168+-- [1,2,3]
169+-- @
160170foldr :: (IsStream t, Monad m) => (a -> b -> b) -> b -> t m a -> m b
161171foldr step acc m = go (toStream m)
162172 where
@@ -166,7 +176,13 @@ foldr step acc m = go (toStream m)
166176 yield a (Just x) = go x >>= \b -> return (step a b)
167177 in (runStream m1) Nothing stop yield
168178
169−-- | Right fold with a monadic step function. See 'toList' for an example use.
179+-- | Lazy right fold with a monadic step function. For example, to fold a
180+-- stream into a list:
181+--
182+-- @
183+-- >> runIdentity $ foldrM (\\x xs -> return (x : xs)) [] (serially $ each [1,2,3])
184+-- [1,2,3]
185+-- @
170186{-# INLINE foldrM #-}
171187foldrM :: (IsStream t, Monad m) => (a -> b -> m b) -> b -> t m a -> m b
172188foldrM step acc m = go (toStream m)
@@ -177,10 +193,13 @@ foldrM step acc m = go (toStream m)
177193 yield a (Just x) = (go x) >>= (step a)
178194 in (runStream m1) Nothing stop yield
179195
180−-- | Scan left. A strict left fold which accumulates the result of its reduction steps inside a stream, from left.
181−{-# INLINE scan #-}
182−scan :: IsStream t => (x -> a -> x) -> x -> (x -> b) -> t m a -> t m b
183−scan step begin done m = cons (done begin) $ fromStream $ go (toStream m) begin
196+-- | Strict left scan with an extraction function. Like 'scanl'', but applies a
197+-- user supplied extraction function (the third argument) at each step. This is
198+-- designed to work with the @foldl@ library. The suffix @x@ is a mnemonic for
199+-- extraction.
200+{-# INLINE scanx #-}
201+scanx :: IsStream t => (x -> a -> x) -> x -> (x -> b) -> t m a -> t m b
202+scanx step begin done m = cons (done begin) $ fromStream $ go (toStream m) begin
184203 where
185204 go m1 !acc = Stream $ \_ stp yld ->
186205 let stop = stp
@@ -190,12 +209,26 @@ scan step begin done m = cons (done begin) $ fromStream $ go (toStream m) begin
190209 in yld (done s) (Just (go x s))
191210 in runStream m1 Nothing stop yield
192211
193−-- | Strict left fold. This is typed to work with the foldl package. To use
194−-- it normally just pass 'id' as the third argument.
195−{-# INLINE foldl #-}
196−foldl :: (IsStream t, Monad m)
212+{-# DEPRECATED scan "Please use scanx instead." #-}
213+scan :: IsStream t => (x -> a -> x) -> x -> (x -> b) -> t m a -> t m b
214+scan = scanx
215+
216+-- | Strict left scan. Like 'foldl'', but returns the folded value at each
217+-- step, generating a stream of all intermediate fold results. The first
218+-- element of the stream is the user supplied initial value, and the last
219+-- element of the stream is the same as the result of 'foldl''.
220+{-# INLINE scanl' #-}
221+scanl' :: IsStream t => (b -> a -> b) -> b -> t m a -> t m b
222+scanl' step begin m = scanx step begin id m
223+
224+-- | Strict left fold with an extraction function. Like the standard strict
225+-- left fold, but applies a user supplied extraction function (the third
226+-- argument) to the folded value at the end. This is designed to work with the
227+-- @foldl@ library. The suffix @x@ is a mnemonic for extraction.
228+{-# INLINE foldx #-}
229+foldx :: (IsStream t, Monad m)
197230 => (x -> a -> x) -> x -> (x -> b) -> t m a -> m b
198−foldl step begin done m = get $ go (toStream m) begin
231+foldx step begin done m = get $ go (toStream m) begin
199232 where
200233 {-# NOINLINE get #-}
201234 get m1 =
@@ -216,12 +249,21 @@ foldl step begin done m = get $ go (toStream m) begin
216249 Just x -> (runStream (go x s)) Nothing undefined yld
217250 in (runStream m1) Nothing stop yield
218251
252+{-# DEPRECATED foldl "Please use foldx instead." #-}
253+foldl :: (IsStream t, Monad m)
254+ => (x -> a -> x) -> x -> (x -> b) -> t m a -> m b
255+foldl = foldx
256+
257+-- | Strict left associative fold.
258+{-# INLINE foldl' #-}
259+foldl' :: (IsStream t, Monad m) => (b -> a -> b) -> b -> t m a -> m b
260+foldl' step begin m = foldx step begin id m
261+
219262-- XXX replace the recursive "go" with explicit continuations.
220−-- | Strict left fold, with monadic step function. This is typed to work
221−-- with the foldl package. To use directly pass 'id' as the third argument.
222−foldlM :: (IsStream t, Monad m)
263+-- | Like 'foldx', but with a monadic step function.
264+foldxM :: (IsStream t, Monad m)
223265 => (x -> a -> m x) -> m x -> (x -> m b) -> t m a -> m b
224−foldlM step begin done m = go begin (toStream m)
266+foldxM step begin done m = go begin (toStream m)
225267 where
226268 go !acc m1 =
227269 let stop = acc >>= done
@@ -229,6 +271,15 @@ foldlM step begin done m = go begin (toStream m)
229271 yield a (Just x) = acc >>= \b -> go (step b a) x
230272 in (runStream m1) Nothing stop yield
231273
274+{-# DEPRECATED foldlM "Please use foldxM instead." #-}
275+foldlM :: (IsStream t, Monad m)
276+ => (x -> a -> m x) -> m x -> (x -> m b) -> t m a -> m b
277+foldlM = foldxM
278+
279+-- | Like 'foldl'' but with a monadic step function.
280+foldlM' :: (IsStream t, Monad m) => (b -> a -> m b) -> b -> t m a -> m b
281+foldlM' step begin m = foldxM step (return begin) return m
282+
232283-- | Decompose a stream into its head and tail. If the stream is empty, returns
233284-- 'Nothing'. If the stream is non-empty, returns 'Just (a, ma)', where 'a' is
234285-- the head of the stream and 'ma' its tail.
test/Prop.hs+3−3
@@ -5,7 +5,7 @@ module Main (main) where
55import Control.Monad (when)
66import Control.Applicative (ZipList(..))
77import Control.Monad (replicateM)
8−import Data.List (sort)
8+import Data.List (sort, foldl', scanl')
99import GHC.Word (Word8)
1010
1111import Test.Hspec.QuickCheck (prop)
@@ -144,7 +144,7 @@ transformOps constr desc t eq = do
144144 transform (dropWhile (const False)) $ t . (A.dropWhile (const False))
145145 prop (desc ++ " dropWhile > 0") $
146146 transform (dropWhile (> 0)) $ t . (A.dropWhile (> 0))
147− prop (desc ++ " scan") $ transform (scanl (+) 0) $ t . (A.scan (+) 0 id)
147+ prop (desc ++ " scan") $ transform (scanl' (+) 0) $ t . (A.scanl' (+) 0)
148148 prop (desc ++ "reverse") $ transform reverse $ t . A.reverse
149149
150150wrapMaybe :: Eq a1 => ([a1] -> a2) -> [a1] -> Maybe a2
@@ -164,7 +164,7 @@ eliminationOps constr desc t = do
164164 -- Elimination
165165 prop (desc ++ " null") $ eliminateOp constr null $ A.null . t
166166 prop (desc ++ " foldl") $
167− eliminateOp constr (foldl (+) 0) $ (A.foldl (+) 0 id) . t
167+ eliminateOp constr (foldl' (+) 0) $ (A.foldl' (+) 0) . t
168168 prop (desc ++ " all") $ eliminateOp constr (all even) $ (A.all even) . t
169169 prop (desc ++ " any") $ eliminateOp constr (any even) $ (A.any even) . t
170170 prop (desc ++ " length") $ eliminateOp constr length $ A.length . t