@@ -23,6 +23,10 @@ module Streamly.Internal.Data.Stream.Bottom
24 , foldContinue
24 , foldContinue
25 , foldBreak
25 , foldBreak
27 -- * Scans
31 -- * Scans
@@ -61,10 +65,13 @@ where
61#include "inline.hs"
65#include "inline.hs"
63import Control.Monad.IO.Class (MonadIO(..))
67import Control.Monad.IO.Class (MonadIO(..))
68+import GHC.Types (SPEC(..))
64import Streamly.Internal.Data.Fold.Type (Fold (..))
69import Streamly.Internal.Data.Fold.Type (Fold (..))
65import Streamly.Internal.Data.Time.Units (AbsTime, RelTime64, addToAbsTime64)
70import Streamly.Internal.Data.Time.Units (AbsTime, RelTime64, addToAbsTime64)
66import Streamly.Internal.Data.Unboxed (Unbox)
71import Streamly.Internal.Data.Unboxed (Unbox)
72+import Streamly.Internal.Data.Producer.Type (Producer(..))
67import Streamly.Internal.System.IO (defaultChunkSize)
73import Streamly.Internal.System.IO (defaultChunkSize)
74+import Streamly.Internal.Data.SVar.Type (defState)
69import qualified Streamly.Internal.Data.Array.Unboxed.Type as A
76import qualified Streamly.Internal.Data.Array.Unboxed.Type as A
70import qualified Streamly.Internal.Data.Fold as Fold
77import qualified Streamly.Internal.Data.Fold as Fold
@@ -214,21 +221,127 @@ fold fl strm = D.fold fl $ D.fromStreamK $ toStreamK strm
215{-# INLINE foldBreak #-}
222{-# INLINE foldBreak #-}
216foldBreak :: Monad m => Fold m a b -> Stream m a -> m (b, Stream m a)
223foldBreak :: Monad m => Fold m a b -> Stream m a -> m (b, Stream m a)
218−-- XXX This shows quadratic performance when used recursively perhaps because
219−-- of StreamK to StreamD conversions not getting eliminated sue to recursion.
220−foldBreak fl (Stream strm) = fmap f $ D.foldBreak fl $ D.fromStreamK strm
224+foldBreak fl strm = fmap f $ K.foldBreak fl (toStreamK strm)
224− f (b, str) = (b, Stream (D.toStreamK str))
228+ f (b, str) = (b, fromStreamK str)
230+-- XXX The quadratic slowdown in recursive use is because recursive function
231+-- cannot be inlined and StreamD/StreamK conversions pile up and cannot be
232+-- eliminated by rewrite rules.
234+-- | Like 'foldBreak' but fuses.
236+-- /Note:/ Unlike 'foldBreak', recursive application on the resulting stream
237+-- would lead to quadratic slowdown. If you need recursion with fusion (within
238+-- one iteration of recursion) use StreamD.foldBreak directly.
241+{-# INLINE foldBreak2 #-}
242+foldBreak2 :: Monad m => Fold m a b -> Stream m a -> m (b, Stream m a)
243+foldBreak2 fl strm = fmap f $ D.foldBreak fl $ toStreamD strm
247+ f (b, str) = (b, fromStreamD str)
249+-- | Fold resulting in either breaking the stream or continuation of the fold
250+-- Instead of supplying the input stream in one go we can run the fold multiple
251+-- times each time supplying the next segment of the input stream. If the fold
252+-- has not yet finished it returns a fold that can be run again otherwise it
253+-- returns the fold result and the residual stream.
256+{-# INLINE foldEither #-}
257+foldEither :: Monad m =>
258+ Fold m a b -> Stream m a -> m (Either (Fold m a b) (b, Stream m a))
226−foldBreak fl strm = fmap f $ K.foldBreak fl (toStreamK strm)
259+foldEither fl strm = fmap (fmap f) $ K.foldEither fl $ toStreamK strm
230 f (b, str) = (b, fromStreamK str)
263 f (b, str) = (b, fromStreamK str)
265+-- | Like 'foldEither' but fuses. However, recursive application on resulting
266+-- stream would lead to quadratic slowdown.
269+{-# INLINE foldEither2 #-}
270+foldEither2 :: Monad m =>
271+ Fold m a b -> Stream m a -> m (Either (Fold m a b) (b, Stream m a))
272+foldEither2 fl strm = fmap (fmap f) $ D.foldEither fl $ toStreamD strm
276+ f (b, str) = (b, fromStreamD str)
278+-- XXX Array folds can be implemented using this.
279+-- foldContainers? Specialized to foldArrays.
281+-- | Generate streams from individual elements of a stream and fold the
282+-- concatenation of those streams using the supplied fold. Return the result of
283+-- the fold and residual stream.
285+-- For example, this can be used to efficiently fold an Array Word8 stream
286+-- using Word8 folds.
288+-- The outer stream forces CPS to allow scalable appends and the inner stream
289+-- forces direct style for stream fusion.
292+{-# INLINE foldConcat #-}
293+foldConcat :: Monad m =>
294+ Producer m a b -> Fold m b c -> Stream m a -> m (c, Stream m a)
296+ (Producer pstep pinject pextract)
297+ (Fold fstep begin done)
302+ Fold.Partial fs -> go fs streamK
303+ Fold.Done fb -> return (fb, fromStreamK streamK)
307+ streamK = toStreamK stream
312+ return (r, fromStreamK K.nil)
315+ res <- go1 SPEC acc st
319+ return (r, fromStreamK K.nil)
322+ return (b, fromStreamK (K.fromPure x))
325+ res <- go1 SPEC acc st
330+ return (b, fromStreamK (x `K.cons` r))
331+ in K.foldStream defState yieldk single stop m1
340+ Fold.Done b -> return $ Right (b, s)
341+ Fold.Partial fs1 -> go1 SPEC fs1 s
342+ D.Skip s -> go1 SPEC fs s
343+ D.Stop -> return $ Left fs
232------------------------------------------------------------------------------
345------------------------------------------------------------------------------
233-- Transformation
346-- Transformation
234------------------------------------------------------------------------------
347------------------------------------------------------------------------------