@@ -89,11 +89,11 @@ module Streamly.Fold
89 -- applications, they buffer all the input in GC memory which can be
89 -- applications, they buffer all the input in GC memory which can be
90 -- detrimental to performance if the input is large.
90 -- detrimental to performance if the input is large.
92− , toStream -- experimental
92+ -- , toStream -- experimental
93− , toStreamRev -- experimental
93+ -- , toStreamRev -- experimental
96− , toListRev -- experimental
96+ -- , toListRev -- experimental
98 -- ** Partial Folds
98 -- ** Partial Folds
99 -- , drainN
99 -- , drainN
@@ -158,9 +158,9 @@ module Streamly.Fold
158 -- , lprescanl'
158 -- , lprescanl'
159 -- , lprescanlM'
159 -- , lprescanlM'
161− -- ** Filtering
161+ -- -- ** Filtering
162− , lfilter
162+ -- , lfilter
163− , lfilterM
163+ -- , lfilterM
164 -- , ldeleteBy
164 -- , ldeleteBy
165 -- , luniq
165 -- , luniq
@@ -198,17 +198,17 @@ module Streamly.Fold
198 -- ** Breaking
198 -- ** Breaking
200 -- By chunks
200 -- By chunks
201− , splitAt
201+ -- , splitAt -- spanN
202− -- , splitIn -- time
202+ -- , splitIn -- sessionN
204 -- By elements
204 -- By elements
205− , span
205+ -- , span -- spanWhile
206− , break -- breakPre
206+ -- , break -- breakBefore
207− -- , breakPost
207+ -- , breakAfter
208 -- , breakOn
208 -- , breakOn
209 -- , breakAround
209 -- , breakAround
210 -- , spanBy
210 -- , spanBy
211− -- , spanRollingBy
211+ -- , spanByRolling
213 -- By sequences
213 -- By sequences
214 -- breakOnSeq
214 -- breakOnSeq
@@ -225,40 +225,45 @@ module Streamly.Fold
226 -- , groupScan
226 -- , groupScan
228− -- *** By Chunks
228+ -- *** Chunks
229 , chunksOf
229 , chunksOf
230 , sessionsOf
230 , sessionsOf
232 -- , lchunksOf
232 -- , lchunksOf
233 -- , lsessionsOf
233 -- , lsessionsOf
235− -- *** By Elements
235+ -- *** Using Element Separators
236− , splitBy
236+ -- On == Dropping the separator
243 , splitOn
237 , splitOn
244− , splitSuffixOn
238+ , splitOnSuffix
245− -- , splitPrefixOn
239+ -- , splitOnPrefix
241+ -- By == Keeping the separator
245+ , wordsBy -- stripAndCompactBy
247+ -- -- *** Using Sequence Separators
249+ -- , splitOnSuffixSeq
250+ -- , splitOnPrefixSeq
248 -- Keeping the delimiters
252 -- Keeping the delimiters
249− , splitOn'
253+ -- , splitBySeq
250− , splitSuffixOn'
254+ -- , splitBySeqSuffix
251− -- , splitPrefixOn'
255+ -- , splitBySeqPrefix
253− -- Splitting by multiple sequences
258+ -- Splitting using multiple sequence separators
254− -- , splitOnAny
259+ -- , splitOnAnySeq
255− -- , splitSuffixOnAny
260+ -- , splitOnAnySuffixSeq
256− -- , splitPrefixOnAny
261+ -- , splitOnAnyPrefixSeq
258 -- ** Grouping
263 -- ** Grouping
260 , groupsBy
265 , groupsBy
261− , groupsRollingBy
266+ , groupsByRolling
263 -- * Distributing
268 -- * Distributing
@@ -296,19 +301,26 @@ module Streamly.Fold
297 -- * Partitioning
302 -- * Partitioning
299− -- Direct items in the input stream to different folds using a function to
304+ -- Direct items in the input stream to different folds using a binary
300− -- select the fold. This is useful to demultiplex the input stream.
305+ -- fold selector.
301 -- , partitionByM
307 -- , partitionByM
302 -- , partitionBy
308 -- , partitionBy
303 , partition
309 , partition
305 -- * Demultiplexing
311 -- * Demultiplexing
312+ -- | Direct values in the input stream to different folds using an n-ary
307 -- , demuxWith
316 -- , demuxWith
309 -- , demuxWith_
318 -- , demuxWith_
311 -- * Classifying
320 -- * Classifying
321+ -- | In an input stream of key value pairs fold values for different keys
322+ -- in individual output buckets using the given fold.
312 , classify
324 , classify
313 -- , classifyWith
325 -- , classifyWith
@@ -318,7 +330,7 @@ module Streamly.Fold
318 -- , unzipWith
330 -- , unzipWith
319 -- , unzipWithM
331 -- , unzipWithM
321− -- * Nested Folds
333+ -- -- * Nested Folds
322 -- , concatMap
334 -- , concatMap
323 -- , chunksOf
335 -- , chunksOf
324 -- , duplicate -- experimental
336 -- , duplicate -- experimental
@@ -403,6 +415,7 @@ import qualified Streamly.Prelude as S
403import qualified Streamly.Streams.StreamD as D
415import qualified Streamly.Streams.StreamD as D
404import qualified Streamly.Streams.StreamK as K
416import qualified Streamly.Streams.StreamK as K
405import qualified Streamly.Streams.Prelude as P
417import qualified Streamly.Streams.Prelude as P
418+import qualified Streamly.Streams.Parallel as Par
407-- $termination
420-- $termination
@@ -1210,8 +1223,11 @@ sessionsOf
1210 :: (IsStream t, MonadAsync m)
1223 :: (IsStream t, MonadAsync m)
1211 => Double -> Fold m a b -> t m a -> t m b
1224 => Double -> Fold m a b -> t m a -> t m b
1212sessionsOf n f xs =
1225sessionsOf n f xs =
1213− splitSuffixBy' isNothing (lcatMaybes f)
1226+ splitBySuffix isNothing (lcatMaybes f)
1214− (S.intersperseByTime n (return Nothing) (S.map Just xs))
1227+ (intersperseByTime n (return Nothing) (S.map Just xs))
1229+ intersperseByTime n f xs = xs `Par.parallelEndByFirst` S.repeatM timed
1230+ where timed = liftIO (threadDelay (round $ n * 1000000)) >> f
1216------------------------------------------------------------------------------
1232------------------------------------------------------------------------------
1217-- Element Aware APIs
1233-- Element Aware APIs
@@ -1355,7 +1371,8 @@ _spanRollingBy cmp (Fold stepL initialL extractL) (Fold stepR initialR extractR)
1355-- first group, if @a \`cmp` b@ is 'True' then @b@ is also assigned to the same
1371-- first group, if @a \`cmp` b@ is 'True' then @b@ is also assigned to the same
1356-- group. If @a \`cmp` c@ is 'True' then @c@ is also assigned to the same
1372-- group. If @a \`cmp` c@ is 'True' then @c@ is also assigned to the same
1357-- group and so on. When the comparison fails a new group is started. Each
1373-- group and so on. When the comparison fails a new group is started. Each
1358−-- group is folded using the fold @f@.
1374+-- group is folded using the fold @f@ and the result of the fold is emitted in
1375+-- the output stream.
1360-- >>> S.toList $ FL.groupsBy (>) FL.toList $ S.fromList [1,3,7,0,2,5]
1377-- >>> S.toList $ FL.groupsBy (>) FL.toList $ S.fromList [1,3,7,0,2,5]
1361-- > [[1,3,7],[0,2,5]]
1378-- > [[1,3,7],[0,2,5]]
@@ -1371,31 +1388,31 @@ groupsBy
1371groupsBy cmp f m = D.fromStreamD $ D.groupsBy cmp f (D.toStreamD m)
1388groupsBy cmp f m = D.fromStreamD $ D.groupsBy cmp f (D.toStreamD m)
1373-- | Unlike @groupsBy@ this function performs a rolling comparison of two
1390-- | Unlike @groupsBy@ this function performs a rolling comparison of two
1374−-- successive elements in the input stream. @groupsRollingBy cmp f $ S.fromList
1391+-- successive elements in the input stream. @groupsByRolling cmp f $ S.fromList
1375-- [a,b,c,...]@ assigns the element @a@ to the first group, if @a \`cmp` b@ is
1392-- [a,b,c,...]@ assigns the element @a@ to the first group, if @a \`cmp` b@ is
1376-- 'True' then @b@ is also assigned to the same group. If @b \`cmp` c@ is
1393-- 'True' then @b@ is also assigned to the same group. If @b \`cmp` c@ is
1377-- 'True' then @c@ is also assigned to the same group and so on. When the
1394-- 'True' then @c@ is also assigned to the same group and so on. When the
1378-- comparison fails a new group is started. Each group is folded using the fold
1395-- comparison fails a new group is started. Each group is folded using the fold
1381−-- >>> S.toList $ FL.groupsRollingBy (\a b -> a + 1 == b) FL.toList $ S.fromList [1,2,3,7,8,9]
1398+-- >>> S.toList $ FL.groupsByRolling (\a b -> a + 1 == b) FL.toList $ S.fromList [1,2,3,7,8,9]
1382-- > [[1,2,3],[7,8,9]]
1399-- > [[1,2,3],[7,8,9]]
1384-- @since 0.7.0
1401-- @since 0.7.0
1385−{-# INLINE groupsRollingBy #-}
1402+{-# INLINE groupsByRolling #-}
1386−groupsRollingBy
1403+groupsByRolling
1387 :: (IsStream t, Monad m)
1404 :: (IsStream t, Monad m)
1388 => (a -> a -> Bool)
1405 => (a -> a -> Bool)
1389 -> Fold m a b
1406 -> Fold m a b
1390 -> t m a
1407 -> t m a
1391 -> t m b
1408 -> t m b
1392−groupsRollingBy cmp f m = D.fromStreamD $ D.groupsRollingBy cmp f (D.toStreamD m)
1409+groupsByRolling cmp f m = D.fromStreamD $ D.groupsRollingBy cmp f (D.toStreamD m)
1395-- > groups = groupsBy (==)
1412-- > groups = groupsBy (==)
1396−-- > groups = groupsRollingBy (==)
1413+-- > groups = groupsByRolling (==)
1398−-- Groups a contiguous span of equal elements together in one group.
1415+-- Groups contiguous spans of equal elements together in individual groups.
1400-- >>> S.toList $ FL.groups FL.toList $ S.fromList [1,1,2,2]
1417-- >>> S.toList $ FL.groups FL.toList $ S.fromList [1,1,2,2]
1401-- > [[1,1],[2,2]]
1418-- > [[1,1],[2,2]]
@@ -1435,92 +1452,104 @@ breakOn pat f m = undefined
1435-- as argument.
1452-- as argument.
1437-- | Split a stream on separator elements determined by a predicate, dropping
1454-- | Split a stream on separator elements determined by a predicate, dropping
1438−-- the separator. Separators are not considered part of stream segments on
1455+-- the separator. Separator is considered as infixed between two segments, if
1439−-- either side of it instead they are treated as infixed between two stream
1456+-- one side of the separator is missing then it is parsed as an empty stream.
1440−-- segments. For example, with @.@ as separator, @"a.b.c"@ would be parsed as
1457+-- With '-' representing elements and '.' as separator, 'splitOn' splits as
1441−-- @["a","b","c"]@. When @.@ is in leading or trailing position it is still
1458+-- follows:
1442−-- considered as infixed, treating the first or the last segment as empty. For
1459+--
1443−-- example, @".a."@ would be parsed as @["","a",""]@. This operation is
1460+-- @
1461+-- "--.--" => "--" "--"
1444−-- opposite of 'intercalate'.
1466+-- @splitOn (== x)@ is an inverse of @intercalate (S.yield x)@
1446-- Let's use the following definition for illustration:
1468-- Let's use the following definition for illustration:
1448−-- > splitBy_ p xs = S.toList $ FL.splitBy p (FL.toList) (S.fromList xs)
1470+-- > splitOn' p xs = S.toList $ FL.splitOn p (FL.toList) (S.fromList xs)
1450−-- >>> splitBy_ (== '.') ""
1472+-- >>> splitOn' (== '.') ""
1453−-- >>> splitBy_ (== '.') "."
1475+-- >>> splitOn' (== '.') "."
1454-- ["",""]
1476-- ["",""]
1456−-- >>> splitBy_ (== '.') ".a"
1478+-- >>> splitOn' (== '.') ".a"
1457-- > ["","a"]
1479-- > ["","a"]
1459−-- >>> splitBy_ (== '.') "a."
1481+-- >>> splitOn' (== '.') "a."
1460-- > ["a",""]
1482-- > ["a",""]
1462−-- >>> splitBy_ (== '.') "a.b"
1484+-- >>> splitOn' (== '.') "a.b"
1463-- > ["a","b"]
1485-- > ["a","b"]
1465−-- >>> splitBy_ (== '.') "a..b"
1487+-- >>> splitOn' (== '.') "a..b"
1466-- > ["a","","b"]
1488-- > ["a","","b"]
1468−-- This can be considered as an n-fold version of 'break' where we apply
1492+-- This can be considered as an n-fold version of 'breakOn' where we apply
1469−-- 'break' successively on the input stream, dropping the first element
1493+-- 'breakOn' successively on the input stream, dropping the first element
1470-- of the second segment after each break.
1494-- of the second segment after each break.
1473−{-# INLINE splitBy #-}
1496+{-# INLINE splitOn #-}
1475 :: (IsStream t, Monad m)
1498 :: (IsStream t, Monad m)
1476 => (a -> Bool) -> Fold m a b -> t m a -> t m b
1499 => (a -> Bool) -> Fold m a b -> t m a -> t m b
1477−splitBy predicate f m =
1500+splitOn predicate f m =
1478 D.fromStreamD $ D.splitBy predicate f (D.toStreamD m)
1501 D.fromStreamD $ D.splitBy predicate f (D.toStreamD m)
1480−-- | Like 'splitBy' but the separator is treated as part of the previous
1503+-- | Like 'splitOn' but the separator is considered as suffixed to the segments
1481−-- stream segment (suffix). Therefore, when the separator is in trailing
1504+-- in the stream. A missing suffix at the end is allowed. A separator at the
1482−-- position, no empty segment is considered to follow it. For example, @"a.b."@
1505+-- beginning is parsed as empty segment. With '-' representing elements and
1483−-- would be parsed as @["a","b"]@ instead of @["a","b",""]@ as in the case of
1506+-- '.' as separator, 'splitOnSuffix' splits as follows:
1484−-- 'splitBy'.
1507+--
1509+-- "--.--." => "--" "--"
1510+-- "--.--" => "--" "--"
1511+-- ".--." => "" "--"
1486−-- > splitSuffixBy_ p xs = S.toList $ FL.splitSuffixBy p (FL.toList) (S.fromList xs)
1514+-- > splitOnSuffix' p xs = S.toList $ FL.splitSuffixBy p (FL.toList) (S.fromList xs)
1488−-- >>> splitSuffixBy_ (== '.') ""
1516+-- >>> splitOnSuffix' (== '.') ""
1491−-- >>> splitSuffixBy_ (== '.') "."
1519+-- >>> splitOnSuffix' (== '.') "."
1494−-- >>> splitSuffixBy_ (== '.') "a"
1522+-- >>> splitOnSuffix' (== '.') "a"
1497−-- >>> splitSuffixBy_ (== '.') ".a"
1525+-- >>> splitOnSuffix' (== '.') ".a"
1498-- > ["","a"]
1526-- > ["","a"]
1500−-- >>> splitSuffixBy_ (== '.') "a."
1528+-- >>> splitOnSuffix' (== '.') "a."
1501-- > ["a"]
1529-- > ["a"]
1503−-- >>> splitSuffixBy_ (== '.') "a.b"
1531+-- >>> splitOnSuffix' (== '.') "a.b"
1504-- > ["a","b"]
1532-- > ["a","b"]
1506−-- >>> splitSuffixBy_ (== '.') "a.b."
1534+-- >>> splitOnSuffix' (== '.') "a.b."
1507-- > ["a","b"]
1535-- > ["a","b"]
1509−-- >>> splitSuffixBy_ (== '.') "a..b.."
1537+-- >>> splitOnSuffix' (== '.') "a..b.."
1510-- > ["a","","b",""]
1538-- > ["a","","b",""]
1512−-- > lines = splitSuffixBy (== '\n')
1540+-- > lines = splitOnSuffix (== '\n')
1514-- This can be considered as an n-fold version of 'breakPost' where we apply
1544-- This can be considered as an n-fold version of 'breakPost' where we apply
1515-- 'breakPost' successively on the input stream, dropping the first element
1545-- 'breakPost' successively on the input stream, dropping the first element
1516-- of the second segment after each break.
1546-- of the second segment after each break.
1518−-- @since 0.7.0
1548+{-# INLINE splitOnSuffix #-}
1519−{-# INLINE splitSuffixBy #-}
1549+splitOnSuffix
1521 :: (IsStream t, Monad m)
1550 :: (IsStream t, Monad m)
1522 => (a -> Bool) -> Fold m a b -> t m a -> t m b
1551 => (a -> Bool) -> Fold m a b -> t m a -> t m b
1523−splitSuffixBy predicate f m =
1552+splitOnSuffix predicate f m =
1524 D.fromStreamD $ D.splitSuffixBy predicate f (D.toStreamD m)
1553 D.fromStreamD $ D.splitSuffixBy predicate f (D.toStreamD m)
1526-- | Like 'splitBy' but ignores repeated separators or separators in leading
1555-- | Like 'splitBy' but ignores repeated separators or separators in leading
@@ -1549,49 +1578,45 @@ wordsBy
1549wordsBy predicate f m =
1578wordsBy predicate f m =
1550 D.fromStreamD $ D.wordsBy predicate f (D.toStreamD m)
1579 D.fromStreamD $ D.wordsBy predicate f (D.toStreamD m)
1552−-- XXX we should express this using the Splitter config.
1581+-- | Like 'splitOnSuffix' but keeps the suffix attached to the resulting
1554−-- We can get splitSuffixBy' by appending the suffix to the output segments
1584+-- > splitBySuffix' p xs = S.toList $ FL.splitBySuffix p (FL.toList) (S.fromList xs)
1555−-- produced by splitSuffixBy. However, it may add an additional suffix if the last
1556−-- fragment did not have a suffix in the first place.
1558−-- | Like 'splitSuffixBy' but keeps the suffix in the splits.
1560−-- > splitSuffixBy'_ p xs = S.toList $ FL.splitSuffixBy' p (FL.toList) (S.fromList xs)
1586+-- >>> splitBySuffix' (== '.') ""
1562−-- >>> splitSuffixBy'_ (== '.') ""
1565−-- >>> splitSuffixBy'_ (== '.') "."
1589+-- >>> splitBySuffix' (== '.') "."
1568−-- >>> splitSuffixBy'_ (== '.') "a"
1592+-- >>> splitBySuffix' (== '.') "a"
1571−-- >>> splitSuffixBy'_ (== '.') ".a"
1595+-- >>> splitBySuffix' (== '.') ".a"
1572-- > [".","a"]
1596-- > [".","a"]
1574−-- >>> splitSuffixBy'_ (== '.') "a."
1598+-- >>> splitBySuffix' (== '.') "a."
1575-- > ["a."]
1599-- > ["a."]
1577−-- >>> splitSuffixBy'_ (== '.') "a.b"
1601+-- >>> splitBySuffix' (== '.') "a.b"
1578-- > ["a.","b"]
1602-- > ["a.","b"]
1580−-- >>> splitSuffixBy'_ (== '.') "a.b."
1604+-- >>> splitBySuffix' (== '.') "a.b."
1581-- > ["a.","b."]
1605-- > ["a.","b."]
1583−-- >>> splitSuffixBy'_ (== '.') "a..b.."
1607+-- >>> splitBySuffix' (== '.') "a..b.."
1584-- > ["a.",".","b.","."]
1608-- > ["a.",".","b.","."]
1586-- This can be considered as an n-fold version of 'breakPost' where we apply
1612-- This can be considered as an n-fold version of 'breakPost' where we apply
1587-- 'breakPost' successively on the input stream.
1613-- 'breakPost' successively on the input stream.
1589−-- @since 0.7.0
1615+{-# INLINE splitBySuffix #-}
1590−{-# INLINE splitSuffixBy' #-}
1616+splitBySuffix
1592 :: (IsStream t, Monad m)
1617 :: (IsStream t, Monad m)
1593 => (a -> Bool) -> Fold m a b -> t m a -> t m b
1618 => (a -> Bool) -> Fold m a b -> t m a -> t m b
1594−splitSuffixBy' predicate f m =
1619+splitBySuffix predicate f m =
1595 D.fromStreamD $ D.splitSuffixBy' predicate f (D.toStreamD m)
1620 D.fromStreamD $ D.splitSuffixBy' predicate f (D.toStreamD m)
1597------------------------------------------------------------------------------
1622------------------------------------------------------------------------------
@@ -1624,43 +1649,43 @@ splitSuffixBy' predicate f m =
1624-- >>> splitList [1,2,3,3,4] [1,2,3,3,4]
1649-- >>> splitList [1,2,3,3,4] [1,2,3,3,4]
1625-- > [[],[]]
1650-- > [[],[]]
1627−-- | Split the stream on both sides of a separator sequence, dropping the
1652+-- | Like 'splitOn' but the separator is a sequence of elements instead of a
1628−-- separator.
1653+-- single element.
1630-- For illustration, let's define a function that operates on pure lists:
1655-- For illustration, let's define a function that operates on pure lists:
1633−-- splitOn_ pat xs = S.toList $ FL.splitOn (A.fromList pat) (FL.toList) (S.fromList xs)
1658+-- splitOnSeq' pat xs = S.toList $ FL.splitOnSeq (A.fromList pat) (FL.toList) (S.fromList xs)
1636−-- >>> splitOn_ "" "hello"
1661+-- >>> splitOnSeq' "" "hello"
1637-- > ["h","e","l","l","o"]
1662-- > ["h","e","l","l","o"]
1639−-- >>> splitOn_ "hello" ""
1664+-- >>> splitOnSeq' "hello" ""
1640-- > [""]
1665-- > [""]
1642−-- >>> splitOn_ "hello" "hello"
1667+-- >>> splitOnSeq' "hello" "hello"
1643-- > ["",""]
1668-- > ["",""]
1645−-- >>> splitOn_ "x" "hello"
1670+-- >>> splitOnSeq' "x" "hello"
1646-- > ["hello"]
1671-- > ["hello"]
1648−-- >>> splitOn_ "h" "hello"
1673+-- >>> splitOnSeq' "h" "hello"
1649-- > ["","ello"]
1674-- > ["","ello"]
1651−-- >>> splitOn_ "o" "hello"
1676+-- >>> splitOnSeq' "o" "hello"
1652-- > ["hell",""]
1677-- > ["hell",""]
1654−-- >>> splitOn_ "e" "hello"
1679+-- >>> splitOnSeq' "e" "hello"
1655-- > ["h","llo"]
1680-- > ["h","llo"]
1657−-- >>> splitOn_ "l" "hello"
1682+-- >>> splitOnSeq' "l" "hello"
1658-- > ["he","","o"]
1683-- > ["he","","o"]
1660−-- >>> splitOn_ "ll" "hello"
1685+-- >>> splitOnSeq' "ll" "hello"
1661-- > ["he","o"]
1686-- > ["he","o"]
1663−-- 'splitOn' is an inverse of 'intercalate'. The following law always holds:
1688+-- 'splitOnSeq' is an inverse of 'intercalate'. The following law always holds:
1665-- > intercalate . splitOn == id
1690-- > intercalate . splitOn == id
@@ -1669,16 +1694,18 @@ splitSuffixBy' predicate f m =
1670-- > splitOn . intercalate == id
1695-- > splitOn . intercalate == id
1672−-- The following law always holds:
1674−-- > concat . splitOn . intercalate == concat
1676-- @since 0.7.0
1697-- @since 0.7.0
1699+-- XXX We can use a polymorphic vector implemented by Array# to represent the
1700+-- sequence, that way we can avoid the Storable constraint. If we still need
1701+-- Storable Array for performance, we can use a separate splitOnArray API for
1702+-- that. We can also have an API where the sequence itself is a lazy stream, so
1703+-- that we can search files in files for example.
1677−{-# INLINE splitOn #-}
1704+{-# INLINE splitOnSeq #-}
1678−splitOn
1705+splitOnSeq
1679 :: (IsStream t, MonadIO m, Storable a, Enum a, Eq a)
1706 :: (IsStream t, MonadIO m, Storable a, Enum a, Eq a)
1680 => Array a -> Fold m a b -> t m a -> t m b
1707 => Array a -> Fold m a b -> t m a -> t m b
1681−splitOn patt f m = D.fromStreamD $ D.splitOn patt f (D.toStreamD m)
1708+splitOnSeq patt f m = D.fromStreamD $ D.splitOn patt f (D.toStreamD m)
1684-- This can be implemented easily using Rabin Karp
1711-- This can be implemented easily using Rabin Karp
@@ -1722,11 +1749,11 @@ splitOnAny subseq f m = undefined -- D.fromStreamD $ D.splitOnAny f subseq (D.to
1722-- > lines = splitSuffixOn "\n"
1749-- > lines = splitSuffixOn "\n"
1724-- @since 0.7.0
1751-- @since 0.7.0
1725−{-# INLINE splitSuffixOn #-}
1752+{-# INLINE splitOnSuffixSeq #-}
1726−splitSuffixOn
1753+splitOnSuffixSeq
1727 :: (IsStream t, MonadIO m, Storable a, Enum a, Eq a)
1754 :: (IsStream t, MonadIO m, Storable a, Enum a, Eq a)
1728 => Array a -> Fold m a b -> t m a -> t m b
1755 => Array a -> Fold m a b -> t m a -> t m b
1729−splitSuffixOn patt f m =
1756+splitOnSuffixSeq patt f m =
1730 D.fromStreamD $ D.splitSuffixOn False patt f (D.toStreamD m)
1757 D.fromStreamD $ D.splitSuffixOn False patt f (D.toStreamD m)
@@ -1741,7 +1768,7 @@ wordsOn subseq f m = undefined -- D.fromStreamD $ D.wordsOn f subseq (D.toStream
1742-- XXX use a non-monadic intersperse to remove the MonadAsync constraint.
1769-- XXX use a non-monadic intersperse to remove the MonadAsync constraint.
1744−-- | Like 'splitOn' but splits the separator as well, as an infix token.
1771+-- | Like 'splitOnSeq' but splits the separator as well, as an infix token.
1746-- > splitOn'_ pat xs = S.toList $ FL.splitOn' (A.fromList pat) (FL.toList) (S.fromList xs)
1773-- > splitOn'_ pat xs = S.toList $ FL.splitOn' (A.fromList pat) (FL.toList) (S.fromList xs)
@@ -1773,11 +1800,11 @@ wordsOn subseq f m = undefined -- D.fromStreamD $ D.wordsOn f subseq (D.toStream
1773-- > ["he","ll","o"]
1800-- > ["he","ll","o"]
1775-- @since 0.7.0
1802-- @since 0.7.0
1776−{-# INLINE splitOn' #-}
1803+{-# INLINE splitBySeq #-}
1777−splitOn'
1804+splitBySeq
1778 :: (IsStream t, MonadAsync m, Storable a, Enum a, Eq a)
1805 :: (IsStream t, MonadAsync m, Storable a, Enum a, Eq a)
1779 => Array a -> Fold m a b -> t m a -> t m b
1806 => Array a -> Fold m a b -> t m a -> t m b
1780−splitOn' patt f m = S.intersperseM (foldl' f (A.read patt)) $ splitOn patt f m
1807+splitBySeq patt f m = S.intersperseM (foldl' f (A.read patt)) $ splitOnSeq patt f m
1782-- | Like 'splitSuffixOn' but keeps the suffix intact in the splits.
1809-- | Like 'splitSuffixOn' but keeps the suffix intact in the splits.
@@ -1808,11 +1835,11 @@ splitOn' patt f m = S.intersperseM (foldl' f (A.read patt)) $ splitOn patt f m
1808-- > ["a.",".","b.","."]
1835-- > ["a.",".","b.","."]
1810-- @since 0.7.0
1837-- @since 0.7.0
1811−{-# INLINE splitSuffixOn' #-}
1838+{-# INLINE splitBySuffixSeq #-}
1812−splitSuffixOn'
1839+splitBySuffixSeq
1813 :: (IsStream t, MonadIO m, Storable a, Enum a, Eq a)
1840 :: (IsStream t, MonadIO m, Storable a, Enum a, Eq a)
1814 => Array a -> Fold m a b -> t m a -> t m b
1841 => Array a -> Fold m a b -> t m a -> t m b
1815−splitSuffixOn' patt f m =
1842+splitBySuffixSeq patt f m =
1816 D.fromStreamD $ D.splitSuffixOn True patt f (D.toStreamD m)
1843 D.fromStreamD $ D.splitSuffixOn True patt f (D.toStreamD m)
@@ -1882,7 +1909,8 @@ foldCons (Fold stepL beginL doneL) (Fold stepR beginR doneR) =
1882 done (Tuple' xL xR) = (:) <$> (doneL xL) <*> (doneR xR)
1909 done (Tuple' xL xR) = (:) <$> (doneL xL) <*> (doneR xR)
1884-- XXX use "List" instead of "[]"?, use Array for output to scale it to a large
1911-- XXX use "List" instead of "[]"?, use Array for output to scale it to a large
1885−-- number of consumers?
1912+-- number of consumers? For polymorphic case a vector could be helpful. For
1913+-- Storables we can use arrays. Will need separate APIs for those.
1887-- | Distribute one copy of the stream to each fold and collect the results in
1915-- | Distribute one copy of the stream to each fold and collect the results in
1888-- a container.
1916-- a container.
@@ -2010,11 +2038,15 @@ partition = partitionBy id
2010-- partitionN fs = Fold step begin done
2038-- partitionN fs = Fold step begin done
2013−-- Demultiplex an input element into a number of typed variants. We want to
2041+-- TODO Demultiplex an input element into a number of typed variants. We want
2014−-- statically restrict the target values within a set of predefined types, an
2042+-- to statically restrict the target values within a set of predefined types,
2015−-- enumeration of a GADT. We also want to make sure that the Map contains only
2043+-- an enumeration of a GADT. We also want to make sure that the Map contains
2016−-- those types and the full set of those types. Instead of Map it should
2044+-- only those types and the full set of those types.
2017−-- probably be a lookup-table using an array and not in GC memory.
2046+-- TODO Instead of the input Map it should probably be a lookup-table using an
2047+-- array and not in GC memory. The same applies to the output Map as well.
2048+-- However, that would only be helpful if we have a very large data structure,
2049+-- need to measure and see how it scales.
2019-- This is the consumer side dual of the producer side 'mux' operation (XXX to
2051-- This is the consumer side dual of the producer side 'mux' operation (XXX to
2020-- be implemented).
2052-- be implemented).
@@ -2131,9 +2163,9 @@ demuxWith_ f kv = Fold step initial extract
2131demux_ :: (Monad m, Ord k) => Map k (Fold m a ()) -> Fold m (k, a) ()
2163demux_ :: (Monad m, Ord k) => Map k (Fold m a ()) -> Fold m (k, a) ()
2132demux_ fs = demuxWith_ fst (Map.map (lmap snd) fs)
2164demux_ fs = demuxWith_ fst (Map.map (lmap snd) fs)
2134−-- XXX instead of a Map we could yield the results as a pure stream as they
2166+-- TODO If the data is large we may need a map/hashmap in pinned memory instead
2135−-- complete. We could then concatMap the fold results to implement the
2167+-- of a regular Map. That may require a serializable constraint though. We can
2136−-- windowing combinators.
2168+-- have another API for that.
2138-- | Split the input stream based on a key field and fold each split using the
2170-- | Split the input stream based on a key field and fold each split using the
2139-- given fold. Useful for map/reduce, bucketizing the input in different bins
2171-- given fold. Useful for map/reduce, bucketizing the input in different bins
@@ -2175,11 +2207,12 @@ classifyWith f (Fold step initial extract) = Fold step' initial' extract'
2175-- fromList [(\"ONE",[1.1,1.0]),(\"TWO",[2.2,2.0])]
2207-- fromList [(\"ONE",[1.1,1.0]),(\"TWO",[2.2,2.0])]
2178-- Same as:
2212-- Same as:
2180-- > classify fld = classifyWith fst (lmap snd fld)
2214-- > classify fld = classifyWith fst (lmap snd fld)
2183{-# INLINE classify #-}
2216{-# INLINE classify #-}
2184classify :: (Monad m, Ord k) => Fold m a b -> Fold m (k, a) (Map k b)
2217classify :: (Monad m, Ord k) => Fold m a b -> Fold m (k, a) (Map k b)
2185classify fld = classifyWith fst (lmap snd fld)
2218classify fld = classifyWith fst (lmap snd fld)
@@ -2219,9 +2252,9 @@ unzipWith f = unzipWithM (return . f)
2222−-- |-------Fold a x--------|
2255+-- |-------Fold m a x--------|
2223−-- -----Stream m x----(a,b)--| |----m (x,y)
2256+-- ---------stream of (a,b)--| |----m (x,y)
2224−-- |-------Fold b y--------|
2257+-- |-------Fold m b y--------|