on master help sign in
cleanup foldl
commit729ccc8f3b5b8c701cab8790ded1340a2ceac108 authorHarendra Kumar <harendra.kumar@gmail.com> dateMon 12 Mar 2018, 20:55 (9 years ago) parent62420fd
1 file changed+13−31
src/Streamly/Prelude.hs+13−31
src/Streamly/Prelude.hs+13−31
@@ -169,30 +169,6 @@ scan step begin done m = cons (done begin) $ fromStream $ go (toStream m) begin
169169 in yld (done s) (Just (go x s))
170170 in runStream m1 Nothing stop yield
171171
172−-- XXX This more straightforward implementation of fold is almost twice as
173−-- costly as the implementation we are using! Need to figure out what's wrong
174−-- with it. Is it GHC that is not able to optimize this somehow? Or is it
175−-- something else? In fact scan is more optimal than this. The fold we are
176−-- using is actually a @scan@ where we discard the intermediate values!
177−{-
178−foldl :: (Streaming t, Monad m)
179− => (x -> a -> x) -> x -> (x -> b) -> t m a -> m b
180−foldl step begin done m = go begin (toStream m)
181− where
182− go !acc m1 =
183− let stop = return (done acc)
184− yield a Nothing = return (done (step acc a))
185− yield a (Just x) = go (step acc a) x
186− in (runStream m1) Nothing stop yield
187−-}
188−
189−-- XXX We implement fold like a scan but just drop the intermediate steps and
190−-- extract the last step as the only element from the stream. We also use a
191−-- NOINLINE on the extraction function but INLINE the fold function. This seems
192−-- to work well with the GHC simplifier and we get almost 50% reduction in
193−-- cost! Need to figure what's going on with GHC simplifier, why is the simpler
194−-- code above is not optimal.
195−
196172-- | Strict left fold. This is typed to work with the foldl package. To use
197173-- it normally just pass 'id' as the third argument.
198174{-# INLINE foldl #-}
@@ -206,16 +182,20 @@ foldl step begin done m = get $ go (toStream m) begin
206182 yield _ _ = undefined
207183 in (runStream m1) Nothing undefined yield
208184
209− go m1 !acc = Stream $ \_ stp yld ->
210− let
211− stop = yld acc Nothing
212− yield a Nothing = yld (step acc a) Nothing
213− yield a (Just x) =
185+ -- Note, this can be implemented by making a recursive call to "go",
186+ -- however that is more expensive because of unnecessary recursion
187+ -- that cannot be tail call optimized. Unfolding recursion explicitly via
188+ -- continuations is much more efficient.
189+ go m1 !acc = Stream $ \_ _ yld ->
190+ let stop = yld acc Nothing
191+ yield a r =
214192 let s = step acc a
215− in (runStream (go x s)) Nothing stp yld
193+ in case r of
194+ Nothing -> yld s Nothing
195+ Just x -> (runStream (go x s)) Nothing undefined yld
216196 in (runStream m1) Nothing stop yield
217197
218−-- XXX Need to measure perf and optimize like foldl if needed.
198+-- XXX replace the recursive "go" with explicit continuations.
219199-- | Strict left fold, with monadic step function. This is typed to work
220200-- with the foldl package. To use directly pass 'id' as the third argument.
221201foldlM :: (Streaming t, Monad m)
@@ -387,6 +367,7 @@ notElem e m = go (toStream m)
387367length :: (Streaming t, Monad m) => t m a -> m Int
388368length = foldl (\n _ -> n + 1) 0 id
389369
370+-- XXX replace the recursive "go" with continuation
390371-- | Determine the minimum element in a stream.
391372minimum :: (Streaming t, Monad m, Ord a) => t m a -> m (Maybe a)
392373minimum m = go Nothing (toStream m)
@@ -401,6 +382,7 @@ minimum m = go Nothing (toStream m)
401382 Nothing -> Just a
402383 Just e -> Just $ min a e
403384
385+-- XXX replace the recursive "go" with continuation
404386-- | Determine the maximum element in a stream.
405387maximum :: (Streaming t, Monad m, Ord a) => t m a -> m (Maybe a)
406388maximum m = go Nothing (toStream m)