on master help sign in
Update docs, add unimplemented skeletons
e19f645Harendra Kumar
src/Streamly/Internal/Data/Fold/Types.hs+157−37
@@ -108,7 +108,7 @@
108-- However, removing extract altogether may lead to less optimal code in some
108-- However, removing extract altogether may lead to less optimal code in some
109-- cases because the driver of the fold needs to thread around the intermediate
109-- cases because the driver of the fold needs to thread around the intermediate
110-- output to return it if the stream stops before the fold could @Done@. When
110-- output to return it if the stream stops before the fold could @Done@. When
111−-- using this approach, the @splitParse (FL.take filesize)@ benchmark shows a
111+-- using this approach, the @parseMany (FL.take filesize)@ benchmark shows a
112-- 2x worse performance even after ensuring everything fuses. So we keep the
112-- 2x worse performance even after ensuring everything fuses. So we keep the
113-- "extract" approach to ensure better perf in all cases.
113-- "extract" approach to ensure better perf in all cases.
114--
114--
@@ -118,7 +118,9 @@
118-- completes.
118-- completes.
119
119
120module Streamly.Internal.Data.Fold.Types
120module Streamly.Internal.Data.Fold.Types
121+ (
122+ -- * Types
121− ( Step (..)
123+ Step (..)
122 , Fold (..)
124 , Fold (..)
123
125
124 , Fold2 (..)
126 , Fold2 (..)
@@ -126,6 +128,11 @@ module Streamly.Internal.Data.Fold.Types
126 , toListRevF -- experimental
128 , toListRevF -- experimental
127 -- $toListRevF
129 -- $toListRevF
128
130
131+ -- * Generators
132+ , yield
133+ , yieldM
134+
135+ -- * Transformations
129 , lmap
136 , lmap
130 , lmapM
137 , lmapM
131 , lfilter
138 , lfilter
@@ -133,13 +140,22 @@ module Streamly.Internal.Data.Fold.Types
133 , lcatMaybes
140 , lcatMaybes
134 , ltake
141 , ltake
135 , takeSepBy
142 , takeSepBy
143+ , takeByTime
136
144
145+ -- * Distributing
137 , teeWith
146 , teeWith
138 , teeWithFst
147 , teeWithFst
139 , teeWithMin
148 , teeWithMin
149+ , shortest
150+ , longest
151+
152+ -- * Serial Application
140 , splitWith
153 , splitWith
154+ , split_
155+
156+ -- * Nested Application
157+ , concatMap
141 , many
158 , many
142− , takeByTime
143 , lsessionsOf
159 , lsessionsOf
144 , lchunksOf
160 , lchunksOf
145 , lchunksOf2
161 , lchunksOf2
@@ -148,6 +164,7 @@ module Streamly.Internal.Data.Fold.Types
148 , initialize
164 , initialize
149 , runStep
165 , runStep
150
166
167+ -- * Misc
151 , GenericRunner(..) -- Is used in multiple step functions
168 , GenericRunner(..) -- Is used in multiple step functions
152 )
169 )
153where
170where
@@ -174,10 +191,13 @@ import Prelude hiding (concatMap)
174-- Monadic left folds
191-- Monadic left folds
175------------------------------------------------------------------------------
192------------------------------------------------------------------------------
176
193
177−-- | This is the intermediate state in the workflow of a @Fold@. @Partial@
194+-- | Represents the result of the @step@ of a 'Fold'. 'Partial' returns an
178−-- represents a new intermediate value available to be extracted. @Done@
195+-- intermediate state of the fold, the fold step can be called again with the
179−-- represents that the fold has been terminated and won't be processed
196+-- state or the driver can use @extract@ on the state to get the result out.
180−-- further.
197+-- 'Done' returns the final result and the fold cannot be driven further.
198+--
199+-- /Internal/
200+--
181{-# ANN type Step Fuse #-}
201{-# ANN type Step Fuse #-}
182data Step s b
202data Step s b
183 = Partial !s
203 = Partial !s
@@ -185,6 +205,9 @@ data Step s b
185
205
186-- | A bifunctor instance on 'Step'. @first@ maps on the value held by 'Partial'
206-- | A bifunctor instance on 'Step'. @first@ maps on the value held by 'Partial'
187-- and @second@ maps on the result held by 'Done'.
207-- and @second@ maps on the result held by 'Done'.
208+--
209+-- /Internal/
210+--
188instance Bifunctor Step where
211instance Bifunctor Step where
189 {-# INLINE bimap #-}
212 {-# INLINE bimap #-}
190 bimap f _ (Partial a) = Partial (f a)
213 bimap f _ (Partial a) = Partial (f a)
@@ -202,17 +225,24 @@ instance Bifunctor Step where
202-- @
225-- @
203-- fmap = 'second'
226-- fmap = 'second'
204-- @
227-- @
228+--
229+-- /Internal/
230+--
205instance Functor (Step s) where
231instance Functor (Step s) where
206 {-# INLINE fmap #-}
232 {-# INLINE fmap #-}
207 fmap = second
233 fmap = second
208
234
235+-- | The type @Fold m a b@ having constructor @Fold step initial extract@
209−-- | Represents a left fold over an input stream of values of type @a@ to a
236+-- represents a left fold over an input stream of values of type @a@ to a
210−-- single value of type @b@ in 'Monad' @m@.
237+-- single value of type @b@ in 'Monad' @m@. The constructor is not exposed via
238+-- exposed modules, smart constructors are provided to create folds.
211--
239--
212−-- The fold uses an intermediate state @s@ as accumulator. The @step@ function
240+-- The fold uses an intermediate state @s@ as accumulator, the type @s@ is
213−-- updates the state and returns the new state. When the fold is done
241+-- specific to the fold. The initial value of the fold state @s@ is returned by
214−-- the final result of the fold is extracted from the intermediate state
242+-- @initial@. The @step@ function consumes an input and either returns the
243+-- final result @b@ if the fold is done or the next intermediate state (see
244+-- 'Step'). At any point the fold driver can extract the result from the
215−-- using the @extract@ function.
245+-- intermediate state using the @extract@ function.
216--
246--
217-- @since 0.7.0
247-- @since 0.7.0
218
248
@@ -244,14 +274,37 @@ instance Functor m => Functor (Fold m a) where
244 step s b = fmap2 f (step1 s b)
274 step s b = fmap2 f (step1 s b)
245 fmap2 g = fmap (fmap g)
275 fmap2 g = fmap (fmap g)
246
276
277+-- This is the dual of stream "yield".
278+--
279+-- | A fold that always yields a pure value without consuming any input.
280+--
281+-- /Unimplemented/
282+--
283+{-# INLINE yield #-}
284+yield :: -- Monad m =>
285+ b -> Fold m a b
286+yield = undefined
287+
288+-- This is the dual of stream "yieldM".
289+--
290+-- | A fold that always yields the result of an effectful action without
291+-- consuming any input.
292+--
293+-- /Unimplemented/
294+--
295+{-# INLINE yieldM #-}
296+yieldM :: -- Monad m =>
297+ m b -> Fold m a b
298+yieldM = undefined
299+
247−-- {-# ANN type Step Fuse #-}
300+{-# ANN type Step Fuse #-}
248−-- data SeqFoldState sl f sr = SeqFoldL !sl | SeqFoldR !f !sr
249data SeqFoldState sl f sr = SeqFoldL sl | SeqFoldR f sr
301data SeqFoldState sl f sr = SeqFoldL sl | SeqFoldR f sr
250
302
251-- | Sequential fold application. Apply two folds sequentially to an input
303-- | Sequential fold application. Apply two folds sequentially to an input
252-- stream. The input is provided to the first fold, when it is done the
304-- stream. The input is provided to the first fold, when it is done the
253−-- remaining input is provided to the second fold. When the second fold is
305+-- remaining input is provided to the second fold. When the second fold is done
254−-- done, the outputs of the two folds are combined using the supplied function.
306+-- or if the input stream is over, the outputs of the two folds are combined
307+-- using the supplied function.
255--
308--
256-- Note: This is a folding dual of appending streams using
309-- Note: This is a folding dual of appending streams using
257-- 'Streamly.Prelude.serial', it splits the streams using two folds and zips
310-- 'Streamly.Prelude.serial', it splits the streams using two folds and zips
@@ -260,8 +313,7 @@ data SeqFoldState sl f sr = SeqFoldL sl | SeqFoldR f sr
260-- /Internal/
313-- /Internal/
261--
314--
262{-# INLINE splitWith #-}
315{-# INLINE splitWith #-}
263−splitWith :: Monad m =>
264− (a -> b -> c) -> Fold m x a -> Fold m x b -> Fold m x c
316+splitWith :: Monad m => (a -> b -> c) -> Fold m x a -> Fold m x b -> Fold m x c
265splitWith func (Fold stepL initialL extractL) (Fold stepR initialR extractR) =
317splitWith func (Fold stepL initialL extractL) (Fold stepR initialR extractR) =
266 Fold step initial extract
318 Fold step initial extract
267
319
@@ -288,7 +340,17 @@ splitWith func (Fold stepL initialL extractL) (Fold stepR initialR extractR) =
288 rR <- extractR sR
340 rR <- extractR sR
289 return $ func rL rR
341 return $ func rL rR
290
342
343+-- | Same as applicative '*>'. Run two folds serially one after the other
344+-- discarding the result of the first.
345+--
346+-- /Unimplemented/
347+--
348+{-# INLINE split_ #-}
349+split_ :: -- Monad m =>
350+ Fold m x a -> Fold m x b -> Fold m x b
351+split_ _f1 _f2 = undefined
352+
291−-- {-# ANN type GenericRunner Fuse #-}
353+{-# ANN type GenericRunner Fuse #-}
292data GenericRunner sL sR bL bR
354data GenericRunner sL sR bL bR
293 = RunBoth !sL !sR
355 = RunBoth !sL !sR
294 | RunLeft !sL !bR
356 | RunLeft !sL !bR
@@ -299,17 +361,17 @@ data GenericRunner sL sR bL bR
299instance Monad m => Applicative (Fold m a) where
361instance Monad m => Applicative (Fold m a) where
300 {-# INLINE pure #-}
362 {-# INLINE pure #-}
301 pure b = Fold (\() _ -> pure $ Done b) (pure ()) (\() -> pure b)
363 pure b = Fold (\() _ -> pure $ Done b) (pure ()) (\() -> pure b)
302− -- XXX deprecate this?
364+
303 {-# INLINE (<*>) #-}
365 {-# INLINE (<*>) #-}
304 (<*>) = teeWith ($)
366 (<*>) = teeWith ($)
305
367
306−-- | @teeWith f f1 f2@ distributes its input to both @f1@ and @f2@ until both
368+-- | @teeWith k f1 f2@ distributes its input to both @f1@ and @f2@ until both
307−-- of them terminate and combines their output using @f@.
369+-- of them terminate and combines their output using @k@.
308--
370--
309-- /Internal/
371-- /Internal/
310--
372--
311{-# INLINE teeWith #-}
373{-# INLINE teeWith #-}
312−teeWith :: Monad m => (b -> c -> d) -> Fold m a b -> Fold m a c -> Fold m a d
374+teeWith :: Monad m => (a -> b -> c) -> Fold m x a -> Fold m x b -> Fold m x c
313teeWith f (Fold stepL beginL doneL) (Fold stepR beginR doneR) =
375teeWith f (Fold stepL beginL doneL) (Fold stepR beginR doneR) =
314 Fold step begin done
376 Fold step begin done
315
377
@@ -375,6 +437,42 @@ teeWithFst = undefined
375teeWithMin :: (b -> c -> d) -> Fold m a b -> Fold m a c -> Fold m a d
437teeWithMin :: (b -> c -> d) -> Fold m a b -> Fold m a c -> Fold m a d
376teeWithMin = undefined
438teeWithMin = undefined
377
439
440+-- | Shortest alternative. Apply both folds in parallel but choose the result
441+-- from the one which consumed least input i.e. take the shortest succeeding
442+-- fold.
443+--
444+-- /Unimplemented/
445+--
446+{-# INLINE shortest #-}
447+shortest :: -- Monad m =>
448+ Fold m x a -> Fold m x a -> Fold m x a
449+shortest _f1 _f2 = undefined
450+
451+-- | Longest alternative. Apply both folds in parallel but choose the result
452+-- from the one which consumed more input i.e. take the longest succeeding
453+-- fold.
454+--
455+-- /Unimplemented/
456+--
457+{-# INLINE longest #-}
458+longest :: -- Monad m =>
459+ Fold m x a -> Fold m x a -> Fold m x a
460+longest _f1 _f2 = undefined
461+
462+-- | Map a 'Fold' returning function on the result of a 'Fold'.
463+--
464+-- Compare with 'Monad' instance method '>>='. This implementation allows
465+-- stream fusion but has quadratic complexity. This can fuse with other
466+-- operations and can be much faster than 'Monad' instance for small number
467+-- (less than 8) of compositions.
468+--
469+-- /Unimplemented/
470+--
471+{-# INLINE concatMap #-}
472+concatMap :: -- Monad m =>
473+ (b -> Fold m a c) -> Fold m a b -> Fold m a c
474+concatMap _func _fld = undefined
475+
378-- | Combines the outputs of the folds (the type @b@) using their 'Semigroup'
476-- | Combines the outputs of the folds (the type @b@) using their 'Semigroup'
379-- instances.
477-- instances.
380instance (Semigroup b, Monad m) => Semigroup (Fold m a b) where
478instance (Semigroup b, Monad m) => Semigroup (Fold m a b) where
@@ -558,8 +656,15 @@ lcatMaybes = lfilter isJust . lmap fromJust
558-- Parsing
656-- Parsing
559------------------------------------------------------------------------------
657------------------------------------------------------------------------------
560
658
561−-- XXX Incorrect implementation when i <= 0
659+-- | Take at most @n@ input elements and fold them using the supplied fold.
562−-- | Take first @n@ elements from the stream and discard the rest.
660+--
661+-- >>> Stream.fold (Fold.ltake 1 Fold.toList) $ Stream.fromList [1]
662+-- [1]
663+--
664+-- >>> Stream.fold (Fold.ltake (-1) Fold.toList) $ Stream.fromList [1]
665+-- []
666+--
667+-- /Internal/
563--
668--
564-- @since 0.7.0
669-- @since 0.7.0
565{-# INLINE ltake #-}
670{-# INLINE ltake #-}
@@ -581,6 +686,7 @@ ltake n (Fold fstep finitial fextract) = Fold step initial extract
581 then return $ Partial s1
686 then return $ Partial s1
582 else Done <$> fextract sres
687 else Done <$> fextract sres
583 Done bres -> return $ Done bres
688 Done bres -> return $ Done bres
689+ -- XXX take 0 case is broken currently
584 | otherwise = Done <$> fextract r
690 | otherwise = Done <$> fextract r
585
691
586 extract (Tuple' _ r) = fextract r
692 extract (Tuple' _ r) = fextract r
@@ -652,6 +758,8 @@ runStep _ _ = undefined
652-- the @split@ fold repeatedly on the input stream and accumulates zero or more
758-- the @split@ fold repeatedly on the input stream and accumulates zero or more
653-- fold results using @collect@.
759-- fold results using @collect@.
654--
760--
761+-- Stops when @collect@ stops.
762+--
655-- /Internal/
763-- /Internal/
656--
764--
657-- /See also: Streamly.Prelude.concatMap, Streamly.Prelude.foldMany/
765-- /See also: Streamly.Prelude.concatMap, Streamly.Prelude.foldMany/
@@ -663,10 +771,7 @@ many (Fold fstep finitial fextract) (Fold step1 initial1 extract1) =
663
771
664 where
772 where
665
773
666− initial = do
667− ps <- initial1
774+ initial = Tuple' <$> initial1 <*> finitial
668− fs <- finitial
669− pure (Tuple' ps fs)
670
775
671 {-# INLINE step #-}
776 {-# INLINE step #-}
672 step (Tuple' st fs) a = do
777 step (Tuple' st fs) a = do
@@ -688,11 +793,15 @@ many (Fold fstep finitial fextract) (Fold step1 initial1 extract1) =
688 Partial s1 -> fextract s1
793 Partial s1 -> fextract s1
689 Done x -> return x
794 Done x -> return x
690
795
691−-- XXX Replace this with the previous implementation using `many`
796+-- | @lchunksOf n split collect@ repeatedly applies the @split@ fold to chunks
692−-- XXX The only difference from the previous implementation is that the `if`
693−-- statement encompasses `collect` rather then the other way around.
694−-- | For every n input items, apply the first fold and supply the result to the
797+-- of @n@ items in the input stream and supplies the result to the @collect@
695−-- next fold.
798+-- fold.
799+--
800+-- > lchunksOf n split collect = many collect (ltake n split)
801+--
802+-- Stops when @collect@ stops.
803+--
804+-- /Internal/
696--
805--
697{-# INLINE lchunksOf #-}
806{-# INLINE lchunksOf #-}
698lchunksOf :: Monad m => Int -> Fold m a b -> Fold m b c -> Fold m a c
807lchunksOf :: Monad m => Int -> Fold m a b -> Fold m b c -> Fold m a c
@@ -712,7 +821,7 @@ lchunksOf2 n (Fold step1 initial1 extract1) (Fold2 step2 inject2 extract2) =
712 then do
821 then do
713 res <- step1 r1 a
822 res <- step1 r1 a
714 case res of
823 case res of
715− Partial sres -> return $ Tuple3' (i + 1) sres r2
824+ Partial s -> return $ Tuple3' (i + 1) s r2
716 Done b -> do
825 Done b -> do
717 s <- initial1
826 s <- initial1
718 r21 <- step2 r2 b
827 r21 <- step2 r2 b
@@ -728,7 +837,13 @@ lchunksOf2 n (Fold step1 initial1 extract1) (Fold2 step2 inject2 extract2) =
728 acc2 <- step2 r2 res
837 acc2 <- step2 r2 res
729 extract2 acc2
838 extract2 acc2
730
839
731−-- XXX zip the streams with timestamps
840+-- | @takeByTime n fold@ uses @fold@ to fold the input items arriving within a
841+-- window of first @n@ seconds.
842+--
843+-- Stops when @fold@ stops or when the timeout occurs.
844+--
845+-- /Internal/
846+--
732{-# INLINE takeByTime #-}
847{-# INLINE takeByTime #-}
733takeByTime :: MonadAsync m => Double -> Fold m a b -> Fold m a b
848takeByTime :: MonadAsync m => Double -> Fold m a b -> Fold m a b
734takeByTime n (Fold step initial done) = Fold step' initial' done'
849takeByTime n (Fold step initial done) = Fold step' initial' done'
@@ -785,6 +900,11 @@ takeByTime n (Fold step initial done) = Fold step' initial' done'
785-- -----Fold m a b----|-Fold n a c-|-Fold n a c-|-...-|----Fold m a c
900-- -----Fold m a b----|-Fold n a c-|-Fold n a c-|-...-|----Fold m a c
786--
901--
787-- @
902-- @
903+--
904+-- > lsessionsOf n split collect = many collect (takeByTime n split)
905+--
906+-- /Internal/
907+--
788{-# INLINE lsessionsOf #-}
908{-# INLINE lsessionsOf #-}
789lsessionsOf :: MonadAsync m => Double -> Fold m a b -> Fold m b c -> Fold m a c
909lsessionsOf :: MonadAsync m => Double -> Fold m a b -> Fold m b c -> Fold m a c
790lsessionsOf n split collect = many collect (takeByTime n split)
910lsessionsOf n split collect = many collect (takeByTime n split)