@@ -146,16 +146,10 @@ module Streamly.Fold
146 -- ** Filtering
146 -- ** Filtering
147 , lfilter
147 , lfilter
148 , lfilterM
148 , lfilterM
156− , ldeleteBy
149+ -- , ldeleteBy
157− , luniq
150+ -- , luniq
159 -- ** Mapping Filters
153 -- ** Mapping Filters
160 , lmapMaybe
154 , lmapMaybe
161 , lmapMaybeM
155 , lmapMaybeM
@@ -174,23 +168,36 @@ module Streamly.Fold
174 , lreverse
168 , lreverse
177− -- * Stream Splitting Operations
171+ -- * Parsing
178− -- ** Spanning
172+ -- ** Trimming
179− -- | Spanning splits the input into two groups and applies two different
173+ , ltake
180− -- folds on each group.
174+ -- , lrunFor -- time
182− -- Element unaware spanning
183+ -- ** Breaking
183 , splitAt
186 , splitAt
187+ -- , splitIn -- time
185− -- Element aware spanning
189+ -- By elements
187− , break
191+ , break -- breakPre
188 -- , spanBy
194 -- , spanBy
189 -- , spanRollingBy
195 -- , spanRollingBy
191− -- ** Grouping
197+ -- By sequences
192− -- | Grouping splits the stream into groups and applies the supplied fold
198+ -- breakOnSeq
193− -- on each group.
199+
195 -- In imperative terms grouped folding can be considered as a nested loop
202 -- In imperative terms grouped folding can be considered as a nested loop
196 -- where we loop over the stream to group elements and then loop over
203 -- where we loop over the stream to group elements and then loop over
@@ -205,23 +212,17 @@ module Streamly.Fold
205 -- groups in memory and then map a fold on it to fold the groups. This kind
212 -- groups in memory and then map a fold on it to fold the groups. This kind
206 -- of grouping and folding would not work well when the group size is big.
213 -- of grouping and folding would not work well when the group size is big.
208− -- Element unaware grouping
215+ -- *** By Chunks
209− , groupsOf
216+ , chunksOf
210− , intervalsOf
217+ , spellsOf
212− -- Element aware grouping
219+ -- *** By Elements
216− , grouped -- XXX experimental
218− -- ** Splitting by an Element
219 , splitBy
220 , splitBy
220 , splitSuffixBy
221 , splitSuffixBy
221 -- , splitPrefixBy
222 -- , splitPrefixBy
222 , wordsBy
223 , wordsBy
224− -- ** Splitting on a Sequence
225+ -- *** By Sequences
225 , splitOn
226 , splitOn
226 , splitSuffixOn
227 , splitSuffixOn
227 -- , splitPrefixOn
228 -- , splitPrefixOn
@@ -237,7 +238,12 @@ module Streamly.Fold
237 -- , splitSuffixOnAny
238 -- , splitSuffixOnAny
238 -- , splitPrefixOnAny
239 -- , splitPrefixOnAny
240− -- ** Distributing
246+ -- * Distributing
242 -- The 'Applicative' instance of a distributing 'Fold' distributes one copy
248 -- The 'Applicative' instance of a distributing 'Fold' distributes one copy
243 -- of the stream to each fold and combines the results using a function.
249 -- of the stream to each fold and combines the results using a function.
@@ -271,7 +277,7 @@ module Streamly.Fold
272 , distribute
278 , distribute
274− -- ** Partitioning
280+ -- * Partitioning
276 -- Direct items in the input stream to different folds using a function to
282 -- Direct items in the input stream to different folds using a function to
277 -- select the fold. This is useful to demultiplex the input stream.
283 -- select the fold. This is useful to demultiplex the input stream.
@@ -280,21 +286,15 @@ module Streamly.Fold
281 , classify
287 , classify
283− -- ** Unzipping
289+ -- * Unzipping
285 , unzipWith
291 , unzipWith
286 , unzipWithM
292 , unzipWithM
288− -- ** Nested Folds
294+ -- * Nested Folds
289 -- , concatMap
295 -- , concatMap
290− -- , groupsOf
296+ -- , chunksOf
291 , duplicate -- experimental
297 , duplicate -- experimental
295− -- | Scans that can be used to split and fold a stream using 'grouped'.
@@ -303,7 +303,7 @@ import Control.Monad (void)
303import Control.Monad.IO.Class (MonadIO(..))
303import Control.Monad.IO.Class (MonadIO(..))
304import Data.Functor.Identity (Identity)
304import Data.Functor.Identity (Identity)
305import Data.Map.Strict (Map)
305import Data.Map.Strict (Map)
306−import Data.Maybe (fromJust, isJust)
306+import Data.Maybe (fromJust, isJust, isNothing)
308import Foreign.Storable (Storable(..))
308import Foreign.Storable (Storable(..))
309import Prelude
309import Prelude
@@ -970,6 +970,9 @@ ltakeWhile predicate (Fold step initial done) = Fold step' initial' done'
970-- >>> splitAt_ 4 [1,2,3]
970-- >>> splitAt_ 4 [1,2,3]
971-- > ([1,2,3],[])
971-- > ([1,2,3],[])
973+-- This can be considered as a two-fold version of 'ltake' where we take both
974+-- the segments instead of discarding the leftover.
973-- @since 0.7.0
976-- @since 0.7.0
974{-# INLINE splitAt #-}
977{-# INLINE splitAt #-}
@@ -997,39 +1000,43 @@ splitAt n (Fold stepL initialL extractL) (Fold stepR initialR extractR) =
997-- | Group the input stream into groups of @n@ elements each and then fold each
1000-- | Group the input stream into groups of @n@ elements each and then fold each
998-- group using the provided fold function.
1001-- group using the provided fold function.
1000−-- >> S.toList $ FL.groupsOf 2 FL.sum (S.enumerateFromTo 1 10)
1003+-- >> S.toList $ FL.chunksOf 2 FL.sum (S.enumerateFromTo 1 10)
1001-- > [3,7,11,15,19]
1004-- > [3,7,11,15,19]
1006+-- This can be considered as an n-fold version of 'ltake' where we apply
1007+-- 'ltake' repeatedly on the leftover stream until the stream exhausts.
1003-- @since 0.7.0
1009-- @since 0.7.0
1004−{-# INLINE groupsOf #-}
1010+{-# INLINE chunksOf #-}
1005−groupsOf
1011+chunksOf
1006 :: (IsStream t, Monad m)
1012 :: (IsStream t, Monad m)
1007 => Int -> Fold m a b -> t m a -> t m b
1013 => Int -> Fold m a b -> t m a -> t m b
1008−groupsOf n f m = D.fromStreamD $ D.groupsOf n f (D.toStreamD m)
1014+chunksOf n f m = D.fromStreamD $ D.groupsOf n f (D.toStreamD m)
1010-- | Transform a fold from a pure input to a 'Maybe' input, consuming only
1016-- | Transform a fold from a pure input to a 'Maybe' input, consuming only
1011-- 'Just' values.
1017-- 'Just' values.
1012lcatMaybes :: Monad m => Fold m a b -> Fold m (Maybe a) b
1018lcatMaybes :: Monad m => Fold m a b -> Fold m (Maybe a) b
1013lcatMaybes = lfilter isJust . lmap fromJust
1019lcatMaybes = lfilter isJust . lmap fromJust
1021+-- XXX we can implement this by repeatedly applying the 'lrunFor' fold.
1015-- XXX add this example after fixing the serial stream rate control
1022-- XXX add this example after fixing the serial stream rate control
1016−-- >>> S.toList $ S.take 5 $ intervalsOf 1 FL.sum $ constRate 2 $ S.enumerateFrom 1
1023+-- >>> S.toList $ S.take 5 $ spellsOf 1 FL.sum $ constRate 2 $ S.enumerateFrom 1
1017-- > [3,7,11,15,19]
1024-- > [3,7,11,15,19]
1019-- | Group the input stream into windows of @n@ second each and then fold each
1026-- | Group the input stream into windows of @n@ second each and then fold each
1020-- group using the provided fold function.
1027-- group using the provided fold function.
1022-- @since 0.7.0
1029-- @since 0.7.0
1023−{-# INLINE intervalsOf #-}
1030+{-# INLINE spellsOf #-}
1024−intervalsOf
1031+spellsOf
1025 :: (IsStream t, MonadAsync m)
1032 :: (IsStream t, MonadAsync m)
1026 => Double -> Fold m a b -> t m a -> t m b
1033 => Double -> Fold m a b -> t m a -> t m b
1027−intervalsOf n f m = grouped (lcatMaybes f) s
1034+spellsOf n f m = splitSuffixBy' isNothing (lcatMaybes f) s
1029− s = S.map (\x -> (Just x, False)) m `parallel` S.repeatM timeout
1036+ s = S.map Just m `parallel` S.repeatM timeout
1030 timeout = do
1037 timeout = do
1031 liftIO $ threadDelay (round $ n * 1000000)
1038 liftIO $ threadDelay (round $ n * 1000000)
1032− return (Nothing, True)
1039+ return Nothing
1034------------------------------------------------------------------------------
1041------------------------------------------------------------------------------
1035-- Element Aware APIs
1042-- Element Aware APIs
@@ -1039,18 +1046,17 @@ intervalsOf n f m = grouped (lcatMaybes f) s
1039-- Binary APIs
1046-- Binary APIs
1040------------------------------------------------------------------------------
1047------------------------------------------------------------------------------
1043-- | Break the input stream into two groups, the first group takes the input as
1049-- | Break the input stream into two groups, the first group takes the input as
1044-- long as the predicate applied to the first element of the stream and next
1050-- long as the predicate applied to the first element of the stream and next
1045-- input element holds 'True', the second group takes the rest of the input.
1051-- input element holds 'True', the second group takes the rest of the input.
1048 :: Monad m
1054 :: Monad m
1049 => (a -> a -> Bool)
1055 => (a -> a -> Bool)
1050 -> Fold m a b
1056 -> Fold m a b
1051 -> Fold m a c
1057 -> Fold m a c
1052 -> Fold m a (b, c)
1058 -> Fold m a (b, c)
1053−spanBy cmp (Fold stepL initialL extractL) (Fold stepR initialR extractR) =
1059+_spanBy cmp (Fold stepL initialL extractL) (Fold stepR initialR extractR) =
1054 Fold step init extract
1060 Fold step init extract
@@ -1071,7 +1077,6 @@ spanBy cmp (Fold stepL initialL extractL) (Fold stepR initialR extractR) =
1071 >>= (\a' -> return (Tuple3' a a' (Tuple' Nothing False)))
1077 >>= (\a' -> return (Tuple3' a a' (Tuple' Nothing False)))
1073 extract (Tuple3' a b _) = (,) <$> extractL a <*> extractR b
1079 extract (Tuple3' a b _) = (,) <$> extractL a <*> extractR b
1076-- | Span as long as the predicate is 'True'. @span p f1 f2@ composes folds
1081-- | Span as long as the predicate is 'True'. @span p f1 f2@ composes folds
1077-- @f1@ and @f2@ such that the composed fold continues sending the input to
1082-- @f1@ and @f2@ such that the composed fold continues sending the input to
@@ -1089,6 +1094,9 @@ spanBy cmp (Fold stepL initialL extractL) (Fold stepR initialR extractR) =
1089-- >>> span_ (< 4) [1,2,3]
1094-- >>> span_ (< 4) [1,2,3]
1090-- > ([1,2,3],[])
1095-- > ([1,2,3],[])
1097+-- This can be considered as a two-fold version of 'ltakeWhile' where we take
1098+-- both the segments instead of discarding the leftover.
1092-- @since 0.7.0
1100-- @since 0.7.0
1093{-# INLINE span #-}
1101{-# INLINE span #-}
@@ -1117,6 +1125,8 @@ span p (Fold stepL initialL extractL) (Fold stepR initialR extractR) =
1117-- folds @f1@ and @f2@ such that @f1@ stops receiving input as soon as the
1125-- folds @f1@ and @f2@ such that @f1@ stops receiving input as soon as the
1118-- predicate @p@ becomes 'True'. The rest of the input is sent to @f2@.
1126-- predicate @p@ becomes 'True'. The rest of the input is sent to @f2@.
1128+-- This is the binary version of 'splitBy'.
1120-- > let break_ p xs = FL.foldl' (FL.break p FL.toList FL.toList) $ S.fromList xs
1130-- > let break_ p xs = FL.foldl' (FL.break p FL.toList FL.toList) $ S.fromList xs
1122-- >>> break_ (< 1) [3,2,1]
1132-- >>> break_ (< 1) [3,2,1]
@@ -1138,17 +1148,16 @@ break
1138 -> Fold m a (b, c)
1148 -> Fold m a (b, c)
1139break p = span (not . p)
1149break p = span (not . p)
1142-- | Like 'spanBy' but applies the predicate in a rolling fashion i.e.
1151-- | Like 'spanBy' but applies the predicate in a rolling fashion i.e.
1143-- predicate is applied to the previous and the next input elements.
1152-- predicate is applied to the previous and the next input elements.
1144−{-# INLINE spanRollingBy #-}
1153+{-# INLINE _spanRollingBy #-}
1145−spanRollingBy
1154+_spanRollingBy
1146 :: Monad m
1155 :: Monad m
1147 => (a -> a -> Bool)
1156 => (a -> a -> Bool)
1148 -> Fold m a b
1157 -> Fold m a b
1149 -> Fold m a c
1158 -> Fold m a c
1150 -> Fold m a (b, c)
1159 -> Fold m a (b, c)
1151−spanRollingBy cmp (Fold stepL initialL extractL) (Fold stepR initialR extractR) =
1160+_spanRollingBy cmp (Fold stepL initialL extractL) (Fold stepR initialR extractR) =
1152 Fold step init extract
1161 Fold step init extract
@@ -1163,33 +1172,11 @@ spanRollingBy cmp (Fold stepL initialL extractL) (Fold stepR initialR extractR)
1163 stepL a input >>= (\a' -> return (Tuple3' a' b (Just input)))
1172 stepL a input >>= (\a' -> return (Tuple3' a' b (Just input)))
1165 extract (Tuple3' a b _) = (,) <$> extractL a <*> extractR b
1174 extract (Tuple3' a b _) = (,) <$> extractL a <*> extractR b
1168------------------------------------------------------------------------------
1176------------------------------------------------------------------------------
1169-- N-ary APIs
1177-- N-ary APIs
1170------------------------------------------------------------------------------
1178------------------------------------------------------------------------------
1172−-- XXX should we use a strict pair?
1174−-- | The splitter returns True if the current element is the last element of
1175−-- the group, otherwise returns false.
1178−{-# INLINE grouped #-}
1180− :: (IsStream t, Monad m)
1184−grouped f m = D.fromStreamD $ D.grouped f (D.toStreamD m)
1186−-- An example of a splitter to be used with grouped.
1187−_newline :: IsStream t => t m Char -> t m (Char,Bool)
1188−_newline m = S.foldrS (\x xs ->
1190− then (x,True) `K.cons` xs
1191− else (x,False) `K.cons` xs) K.nil m
1193-- | @groupsBy cmp f $ S.fromList [a,b,c,...]@ assigns the element @a@ to the
1180-- | @groupsBy cmp f $ S.fromList [a,b,c,...]@ assigns the element @a@ to the
1194-- first group, if @a \`cmp` b@ is 'True' then @b@ is also assigned to the same
1181-- first group, if @a \`cmp` b@ is 'True' then @b@ is also assigned to the same
1195-- group. If @a \`cmp` c@ is 'True' then @c@ is also assigned to the same
1182-- group. If @a \`cmp` c@ is 'True' then @c@ is also assigned to the same
@@ -1292,6 +1279,10 @@ breakOn pat f m = undefined
1292-- >>> splitBy_ (== '.') "a..b"
1279-- >>> splitBy_ (== '.') "a..b"
1293-- > ["a","","b"]
1280-- > ["a","","b"]
1282+-- This can be considered as an n-fold version of 'break' where we apply
1283+-- 'break' successively on the input stream, dropping the first element
1284+-- of the second segment after each break.
1295-- @since 0.7.0
1286-- @since 0.7.0
1296{-# INLINE splitBy #-}
1287{-# INLINE splitBy #-}
@@ -1334,6 +1325,10 @@ splitBy predicate f m =
1335-- > lines = splitSuffixBy (== '\n')
1326-- > lines = splitSuffixBy (== '\n')
1328+-- This can be considered as an n-fold version of 'breakPost' where we apply
1329+-- 'breakPost' successively on the input stream, dropping the first element
1330+-- of the second segment after each break.
1337-- @since 0.7.0
1332-- @since 0.7.0
1338{-# INLINE splitSuffixBy #-}
1333{-# INLINE splitSuffixBy #-}
1339splitSuffixBy
1334splitSuffixBy
@@ -1402,15 +1397,19 @@ wordsBy predicate f m =
1402-- >>> splitSuffixBy'_ (== '.') "a..b.."
1397-- >>> splitSuffixBy'_ (== '.') "a..b.."
1403-- > ["a.",".","b.","."]
1398-- > ["a.",".","b.","."]
1400+-- This can be considered as an n-fold version of 'breakPost' where we apply
1401+-- 'breakPost' successively on the input stream.
1405-- @since 0.7.0
1403-- @since 0.7.0
1406−{-# INLINE _splitSuffixBy' #-}
1404+{-# INLINE splitSuffixBy' #-}
1407−_splitSuffixBy'
1405+splitSuffixBy'
1408 :: (IsStream t, Monad m)
1406 :: (IsStream t, Monad m)
1409 => (a -> Bool) -> Fold m a b -> t m a -> t m b
1407 => (a -> Bool) -> Fold m a b -> t m a -> t m b
1410−_splitSuffixBy' predicate f m = grouped f (S.map (\a -> (a, predicate a)) m)
1408+splitSuffixBy' predicate f m =
1409+ D.fromStreamD $ D.splitSuffixBy' predicate f (D.toStreamD m)
1412------------------------------------------------------------------------------
1411------------------------------------------------------------------------------
1413−-- Split on a delimiter
1412+-- Split on a delimiter sequence
1414------------------------------------------------------------------------------
1413------------------------------------------------------------------------------
1416-- Int list examples for splitOn:
1415-- Int list examples for splitOn:
@@ -1986,6 +1985,6 @@ lconcatMap s f1 f2 = undefined
1986-- -----Fold m a b----|-Fold n a c-|-Fold n a c-|-...-|----Fold m a c
1985-- -----Fold m a b----|-Fold n a c-|-Fold n a c-|-...-|----Fold m a c
1989−lgroupsOf :: Int -> Fold m a b -> Fold m b c -> Fold m a c
1988+lchunksOf :: Int -> Fold m a b -> Fold m b c -> Fold m a c
1990−lgroupsOf n f1 f2 = undefined
1989+lchunksOf n f1 f2 = undefined