on master help sign in
rename fold functions to make them consistent with base/Foldable
a34b1f3Harendra Kumar
Changelog.md+16−6
@@ -4,12 +4,22 @@
4* Change the type of `foldrM` to make it consistent with `foldrM` in base
4* Change the type of `foldrM` to make it consistent with `foldrM` in base
5
5
6### Deprecations
6### Deprecations
7+* Deprecate and rename the following symbols:
7−* Deprecate `StreamT`, rename to `SerialT`
8+ * `StreamT` to `SerialT`
8−* Deprecate `runStreamT`, rename to `runSerialT`
9+ * `runStreamT` to `runSerialT`
9−* Deprecate `ZipStream`, rename to `ZipSerial`
10+ * `ZipStream` to `ZipSerial`
10−* Deprecate `runZipStream`, rename to `runZipSerial`
11+ * `runZipStream` to `runZipSerial`
11−* Deprecate `Streaming`, rename to `IsStream`
12+ * `Streaming` to `IsStream`
12−* Deprecate `runStreaming`, rename to `runStream`
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
13
23
14## 0.1.2
24## 0.1.2
15
25
benchmark/BenchmarkOps.hs+3−3
@@ -8,7 +8,7 @@
8module BenchmarkOps where
8module BenchmarkOps where
9
9
10import Prelude
10import Prelude
11− (Monad, Int, (+), id, ($), (.), return, fmap, even, (>), (<=),
11+ (Monad, Int, (+), ($), (.), return, fmap, even, (>), (<=),
12 subtract, undefined, Maybe)
12 subtract, undefined, Maybe)
13
13
14import qualified Streamly as S
14import qualified Streamly as S
@@ -73,7 +73,7 @@ runStream = S.runSerialT
73
73
74toNull = runStream
74toNull = runStream
75toList = S.toList
75toList = S.toList
76−foldl = S.foldl (+) 0 id
76+foldl = S.foldl' (+) 0
77last = S.last
77last = S.last
78
78
79-------------------------------------------------------------------------------
79-------------------------------------------------------------------------------
@@ -84,7 +84,7 @@ last = S.last
84transform :: Monad m => Stream m a -> m ()
84transform :: Monad m => Stream m a -> m ()
85transform = runStream
85transform = runStream
86
86
87−scan = transform . S.scan (+) 0 id
87+scan = transform . S.scanl' (+) 0
88map = transform . fmap (+1)
88map = transform . fmap (+1)
89mapM = transform . S.mapM return
89mapM = transform . S.mapM return
90filterEven = transform . S.filter even
90filterEven = transform . S.filter even
src/Streamly/Prelude.hs+71−20
@@ -31,9 +31,12 @@ module Streamly.Prelude
31 -- ** General Folds
31 -- ** General Folds
32 , foldr
32 , foldr
33 , foldrM
33 , foldrM
34− , scan
35− , foldl
34+ , foldl'
36− , foldlM
35+ , foldlM'
36+ , scanl'
37+ , scanx
38+ , foldx
39+ , foldxM
37 , uncons
40 , uncons
38
41
39 -- ** Special Folds
42 -- ** Special Folds
@@ -76,6 +79,10 @@ module Streamly.Prelude
76 , fromHandle
79 , fromHandle
77 , toHandle
80 , toHandle
78
81
82+ -- * Deprecated
83+ , scan
84+ , foldl
85+ , foldlM
79 )
86 )
80where
87where
81
88
@@ -154,9 +161,12 @@ fromHandle h = fromStream go
154-- Elimination
161-- Elimination
155------------------------------------------------------------------------------
162------------------------------------------------------------------------------
156
163
157−-- Parallel variants of folds?
164+-- | Lazy right associative fold. For example, to fold a stream into a list:
158−
165+--
159−-- | Right fold.
166+-- @
167+-- >> runIdentity $ foldr (:) [] (serially $ each [1,2,3])
168+-- [1,2,3]
169+-- @
160foldr :: (IsStream t, Monad m) => (a -> b -> b) -> b -> t m a -> m b
170foldr :: (IsStream t, Monad m) => (a -> b -> b) -> b -> t m a -> m b
161foldr step acc m = go (toStream m)
171foldr step acc m = go (toStream m)
162 where
172 where
@@ -166,7 +176,13 @@ foldr step acc m = go (toStream m)
166 yield a (Just x) = go x >>= \b -> return (step a b)
176 yield a (Just x) = go x >>= \b -> return (step a b)
167 in (runStream m1) Nothing stop yield
177 in (runStream m1) Nothing stop yield
168
178
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+-- @
170{-# INLINE foldrM #-}
186{-# INLINE foldrM #-}
171foldrM :: (IsStream t, Monad m) => (a -> b -> m b) -> b -> t m a -> m b
187foldrM :: (IsStream t, Monad m) => (a -> b -> m b) -> b -> t m a -> m b
172foldrM step acc m = go (toStream m)
188foldrM step acc m = go (toStream m)
@@ -177,10 +193,13 @@ foldrM step acc m = go (toStream m)
177 yield a (Just x) = (go x) >>= (step a)
193 yield a (Just x) = (go x) >>= (step a)
178 in (runStream m1) Nothing stop yield
194 in (runStream m1) Nothing stop yield
179
195
180−-- | Scan left. A strict left fold which accumulates the result of its reduction steps inside a stream, from left.
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.
181−{-# INLINE scan #-}
200+{-# INLINE scanx #-}
182−scan :: IsStream t => (x -> a -> x) -> x -> (x -> b) -> t m a -> t m b
201+scanx :: 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
202+scanx step begin done m = cons (done begin) $ fromStream $ go (toStream m) begin
184 where
203 where
185 go m1 !acc = Stream $ \_ stp yld ->
204 go m1 !acc = Stream $ \_ stp yld ->
186 let stop = stp
205 let stop = stp
@@ -190,12 +209,26 @@ scan step begin done m = cons (done begin) $ fromStream $ go (toStream m) begin
190 in yld (done s) (Just (go x s))
209 in yld (done s) (Just (go x s))
191 in runStream m1 Nothing stop yield
210 in runStream m1 Nothing stop yield
192
211
193−-- | Strict left fold. This is typed to work with the foldl package. To use
212+{-# DEPRECATED scan "Please use scanx instead." #-}
194−-- it normally just pass 'id' as the third argument.
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.
195−{-# INLINE foldl #-}
228+{-# INLINE foldx #-}
196−foldl :: (IsStream t, Monad m)
229+foldx :: (IsStream t, Monad m)
197 => (x -> a -> x) -> x -> (x -> b) -> t m a -> m b
230 => (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
199 where
232 where
200 {-# NOINLINE get #-}
233 {-# NOINLINE get #-}
201 get m1 =
234 get m1 =
@@ -216,12 +249,21 @@ foldl step begin done m = get $ go (toStream m) begin
216 Just x -> (runStream (go x s)) Nothing undefined yld
249 Just x -> (runStream (go x s)) Nothing undefined yld
217 in (runStream m1) Nothing stop yield
250 in (runStream m1) Nothing stop yield
218
251
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+
219-- XXX replace the recursive "go" with explicit continuations.
262-- XXX replace the recursive "go" with explicit continuations.
220−-- | Strict left fold, with monadic step function. This is typed to work
263+-- | Like 'foldx', but with a monadic step function.
221−-- with the foldl package. To use directly pass 'id' as the third argument.
222−foldlM :: (IsStream t, Monad m)
264+foldxM :: (IsStream t, Monad m)
223 => (x -> a -> m x) -> m x -> (x -> m b) -> t m a -> m b
265 => (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)
225 where
267 where
226 go !acc m1 =
268 go !acc m1 =
227 let stop = acc >>= done
269 let stop = acc >>= done
@@ -229,6 +271,15 @@ foldlM step begin done m = go begin (toStream m)
229 yield a (Just x) = acc >>= \b -> go (step b a) x
271 yield a (Just x) = acc >>= \b -> go (step b a) x
230 in (runStream m1) Nothing stop yield
272 in (runStream m1) Nothing stop yield
231
273
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+
232-- | Decompose a stream into its head and tail. If the stream is empty, returns
283-- | Decompose a stream into its head and tail. If the stream is empty, returns
233-- 'Nothing'. If the stream is non-empty, returns 'Just (a, ma)', where 'a' is
284-- 'Nothing'. If the stream is non-empty, returns 'Just (a, ma)', where 'a' is
234-- the head of the stream and 'ma' its tail.
285-- the head of the stream and 'ma' its tail.
test/Prop.hs+3−3
@@ -5,7 +5,7 @@ module Main (main) where
5import Control.Monad (when)
5import Control.Monad (when)
6import Control.Applicative (ZipList(..))
6import Control.Applicative (ZipList(..))
7import Control.Monad (replicateM)
7import Control.Monad (replicateM)
8−import Data.List (sort)
8+import Data.List (sort, foldl', scanl')
9import GHC.Word (Word8)
9import GHC.Word (Word8)
10
10
11import Test.Hspec.QuickCheck (prop)
11import Test.Hspec.QuickCheck (prop)
@@ -144,7 +144,7 @@ transformOps constr desc t eq = do
144 transform (dropWhile (const False)) $ t . (A.dropWhile (const False))
144 transform (dropWhile (const False)) $ t . (A.dropWhile (const False))
145 prop (desc ++ " dropWhile > 0") $
145 prop (desc ++ " dropWhile > 0") $
146 transform (dropWhile (> 0)) $ t . (A.dropWhile (> 0))
146 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)
148 prop (desc ++ "reverse") $ transform reverse $ t . A.reverse
148 prop (desc ++ "reverse") $ transform reverse $ t . A.reverse
149
149
150wrapMaybe :: Eq a1 => ([a1] -> a2) -> [a1] -> Maybe a2
150wrapMaybe :: Eq a1 => ([a1] -> a2) -> [a1] -> Maybe a2
@@ -164,7 +164,7 @@ eliminationOps constr desc t = do
164 -- Elimination
164 -- Elimination
165 prop (desc ++ " null") $ eliminateOp constr null $ A.null . t
165 prop (desc ++ " null") $ eliminateOp constr null $ A.null . t
166 prop (desc ++ " foldl") $
166 prop (desc ++ " foldl") $
167− eliminateOp constr (foldl (+) 0) $ (A.foldl (+) 0 id) . t
167+ eliminateOp constr (foldl' (+) 0) $ (A.foldl' (+) 0) . t
168 prop (desc ++ " all") $ eliminateOp constr (all even) $ (A.all even) . t
168 prop (desc ++ " all") $ eliminateOp constr (all even) $ (A.all even) . t
169 prop (desc ++ " any") $ eliminateOp constr (any even) $ (A.any even) . t
169 prop (desc ++ " any") $ eliminateOp constr (any even) $ (A.any even) . t
170 prop (desc ++ " length") $ eliminateOp constr length $ A.length . t
170 prop (desc ++ " length") $ eliminateOp constr length $ A.length . t