@@ -173,7 +173,7 @@ module Streamly.Internal.Data.Stream.IsStream.Nesting
173 -- -- *** Using Element Separators
173 -- -- *** Using Element Separators
174 , splitOn
174 , splitOn
175 , splitOnSuffix
175 , splitOnSuffix
176− -- , splitOnPrefix
176+ , splitOnPrefix
178 -- , splitBy
178 -- , splitBy
179 , splitWithSuffix
179 , splitWithSuffix
@@ -903,19 +903,16 @@ iterateMapLeftsWith combine f = iterateMapWith combine (either f (const K.nil))
904-- XXX We need takeGE/takeBetween to implement "some" using "many".
904-- XXX We need takeGE/takeBetween to implement "some" using "many".
906−-- | Apply a 'Fold' repeatedly on a stream and emit the parsed values in the
906+-- | Like 'foldMany1' but appends empty fold output if the fold and stream
907−-- output stream.
907+-- termination aligns:
909−-- This is the streaming dual of the 'Streamly.Internal.Data.Fold.many'
912-- >>> f = Fold.takeLE 2 Fold.sum
909-- >>> f = Fold.takeLE 2 Fold.sum
910+-- >>> Stream.toList $ Stream.foldMany f $ Stream.fromList []
912+-- >>> Stream.toList $ Stream.foldMany f $ Stream.fromList [1..9]
913-- >>> Stream.toList $ Stream.foldMany f $ Stream.fromList [1..10]
914-- >>> Stream.toList $ Stream.foldMany f $ Stream.fromList [1..10]
914−-- > [3,7,11,15,19]
915+-- > [3,7,11,15,19,0]
916−-- >>> f = Fold.sliceEndWith Fold.toList
917−-- >>> Stream.toList $ Stream.foldMany f $ Stream.fromList "hello\nworld"
918−-- > ["hello\n","world"]
920-- /Internal/
917-- /Internal/
@@ -927,6 +924,25 @@ foldMany
928foldMany f m = D.fromStreamD $ D.foldMany f (D.toStreamD m)
925foldMany f m = D.fromStreamD $ D.foldMany f (D.toStreamD m)
927+-- | Apply a 'Fold' repeatedly on a stream and emit the fold outputs in the
930+-- To sum every two contiguous elements in a stream:
932+-- >>> f = Fold.takeLE 2 Fold.sum
933+-- >>> Stream.toList $ Stream.foldMany1 f $ Stream.fromList [1..10]
936+-- On an empty stream the output is empty:
938+-- >>> Stream.toList $ Stream.foldMany1 f $ Stream.fromList []
941+-- Note @foldMany1 (takeLE 0)@ would result in an infinite loop in a non-empty
930{-# INLINE foldMany1 #-}
946{-# INLINE foldMany1 #-}
932 :: (IsStream t, Monad m)
948 :: (IsStream t, Monad m)
@@ -988,6 +1004,13 @@ foldIterate _f _i _m = undefined
988-- >>> S.toList $ S.parseMany (PR.line FL.toList) $ S.fromList "hello\nworld"
1004-- >>> S.toList $ S.parseMany (PR.line FL.toList) $ S.fromList "hello\nworld"
989-- > ["hello\n","world"]
1005-- > ["hello\n","world"]
1008+-- foldMany1 f = parseMany (fromFold f)
1011+-- Known Issues: When the parser fails there is no way to get the remaining
991-- /Internal/
1014-- /Internal/
993{-# INLINE parseMany #-}
1016{-# INLINE parseMany #-}
@@ -1201,34 +1224,32 @@ groups = groupsBy (==)
1201-- Splitting - by a predicate
1224-- Splitting - by a predicate
1202------------------------------------------------------------------------------
1225------------------------------------------------------------------------------
1204−-- TODO: Use a Splitter configuration similar to the "split" package to make it
1227+-- In general we can use deintercalate for splitting. Then we can also use
1205−-- possible to express all splitting combinations. In general, we can have
1228+-- uniqBy to condense the separators. One way to generalize splitting is to
1206−-- infix/suffix/prefix/condensing of separators, dropping both leading/trailing
1229+-- output:
1207−-- separators. We can have a single split operation taking the splitter config
1210−-- | Split on an infixed separator element, dropping the separator. Splits the
1211−-- stream on separator elements determined by the supplied predicate, separator
1212−-- is considered as infixed between two segments, if one side of the separator
1213−-- is missing then it is parsed as an empty stream. The supplied 'Fold' is
1214−-- applied on the split segments. With '-' representing non-separator elements
1215−-- and '.' as separator, 'splitOn' splits as follows:
1217−-- @
1231+-- data Segment a b = Empty | Segment b | Separator a
1218−-- "--.--" => "--" "--"
1223−-- @splitOn (== x)@ is an inverse of @intercalate (S.yield x)@
1233+-- XXX splitOn and splitOnSuffix have a different behavior on an empty stream,
1234+-- is that desirable?
1236+-- | Split on an infixed separator element, dropping the separator. The
1237+-- supplied 'Fold' is applied on the split segments. Splits the stream on
1238+-- separator elements determined by the supplied predicate, separator is
1239+-- considered as infixed between two segments:
1225−-- Let's use the following definition for illustration:
1241+-- >>> splitOn' p xs = S.toList $ S.splitOn p FL.toList (S.fromList xs)
1242+-- >>> splitOn' (== '.') "a.b"
1227−-- > splitOn' p xs = S.toList $ S.splitOn p (FL.toList) (S.fromList xs)
1245+-- An empty stream is folded to the default value of the fold:
1229-- >>> splitOn' (== '.') ""
1247-- >>> splitOn' (== '.') ""
1250+-- If one or both sides of the separator are missing then the empty segment on
1251+-- that side is folded to the default output of the fold:
1232-- >>> splitOn' (== '.') "."
1253-- >>> splitOn' (== '.') "."
1233-- ["",""]
1254-- ["",""]
@@ -1238,69 +1259,85 @@ groups = groupsBy (==)
1238-- >>> splitOn' (== '.') "a."
1259-- >>> splitOn' (== '.') "a."
1239-- > ["a",""]
1260-- > ["a",""]
1241−-- >>> splitOn' (== '.') "a.b"
1244-- >>> splitOn' (== '.') "a..b"
1262-- >>> splitOn' (== '.') "a..b"
1245-- > ["a","","b"]
1263-- > ["a","","b"]
1265+-- splitOn is an inverse of intercalating single element:
1267+-- @Stream.intercalate (Stream.yield '.') Unfold.fromList . Stream.splitOn (== '.') Fold.toList === id@
1269+-- Assuming the input stream does not contain the separator:
1271+-- @Stream.splitOn (== '.') Fold.toList . Stream.intercalate (Stream.yield '.') Unfold.fromList === id@
1247-- @since 0.7.0
1273-- @since 0.7.0
1249−-- This can be considered as an n-fold version of 'breakOn' where we apply
1250−-- 'breakOn' successively on the input stream, dropping the first element
1251−-- of the second segment after each break.
1253{-# INLINE splitOn #-}
1275{-# INLINE splitOn #-}
1255 :: (IsStream t, Monad m)
1277 :: (IsStream t, Monad m)
1256 => (a -> Bool) -> Fold m a b -> t m a -> t m b
1278 => (a -> Bool) -> Fold m a b -> t m a -> t m b
1279+splitOn predicate f =
1280+ -- We can express the infix splitting in terms of optional suffix split
1281+ -- fold. After applying a suffix split fold repeatedly if the last segment
1282+ -- ends with a suffix then we need to return the default output of the fold
1283+ -- after that to make it an infix split.
1285+ -- Alternately, we can also express it using an optional prefix split fold.
1286+ -- If the first segment starts with a prefix then we need to emit the
1287+ -- default output of the fold before that to make it an infix split, and
1288+ -- then apply prefix split fold repeatedly.
1290+ -- Since a suffix split fold can be easily expressed using a
1291+ -- non-backtracking fold, we use that.
1257−splitOn predicate f = foldMany (FL.sliceSepBy predicate f)
1292+ foldMany (FL.sliceSepBy predicate f)
1259−-- | Like 'splitOn' but the separator is considered as suffixed to the segments
1294+-- | Split on a suffixed separator element, dropping the separator. The
1260−-- in the stream. A missing suffix at the end is allowed. A separator at the
1295+-- supplied 'Fold' is applied on the split segments.
1261−-- beginning is parsed as empty segment. With '-' representing elements and
1262−-- '.' as separator, 'splitOnSuffix' splits as follows:
1264−-- @
1297+-- > splitOnSuffix' p xs = S.toList $ S.splitOnSuffix p (FL.toList) (S.fromList xs)
1265−-- "--.--." => "--" "--"
1298+-- >>> splitOnSuffix' (== '.') "a.b."
1266−-- "--.--" => "--" "--"
1299+-- > ["a","b"]
1267−-- ".--." => "" "--"
1270−-- > splitOnSuffix' p xs = S.toList $ S.splitSuffixBy p (FL.toList) (S.fromList xs)
1301+-- >>> splitOnSuffix' (== '.') "a."
1304+-- An empty stream results in an empty output stream:
1272-- >>> splitOnSuffix' (== '.') ""
1306-- >>> splitOnSuffix' (== '.') ""
1309+-- An empty segment consisting of only a suffix is folded to the default output
1275-- >>> splitOnSuffix' (== '.') "."
1312-- >>> splitOnSuffix' (== '.') "."
1315+-- >>> splitOnSuffix' (== '.') "a..b.."
1316+-- > ["a","","b",""]
1318+-- A suffix is optional at the end of the stream:
1278-- >>> splitOnSuffix' (== '.') "a"
1320-- >>> splitOnSuffix' (== '.') "a"
1281-- >>> splitOnSuffix' (== '.') ".a"
1323-- >>> splitOnSuffix' (== '.') ".a"
1282-- > ["","a"]
1324-- > ["","a"]
1284−-- >>> splitOnSuffix' (== '.') "a."
1287-- >>> splitOnSuffix' (== '.') "a.b"
1326-- >>> splitOnSuffix' (== '.') "a.b"
1288-- > ["a","b"]
1327-- > ["a","b"]
1290−-- >>> splitOnSuffix' (== '.') "a.b."
1329+-- > lines = splitOnSuffix (== '\n')
1293−-- >>> splitOnSuffix' (== '.') "a..b.."
1331+-- 'splitOnSuffix' is an inverse of 'intercalateSuffix' with a single element:
1294−-- > ["a","","b",""]
1296−-- > lines = splitOnSuffix (== '\n')
1333+-- @Stream.intercalateSuffix (Stream.yield '.') Unfold.fromList . Stream.splitOnSuffix (== '.') Fold.toList === id@
1335+-- Assuming the input stream does not contain the separator:
1337+-- @Stream.splitOnSuffix (== '.') Fold.toList . Stream.intercalateSuffix (Stream.yield '.') Unfold.fromList === id@
1298-- @since 0.7.0
1339-- @since 0.7.0
1300−-- This can be considered as an n-fold version of 'breakPost' where we apply
1301−-- 'breakPost' successively on the input stream, dropping the first element
1302−-- of the second segment after each break.
1304{-# INLINE splitOnSuffix #-}
1341{-# INLINE splitOnSuffix #-}
1305splitOnSuffix
1342splitOnSuffix
1306 :: (IsStream t, Monad m)
1343 :: (IsStream t, Monad m)
@@ -1308,6 +1345,53 @@ splitOnSuffix
1308splitOnSuffix predicate f m =
1345splitOnSuffix predicate f m =
1309 D.fromStreamD $ D.foldMany1 (FL.sliceSepBy predicate f) (D.toStreamD m)
1346 D.fromStreamD $ D.foldMany1 (FL.sliceSepBy predicate f) (D.toStreamD m)
1348+-- | Split on a prefixed separator element, dropping the separator. The
1349+-- supplied 'Fold' is applied on the split segments.
1351+-- >>> splitOnPrefix' p xs = S.toList $ S.splitOnPrefix p (FL.toList) (S.fromList xs)
1352+-- >>> splitOnPrefix' (== '.') ".a.b"
1355+-- An empty stream results in an empty output stream:
1356+-- >>> splitOnPrefix' (== '.') ""
1359+-- An empty segment consisting of only a prefix is folded to the default output
1362+-- >>> splitOnPrefix' (== '.') "."
1365+-- >>> splitOnPrefix' (== '.') ".a.b."
1368+-- >>> splitOnPrefix' (== '.') ".a..b"
1371+-- A prefix is optional at the beginning of the stream:
1373+-- >>> splitOnPrefix' (== '.') "a"
1376+-- >>> splitOnPrefix' (== '.') "a.b"
1379+-- 'splitOnPrefix' is an inverse of 'intercalatePrefix' with a single element:
1381+-- @Stream.intercalatePrefix (Stream.yield '.') Unfold.fromList . Stream.splitOnPrefix (== '.') Fold.toList === id@
1383+-- Assuming the input stream does not contain the separator:
1385+-- @Stream.splitOnPrefix (== '.') Fold.toList . Stream.intercalatePrefix (Stream.yield '.') Unfold.fromList === id@
1389+{-# INLINE splitOnPrefix #-}
1390+splitOnPrefix :: -- (IsStream t, MonadCatch m) =>
1391+ (a -> Bool) -> Fold m a b -> t m a -> t m b
1392+splitOnPrefix _predicate _f = undefined
1393+ -- parseMany (Parser.sliceBeginBy predicate f)
1311-- | Like 'splitOn' after stripping leading, trailing, and repeated separators.
1395-- | Like 'splitOn' after stripping leading, trailing, and repeated separators.
1312-- Therefore, @".a..b."@ with '.' as the separator would be parsed as
1396-- Therefore, @".a..b."@ with '.' as the separator would be parsed as
1313-- @["a","b"]@. In other words, its like parsing words from whitespace
1397-- @["a","b"]@. In other words, its like parsing words from whitespace
@@ -1368,9 +1452,6 @@ wordsBy predicate f m =
1369-- @since 0.7.0
1453-- @since 0.7.0
1371−-- This can be considered as an n-fold version of 'breakPost' where we apply
1372−-- 'breakPost' successively on the input stream.
1374{-# INLINE splitWithSuffix #-}
1455{-# INLINE splitWithSuffix #-}
1375splitWithSuffix
1456splitWithSuffix
1376 :: (IsStream t, Monad m)
1457 :: (IsStream t, Monad m)
@@ -1419,6 +1500,10 @@ splitOnAny subseq f m = undefined -- D.fromStreamD $ D.splitOnAny f subseq (D.to
1421-- XXX use a non-monadic intersperse to remove the MonadAsync constraint.
1502-- XXX use a non-monadic intersperse to remove the MonadAsync constraint.
1503+-- XXX Use two folds, one ring buffer fold for separator sequence and the other
1504+-- split consumer fold. The input is fed to the ring fold first and the
1505+-- rejected input is fed to the split fold. If the separator matches, the ring
1506+-- fold would consume all.
1423-- | Like 'splitOnSeq' but splits the separator as well, as an infix token.
1508-- | Like 'splitOnSeq' but splits the separator as well, as an infix token.