@@ -169,30 +169,6 @@ scan step begin done m = cons (done begin) $ fromStream $ go (toStream m) begin
169 in yld (done s) (Just (go x s))
169 in yld (done s) (Just (go x s))
170 in runStream m1 Nothing stop yield
170 in runStream m1 Nothing stop yield
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!
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)
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
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.
196-- | Strict left fold. This is typed to work with the foldl package. To use
172-- | Strict left fold. This is typed to work with the foldl package. To use
197-- it normally just pass 'id' as the third argument.
173-- it normally just pass 'id' as the third argument.
198{-# INLINE foldl #-}
174{-# INLINE foldl #-}
@@ -206,16 +182,20 @@ foldl step begin done m = get $ go (toStream m) begin
206 yield _ _ = undefined
182 yield _ _ = undefined
207 in (runStream m1) Nothing undefined yield
183 in (runStream m1) Nothing undefined yield
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.
209− go m1 !acc = Stream $ \_ stp yld ->
189+ go m1 !acc = Stream $ \_ _ yld ->
211− stop = yld acc Nothing
190+ let stop = yld acc Nothing
212− yield a Nothing = yld (step acc a) Nothing
191+ yield a r =
214 let s = step acc a
192 let s = step acc a
194+ Nothing -> yld s Nothing
215− in (runStream (go x s)) Nothing stp yld
195+ Just x -> (runStream (go x s)) Nothing undefined yld
216 in (runStream m1) Nothing stop yield
196 in (runStream m1) Nothing stop yield
218−-- XXX Need to measure perf and optimize like foldl if needed.
198+-- XXX replace the recursive "go" with explicit continuations.
219-- | Strict left fold, with monadic step function. This is typed to work
199-- | Strict left fold, with monadic step function. This is typed to work
220-- with the foldl package. To use directly pass 'id' as the third argument.
200-- with the foldl package. To use directly pass 'id' as the third argument.
221foldlM :: (Streaming t, Monad m)
201foldlM :: (Streaming t, Monad m)
@@ -387,6 +367,7 @@ notElem e m = go (toStream m)
387length :: (Streaming t, Monad m) => t m a -> m Int
367length :: (Streaming t, Monad m) => t m a -> m Int
388length = foldl (\n _ -> n + 1) 0 id
368length = foldl (\n _ -> n + 1) 0 id
370+-- XXX replace the recursive "go" with continuation
390-- | Determine the minimum element in a stream.
371-- | Determine the minimum element in a stream.
391minimum :: (Streaming t, Monad m, Ord a) => t m a -> m (Maybe a)
372minimum :: (Streaming t, Monad m, Ord a) => t m a -> m (Maybe a)
392minimum m = go Nothing (toStream m)
373minimum m = go Nothing (toStream m)
@@ -401,6 +382,7 @@ minimum m = go Nothing (toStream m)
401 Nothing -> Just a
382 Nothing -> Just a
402 Just e -> Just $ min a e
383 Just e -> Just $ min a e
385+-- XXX replace the recursive "go" with continuation
404-- | Determine the maximum element in a stream.
386-- | Determine the maximum element in a stream.
405maximum :: (Streaming t, Monad m, Ord a) => t m a -> m (Maybe a)
387maximum :: (Streaming t, Monad m, Ord a) => t m a -> m (Maybe a)
406maximum m = go Nothing (toStream m)
388maximum m = go Nothing (toStream m)