on master help sign in
update doc, hide some combinators, rename split combinators
commitfdec798a637e412cca9ad21184a063fa3a6e8c39 authorHarendra Kumar <harendra.kumar@gmail.com> dateFri 2 Aug 2019, 02:56 (7 years ago) parentf66ed7b
3 files changed+206−162
src/Streamly/Fold.hs+180−147 src/Streamly/String.hs+2−2 test/Prop.hs+24−13
src/Streamly/Fold.hs+180−147
@@ -89,11 +89,11 @@ module Streamly.Fold
8989 -- applications, they buffer all the input in GC memory which can be
9090 -- detrimental to performance if the input is large.
9191
92− , toStream -- experimental
93− , toStreamRev -- experimental
92+ -- , toStream -- experimental
93+ -- , toStreamRev -- experimental
9494
9595 , toList
96− , toListRev -- experimental
96+ -- , toListRev -- experimental
9797
9898 -- ** Partial Folds
9999 -- , drainN
@@ -158,9 +158,9 @@ module Streamly.Fold
158158 -- , lprescanl'
159159 -- , lprescanlM'
160160
161− -- ** Filtering
162− , lfilter
163− , lfilterM
161+ -- -- ** Filtering
162+ -- , lfilter
163+ -- , lfilterM
164164 -- , ldeleteBy
165165 -- , luniq
166166
@@ -198,17 +198,17 @@ module Streamly.Fold
198198 -- ** Breaking
199199
200200 -- By chunks
201− , splitAt
202− -- , splitIn -- time
201+ -- , splitAt -- spanN
202+ -- , splitIn -- sessionN
203203
204204 -- By elements
205− , span
206− , break -- breakPre
207− -- , breakPost
205+ -- , span -- spanWhile
206+ -- , break -- breakBefore
207+ -- , breakAfter
208208 -- , breakOn
209209 -- , breakAround
210210 -- , spanBy
211− -- , spanRollingBy
211+ -- , spanByRolling
212212
213213 -- By sequences
214214 -- breakOnSeq
@@ -225,40 +225,45 @@ module Streamly.Fold
225225
226226 -- , groupScan
227227
228− -- *** By Chunks
228+ -- *** Chunks
229229 , chunksOf
230230 , sessionsOf
231231
232232 -- , lchunksOf
233233 -- , lsessionsOf
234234
235− -- *** By Elements
236− , splitBy
237− , splitSuffixBy
238− , splitSuffixBy'
239− -- , splitPrefixBy
240− , wordsBy
241−
242− -- *** By Sequences
235+ -- *** Using Element Separators
236+ -- On == Dropping the separator
243237 , splitOn
244− , splitSuffixOn
245− -- , splitPrefixOn
246− -- , wordsOn
238+ , splitOnSuffix
239+ -- , splitOnPrefix
240+
241+ -- By == Keeping the separator
242+ -- , splitBy
243+ -- , splitBySuffix
244+ -- , splitByPrefix
245+ , wordsBy -- stripAndCompactBy
246+
247+ -- -- *** Using Sequence Separators
248+ -- , splitOnSeq
249+ -- , splitOnSuffixSeq
250+ -- , splitOnPrefixSeq
247251
248252 -- Keeping the delimiters
249− , splitOn'
250− , splitSuffixOn'
251− -- , splitPrefixOn'
253+ -- , splitBySeq
254+ -- , splitBySeqSuffix
255+ -- , splitBySeqPrefix
256+ -- , wordsBySeq
252257
253− -- Splitting by multiple sequences
254− -- , splitOnAny
255− -- , splitSuffixOnAny
256− -- , splitPrefixOnAny
258+ -- Splitting using multiple sequence separators
259+ -- , splitOnAnySeq
260+ -- , splitOnAnySuffixSeq
261+ -- , splitOnAnyPrefixSeq
257262
258263 -- ** Grouping
259264 , groups
260265 , groupsBy
261− , groupsRollingBy
266+ , groupsByRolling
262267
263268 -- * Distributing
264269 -- |
@@ -296,19 +301,26 @@ module Streamly.Fold
296301
297302 -- * Partitioning
298303 -- |
299− -- Direct items in the input stream to different folds using a function to
300− -- select the fold. This is useful to demultiplex the input stream.
304+ -- Direct items in the input stream to different folds using a binary
305+ -- fold selector.
306+
301307 -- , partitionByM
302308 -- , partitionBy
303309 , partition
304310
305311 -- * Demultiplexing
312+ -- | Direct values in the input stream to different folds using an n-ary
313+ -- fold selector.
314+
306315 , demux
307316 -- , demuxWith
308317 , demux_
309318 -- , demuxWith_
310319
311320 -- * Classifying
321+ -- | In an input stream of key value pairs fold values for different keys
322+ -- in individual output buckets using the given fold.
323+
312324 , classify
313325 -- , classifyWith
314326
@@ -318,7 +330,7 @@ module Streamly.Fold
318330 -- , unzipWith
319331 -- , unzipWithM
320332
321− -- * Nested Folds
333+ -- -- * Nested Folds
322334 -- , concatMap
323335 -- , chunksOf
324336 -- , duplicate -- experimental
@@ -403,6 +415,7 @@ import qualified Streamly.Prelude as S
403415import qualified Streamly.Streams.StreamD as D
404416import qualified Streamly.Streams.StreamK as K
405417import qualified Streamly.Streams.Prelude as P
418+import qualified Streamly.Streams.Parallel as Par
406419
407420-- $termination
408421--
@@ -1210,8 +1223,11 @@ sessionsOf
12101223 :: (IsStream t, MonadAsync m)
12111224 => Double -> Fold m a b -> t m a -> t m b
12121225sessionsOf n f xs =
1213− splitSuffixBy' isNothing (lcatMaybes f)
1214− (S.intersperseByTime n (return Nothing) (S.map Just xs))
1226+ splitBySuffix isNothing (lcatMaybes f)
1227+ (intersperseByTime n (return Nothing) (S.map Just xs))
1228+ where
1229+ intersperseByTime n f xs = xs `Par.parallelEndByFirst` S.repeatM timed
1230+ where timed = liftIO (threadDelay (round $ n * 1000000)) >> f
12151231
12161232------------------------------------------------------------------------------
12171233-- Element Aware APIs
@@ -1355,7 +1371,8 @@ _spanRollingBy cmp (Fold stepL initialL extractL) (Fold stepR initialR extractR)
13551371-- first group, if @a \`cmp` b@ is 'True' then @b@ is also assigned to the same
13561372-- group. If @a \`cmp` c@ is 'True' then @c@ is also assigned to the same
13571373-- 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.
13591376--
13601377-- >>> S.toList $ FL.groupsBy (>) FL.toList $ S.fromList [1,3,7,0,2,5]
13611378-- > [[1,3,7],[0,2,5]]
@@ -1371,31 +1388,31 @@ groupsBy
13711388groupsBy cmp f m = D.fromStreamD $ D.groupsBy cmp f (D.toStreamD m)
13721389
13731390-- | 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
13751392-- [a,b,c,...]@ assigns the element @a@ to the first group, if @a \`cmp` b@ is
13761393-- 'True' then @b@ is also assigned to the same group. If @b \`cmp` c@ is
13771394-- 'True' then @c@ is also assigned to the same group and so on. When the
13781395-- comparison fails a new group is started. Each group is folded using the fold
13791396-- @f@.
13801397--
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]
13821399-- > [[1,2,3],[7,8,9]]
13831400--
13841401-- @since 0.7.0
1385−{-# INLINE groupsRollingBy #-}
1386−groupsRollingBy
1402+{-# INLINE groupsByRolling #-}
1403+groupsByRolling
13871404 :: (IsStream t, Monad m)
13881405 => (a -> a -> Bool)
13891406 -> Fold m a b
13901407 -> t m a
13911408 -> 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)
13931410
13941411-- |
13951412-- > groups = groupsBy (==)
1396−-- > groups = groupsRollingBy (==)
1413+-- > groups = groupsByRolling (==)
13971414--
1398−-- Groups a contiguous span of equal elements together in one group.
1415+-- Groups contiguous spans of equal elements together in individual groups.
13991416--
14001417-- >>> S.toList $ FL.groups FL.toList $ S.fromList [1,1,2,2]
14011418-- > [[1,1],[2,2]]
@@ -1435,92 +1452,104 @@ breakOn pat f m = undefined
14351452-- as argument.
14361453
14371454-- | Split a stream on separator elements determined by a predicate, dropping
1438−-- the separator. Separators are not considered part of stream segments on
1439−-- either side of it instead they are treated as infixed between two stream
1440−-- segments. For example, with @.@ as separator, @"a.b.c"@ would be parsed as
1441−-- @["a","b","c"]@. When @.@ is in leading or trailing position it is still
1442−-- considered as infixed, treating the first or the last segment as empty. For
1443−-- example, @".a."@ would be parsed as @["","a",""]@. This operation is
1444−-- opposite of 'intercalate'.
1455+-- the separator. Separator is considered as infixed between two segments, if
1456+-- one side of the separator is missing then it is parsed as an empty stream.
1457+-- With '-' representing elements and '.' as separator, 'splitOn' splits as
1458+-- follows:
1459+--
1460+-- @
1461+-- "--.--" => "--" "--"
1462+-- "--." => "--" ""
1463+-- ".--" => "" "--"
1464+-- @
1465+--
1466+-- @splitOn (== x)@ is an inverse of @intercalate (S.yield x)@
14451467--
14461468-- Let's use the following definition for illustration:
14471469--
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)
14491471--
1450−-- >>> splitBy_ (== '.') ""
1472+-- >>> splitOn' (== '.') ""
14511473-- [""]
14521474--
1453−-- >>> splitBy_ (== '.') "."
1475+-- >>> splitOn' (== '.') "."
14541476-- ["",""]
14551477--
1456−-- >>> splitBy_ (== '.') ".a"
1478+-- >>> splitOn' (== '.') ".a"
14571479-- > ["","a"]
14581480--
1459−-- >>> splitBy_ (== '.') "a."
1481+-- >>> splitOn' (== '.') "a."
14601482-- > ["a",""]
14611483--
1462−-- >>> splitBy_ (== '.') "a.b"
1484+-- >>> splitOn' (== '.') "a.b"
14631485-- > ["a","b"]
14641486--
1465−-- >>> splitBy_ (== '.') "a..b"
1487+-- >>> splitOn' (== '.') "a..b"
14661488-- > ["a","","b"]
14671489--
1468−-- This can be considered as an n-fold version of 'break' where we apply
1469−-- 'break' successively on the input stream, dropping the first element
1490+-- @since 0.7.0
1491+
1492+-- This can be considered as an n-fold version of 'breakOn' where we apply
1493+-- 'breakOn' successively on the input stream, dropping the first element
14701494-- of the second segment after each break.
14711495--
1472−-- @since 0.7.0
1473−{-# INLINE splitBy #-}
1474−splitBy
1496+{-# INLINE splitOn #-}
1497+splitOn
14751498 :: (IsStream t, Monad m)
14761499 => (a -> Bool) -> Fold m a b -> t m a -> t m b
1477−splitBy predicate f m =
1500+splitOn predicate f m =
14781501 D.fromStreamD $ D.splitBy predicate f (D.toStreamD m)
14791502
1480−-- | Like 'splitBy' but the separator is treated as part of the previous
1481−-- stream segment (suffix). Therefore, when the separator is in trailing
1482−-- position, no empty segment is considered to follow it. For example, @"a.b."@
1483−-- would be parsed as @["a","b"]@ instead of @["a","b",""]@ as in the case of
1484−-- 'splitBy'.
1503+-- | Like 'splitOn' but the separator is considered as suffixed to the segments
1504+-- in the stream. A missing suffix at the end is allowed. A separator at the
1505+-- beginning is parsed as empty segment. With '-' representing elements and
1506+-- '.' as separator, 'splitOnSuffix' splits as follows:
1507+--
1508+-- @
1509+-- "--.--." => "--" "--"
1510+-- "--.--" => "--" "--"
1511+-- ".--." => "" "--"
1512+-- @
14851513--
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)
14871515--
1488−-- >>> splitSuffixBy_ (== '.') ""
1516+-- >>> splitOnSuffix' (== '.') ""
14891517-- []
14901518--
1491−-- >>> splitSuffixBy_ (== '.') "."
1519+-- >>> splitOnSuffix' (== '.') "."
14921520-- [""]
14931521--
1494−-- >>> splitSuffixBy_ (== '.') "a"
1522+-- >>> splitOnSuffix' (== '.') "a"
14951523-- ["a"]
14961524--
1497−-- >>> splitSuffixBy_ (== '.') ".a"
1525+-- >>> splitOnSuffix' (== '.') ".a"
14981526-- > ["","a"]
14991527--
1500−-- >>> splitSuffixBy_ (== '.') "a."
1528+-- >>> splitOnSuffix' (== '.') "a."
15011529-- > ["a"]
15021530--
1503−-- >>> splitSuffixBy_ (== '.') "a.b"
1531+-- >>> splitOnSuffix' (== '.') "a.b"
15041532-- > ["a","b"]
15051533--
1506−-- >>> splitSuffixBy_ (== '.') "a.b."
1534+-- >>> splitOnSuffix' (== '.') "a.b."
15071535-- > ["a","b"]
15081536--
1509−-- >>> splitSuffixBy_ (== '.') "a..b.."
1537+-- >>> splitOnSuffix' (== '.') "a..b.."
15101538-- > ["a","","b",""]
15111539--
1512−-- > lines = splitSuffixBy (== '\n')
1540+-- > lines = splitOnSuffix (== '\n')
15131541--
1542+-- @since 0.7.0
1543+
15141544-- This can be considered as an n-fold version of 'breakPost' where we apply
15151545-- 'breakPost' successively on the input stream, dropping the first element
15161546-- of the second segment after each break.
15171547--
1518−-- @since 0.7.0
1519−{-# INLINE splitSuffixBy #-}
1520−splitSuffixBy
1548+{-# INLINE splitOnSuffix #-}
1549+splitOnSuffix
15211550 :: (IsStream t, Monad m)
15221551 => (a -> Bool) -> Fold m a b -> t m a -> t m b
1523−splitSuffixBy predicate f m =
1552+splitOnSuffix predicate f m =
15241553 D.fromStreamD $ D.splitSuffixBy predicate f (D.toStreamD m)
15251554
15261555-- | Like 'splitBy' but ignores repeated separators or separators in leading
@@ -1549,49 +1578,45 @@ wordsBy
15491578wordsBy predicate f m =
15501579 D.fromStreamD $ D.wordsBy predicate f (D.toStreamD m)
15511580
1552−-- XXX we should express this using the Splitter config.
1581+-- | Like 'splitOnSuffix' but keeps the suffix attached to the resulting
1582+-- splits.
15531583--
1554−-- We can get splitSuffixBy' by appending the suffix to the output segments
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.
1557−
1558−-- | Like 'splitSuffixBy' but keeps the suffix in the splits.
1584+-- > splitBySuffix' p xs = S.toList $ FL.splitBySuffix p (FL.toList) (S.fromList xs)
15591585--
1560−-- > splitSuffixBy'_ p xs = S.toList $ FL.splitSuffixBy' p (FL.toList) (S.fromList xs)
1561−--
1562−-- >>> splitSuffixBy'_ (== '.') ""
1586+-- >>> splitBySuffix' (== '.') ""
15631587-- []
15641588--
1565−-- >>> splitSuffixBy'_ (== '.') "."
1589+-- >>> splitBySuffix' (== '.') "."
15661590-- ["."]
15671591--
1568−-- >>> splitSuffixBy'_ (== '.') "a"
1592+-- >>> splitBySuffix' (== '.') "a"
15691593-- ["a"]
15701594--
1571−-- >>> splitSuffixBy'_ (== '.') ".a"
1595+-- >>> splitBySuffix' (== '.') ".a"
15721596-- > [".","a"]
15731597--
1574−-- >>> splitSuffixBy'_ (== '.') "a."
1598+-- >>> splitBySuffix' (== '.') "a."
15751599-- > ["a."]
15761600--
1577−-- >>> splitSuffixBy'_ (== '.') "a.b"
1601+-- >>> splitBySuffix' (== '.') "a.b"
15781602-- > ["a.","b"]
15791603--
1580−-- >>> splitSuffixBy'_ (== '.') "a.b."
1604+-- >>> splitBySuffix' (== '.') "a.b."
15811605-- > ["a.","b."]
15821606--
1583−-- >>> splitSuffixBy'_ (== '.') "a..b.."
1607+-- >>> splitBySuffix' (== '.') "a..b.."
15841608-- > ["a.",".","b.","."]
15851609--
1610+-- @since 0.7.0
1611+
15861612-- This can be considered as an n-fold version of 'breakPost' where we apply
15871613-- 'breakPost' successively on the input stream.
15881614--
1589−-- @since 0.7.0
1590−{-# INLINE splitSuffixBy' #-}
1591−splitSuffixBy'
1615+{-# INLINE splitBySuffix #-}
1616+splitBySuffix
15921617 :: (IsStream t, Monad m)
15931618 => (a -> Bool) -> Fold m a b -> t m a -> t m b
1594−splitSuffixBy' predicate f m =
1619+splitBySuffix predicate f m =
15951620 D.fromStreamD $ D.splitSuffixBy' predicate f (D.toStreamD m)
15961621
15971622------------------------------------------------------------------------------
@@ -1624,43 +1649,43 @@ splitSuffixBy' predicate f m =
16241649-- >>> splitList [1,2,3,3,4] [1,2,3,3,4]
16251650-- > [[],[]]
16261651
1627−-- | Split the stream on both sides of a separator sequence, dropping the
1628−-- separator.
1652+-- | Like 'splitOn' but the separator is a sequence of elements instead of a
1653+-- single element.
16291654--
16301655-- For illustration, let's define a function that operates on pure lists:
16311656--
16321657-- @
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)
16341659-- @
16351660--
1636−-- >>> splitOn_ "" "hello"
1661+-- >>> splitOnSeq' "" "hello"
16371662-- > ["h","e","l","l","o"]
16381663--
1639−-- >>> splitOn_ "hello" ""
1664+-- >>> splitOnSeq' "hello" ""
16401665-- > [""]
16411666--
1642−-- >>> splitOn_ "hello" "hello"
1667+-- >>> splitOnSeq' "hello" "hello"
16431668-- > ["",""]
16441669--
1645−-- >>> splitOn_ "x" "hello"
1670+-- >>> splitOnSeq' "x" "hello"
16461671-- > ["hello"]
16471672--
1648−-- >>> splitOn_ "h" "hello"
1673+-- >>> splitOnSeq' "h" "hello"
16491674-- > ["","ello"]
16501675--
1651−-- >>> splitOn_ "o" "hello"
1676+-- >>> splitOnSeq' "o" "hello"
16521677-- > ["hell",""]
16531678--
1654−-- >>> splitOn_ "e" "hello"
1679+-- >>> splitOnSeq' "e" "hello"
16551680-- > ["h","llo"]
16561681--
1657−-- >>> splitOn_ "l" "hello"
1682+-- >>> splitOnSeq' "l" "hello"
16581683-- > ["he","","o"]
16591684--
1660−-- >>> splitOn_ "ll" "hello"
1685+-- >>> splitOnSeq' "ll" "hello"
16611686-- > ["he","o"]
16621687--
1663−-- 'splitOn' is an inverse of 'intercalate'. The following law always holds:
1688+-- 'splitOnSeq' is an inverse of 'intercalate'. The following law always holds:
16641689--
16651690-- > intercalate . splitOn == id
16661691--
@@ -1669,16 +1694,18 @@ splitSuffixBy' predicate f m =
16691694--
16701695-- > splitOn . intercalate == id
16711696--
1672−-- The following law always holds:
1673−--
1674−-- > concat . splitOn . intercalate == concat
1675−--
16761697-- @since 0.7.0
1677−{-# INLINE splitOn #-}
1678−splitOn
1698+
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.
1704+{-# INLINE splitOnSeq #-}
1705+splitOnSeq
16791706 :: (IsStream t, MonadIO m, Storable a, Enum a, Eq a)
16801707 => 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)
16821709
16831710{-
16841711-- 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
17221749-- > lines = splitSuffixOn "\n"
17231750--
17241751-- @since 0.7.0
1725−{-# INLINE splitSuffixOn #-}
1726−splitSuffixOn
1752+{-# INLINE splitOnSuffixSeq #-}
1753+splitOnSuffixSeq
17271754 :: (IsStream t, MonadIO m, Storable a, Enum a, Eq a)
17281755 => Array a -> Fold m a b -> t m a -> t m b
1729−splitSuffixOn patt f m =
1756+splitOnSuffixSeq patt f m =
17301757 D.fromStreamD $ D.splitSuffixOn False patt f (D.toStreamD m)
17311758
17321759{-
@@ -1741,7 +1768,7 @@ wordsOn subseq f m = undefined -- D.fromStreamD $ D.wordsOn f subseq (D.toStream
17411768
17421769-- XXX use a non-monadic intersperse to remove the MonadAsync constraint.
17431770--
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.
17451772--
17461773-- > splitOn'_ pat xs = S.toList $ FL.splitOn' (A.fromList pat) (FL.toList) (S.fromList xs)
17471774--
@@ -1773,11 +1800,11 @@ wordsOn subseq f m = undefined -- D.fromStreamD $ D.wordsOn f subseq (D.toStream
17731800-- > ["he","ll","o"]
17741801--
17751802-- @since 0.7.0
1776−{-# INLINE splitOn' #-}
1777−splitOn'
1803+{-# INLINE splitBySeq #-}
1804+splitBySeq
17781805 :: (IsStream t, MonadAsync m, Storable a, Enum a, Eq a)
17791806 => 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
17811808
17821809-- | Like 'splitSuffixOn' but keeps the suffix intact in the splits.
17831810--
@@ -1808,11 +1835,11 @@ splitOn' patt f m = S.intersperseM (foldl' f (A.read patt)) $ splitOn patt f m
18081835-- > ["a.",".","b.","."]
18091836--
18101837-- @since 0.7.0
1811−{-# INLINE splitSuffixOn' #-}
1812−splitSuffixOn'
1838+{-# INLINE splitBySuffixSeq #-}
1839+splitBySuffixSeq
18131840 :: (IsStream t, MonadIO m, Storable a, Enum a, Eq a)
18141841 => Array a -> Fold m a b -> t m a -> t m b
1815−splitSuffixOn' patt f m =
1842+splitBySuffixSeq patt f m =
18161843 D.fromStreamD $ D.splitSuffixOn True patt f (D.toStreamD m)
18171844
18181845{-
@@ -1882,7 +1909,8 @@ foldCons (Fold stepL beginL doneL) (Fold stepR beginR doneR) =
18821909 done (Tuple' xL xR) = (:) <$> (doneL xL) <*> (doneR xR)
18831910
18841911-- 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.
18861914--
18871915-- | Distribute one copy of the stream to each fold and collect the results in
18881916-- a container.
@@ -2010,11 +2038,15 @@ partition = partitionBy id
20102038-- partitionN fs = Fold step begin done
20112039-}
20122040
2013−-- Demultiplex an input element into a number of typed variants. We want to
2014−-- statically restrict the target values within a set of predefined types, an
2015−-- enumeration of a GADT. We also want to make sure that the Map contains only
2016−-- those types and the full set of those types. Instead of Map it should
2017−-- probably be a lookup-table using an array and not in GC memory.
2041+-- TODO Demultiplex an input element into a number of typed variants. We want
2042+-- to statically restrict the target values within a set of predefined types,
2043+-- an enumeration of a GADT. We also want to make sure that the Map contains
2044+-- only those types and the full set of those types.
2045+--
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.
20182050--
20192051-- This is the consumer side dual of the producer side 'mux' operation (XXX to
20202052-- be implemented).
@@ -2131,9 +2163,9 @@ demuxWith_ f kv = Fold step initial extract
21312163demux_ :: (Monad m, Ord k) => Map k (Fold m a ()) -> Fold m (k, a) ()
21322164demux_ fs = demuxWith_ fst (Map.map (lmap snd) fs)
21332165
2134−-- XXX instead of a Map we could yield the results as a pure stream as they
2135−-- complete. We could then concatMap the fold results to implement the
2136−-- windowing combinators.
2166+-- TODO If the data is large we may need a map/hashmap in pinned memory instead
2167+-- of a regular Map. That may require a serializable constraint though. We can
2168+-- have another API for that.
21372169--
21382170-- | Split the input stream based on a key field and fold each split using the
21392171-- 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'
21752207-- fromList [(\"ONE",[1.1,1.0]),(\"TWO",[2.2,2.0])]
21762208-- @
21772209--
2210+-- @since 0.7.0
2211+
21782212-- Same as:
21792213--
21802214-- > classify fld = classifyWith fst (lmap snd fld)
21812215--
2182−-- @since 0.7.0
21832216{-# INLINE classify #-}
21842217classify :: (Monad m, Ord k) => Fold m a b -> Fold m (k, a) (Map k b)
21852218classify fld = classifyWith fst (lmap snd fld)
@@ -2219,9 +2252,9 @@ unzipWith f = unzipWithM (return . f)
22192252--
22202253-- @
22212254--
2222−-- |-------Fold a x--------|
2223−-- -----Stream m x----(a,b)--| |----m (x,y)
2224−-- |-------Fold b y--------|
2255+-- |-------Fold m a x--------|
2256+-- ---------stream of (a,b)--| |----m (x,y)
2257+-- |-------Fold m b y--------|
22252258--
22262259-- @
22272260--
src/Streamly/String.hs+2−2
@@ -171,7 +171,7 @@ stripStart = S.dropWhile isSpace
171171-- ["lines", "this", "string", "", ""]
172172{-# INLINE foldLines #-}
173173foldLines :: (Monad m, IsStream t) => t m Char -> Fold m Char b -> t m b
174−foldLines = flip (FL.splitSuffixBy (== '\n'))
174+foldLines = flip (FL.splitOnSuffix (== '\n'))
175175
176176-- | Fold each word of the stream using the supplied Fold
177177-- and stream the result.
@@ -204,7 +204,7 @@ isSpace c
204204-- 'foldLines' instead.
205205{-# INLINE lines #-}
206206lines :: (MonadIO m, IsStream t) => t m Char -> t m (Array Char)
207−lines = FL.splitSuffixBy (== '\n') toArray
207+lines = FL.splitOnSuffix (== '\n') toArray
208208
209209-- | Break a string up into a list of strings, which were delimited
210210-- by characters representing white space.
test/Prop.hs+24−13
@@ -24,7 +24,7 @@ import GHC.Word (Word8)
2424import Test.Hspec.QuickCheck
2525import Test.QuickCheck
2626 (counterexample, Property, withMaxSuccess, forAll, choose, Gen,
27− arbitrary, elements, frequency, listOf, listOf1, vectorOf, suchThat)
27+ arbitrary, elements, frequency, listOf) --, listOf1, vectorOf, suchThat)
2828import Test.QuickCheck.Monadic (run, monadicIO, monitor, assert, PropertyM)
2929
3030import Test.Hspec as H
@@ -493,7 +493,7 @@ transformCombineOpsCommon constr desc eq t = do
493493
494494 -- reordering
495495 prop (desc <> " reverse") $ transform reverse t S.reverse
496− prop (desc <> " reverse'") $ transform reverse t S.reverse'
496+ -- prop (desc <> " reverse'") $ transform reverse t S.reverse'
497497
498498 -- inserting
499499 prop (desc <> " intersperseM") $
@@ -510,56 +510,66 @@ transformCombineOpsCommon constr desc eq t = do
510510 t (S.concatMap (const (S.fromList [1..n])))
511511
512512toListFL :: Monad m => FL.Fold m a [a]
513−toListFL = fmap reverse FL.toListRev
513+toListFL = FL.toList
514514
515515groupSplitOps :: String -> Spec
516516groupSplitOps desc = do
517517 -- splitting
518518 -- XXX add tests with multichar separators too
519519
520− prop (desc <> " intercalate . splitOn == id (nil separator)") $
520+{-
521+ prop (desc <> " intercalate . splitOnSeq == id (nil separator)") $
521522 forAll listWithZeroes $ \xs -> do
522523 withMaxSuccess maxTestCount $
523524 monadicIO $ do
524− ys <- S.toList $ FL.splitOn [] toListFL (S.fromList xs)
525+ ys <- S.toList $ FL.splitOnSeq [] toListFL (S.fromList xs)
525526 listEquals (==) (intercalate [] ys) xs
526527
527− prop (desc <> " intercalate . splitOn == id (single element separator)") $
528+ prop (desc <> " intercalate . splitOnSeq == id (single element separator)") $
528529 forAll listWithZeroes $ \xs -> do
529530 withMaxSuccess maxTestCount $
530531 monadicIO $ do
531− ys <- S.toList $ FL.splitOn [0] toListFL (S.fromList xs)
532+ ys <- S.toList $ FL.splitOnSeq [0] toListFL (S.fromList xs)
532533 listEquals (==) (intercalate [0] ys) xs
533534
534− prop (desc <> " concat . splitOn . intercalate == concat (nil separator/possibly empty list)") $
535+ prop (desc <> " concat . splitOnSeq . intercalate == concat (nil separator/possibly empty list)") $
535536 forAll listsWithoutZeroes $ \xss -> do
536537 withMaxSuccess maxTestCount $
537538 monadicIO $ do
538539 let xs = intercalate [] xss
539− ys <- S.toList $ FL.splitOn [0] toListFL (S.fromList xs)
540+ ys <- S.toList $ FL.splitOnSeq [0] toListFL (S.fromList xs)
540541 listEquals (==) (concat ys) (concat xss)
541542
542− prop (desc <> " concat . splitOn . intercalate == concat (non-nil separator/possibly empty list)") $
543+ prop (desc <> " concat . splitOnSeq . intercalate == concat (non-nil separator/possibly empty list)") $
543544 forAll listsWithoutZeroes $ \xss -> do
544545 withMaxSuccess maxTestCount $
545546 monadicIO $ do
546547 let xs = intercalate [0] xss
547− ys <- S.toList $ FL.splitOn [0] toListFL (S.fromList xs)
548+ ys <- S.toList $ FL.splitOnSeq [0] toListFL (S.fromList xs)
548549 listEquals (==) (concat ys) (concat xss)
549550
550− prop (desc <> " splitOn . intercalate == id (exclusive separator/non-empty list)") $
551+ prop (desc <> " splitOnSeq . intercalate == id (exclusive separator/non-empty list)") $
551552 forAll listsWithoutZeroes1 $ \xss -> do
552553 withMaxSuccess maxTestCount $
553554 monadicIO $ do
554555 let xs = intercalate [0] xss
555− ys <- S.toList $ FL.splitOn [0] toListFL (S.fromList xs)
556+ ys <- S.toList $ FL.splitOnSeq [0] toListFL (S.fromList xs)
556557 listEquals (==) ys xss
558+-}
559+
560+ prop (desc <> " intercalate [x] . splitOn (== x) == id") $
561+ forAll listWithZeroes $ \xs -> do
562+ withMaxSuccess maxTestCount $
563+ monadicIO $ do
564+ ys <- S.toList $ FL.splitOn (== 0) toListFL (S.fromList xs)
565+ listEquals (==) (intercalate [0] ys) xs
557566
558567 where
559568
560569 listWithZeroes :: Gen [Int]
561570 listWithZeroes = listOf $ frequency [(3, arbitrary), (1, elements [0])]
562571
572+{-
563573 listWithoutZeroes = vectorOf 4 $ suchThat arbitrary (/= 0)
564574
565575 listsWithoutZeroes :: Gen [[Int]]
@@ -567,6 +577,7 @@ groupSplitOps desc = do
567577
568578 listsWithoutZeroes1 :: Gen [[Int]]
569579 listsWithoutZeroes1 = listOf1 listWithoutZeroes
580+-}
570581
571582-- transformation tests that can only work reliably for ordered streams i.e.
572583-- Serial, Ahead and Zip. For example if we use "take 1" on an async stream, it