@@ -39,6 +39,9 @@ module Streamly.Internal.Data.Stream.StreamD.Transform
40 , scanMany
40 , scanMany
42 -- * Scanning
45 -- * Scanning
43 -- | Left scans. Stateful, mostly one-to-one maps.
46 -- | Left scans. Stateful, mostly one-to-one maps.
@@ -1842,3 +1845,61 @@ catRights = fmap (fromRight undefined) . filter isRight
1842{-# INLINE catEithers #-}
1845{-# INLINE catEithers #-}
1843catEithers :: Monad m => Stream m (Either a a) -> Stream m a
1846catEithers :: Monad m => Stream m (Either a a) -> Stream m a
1844catEithers = fmap (either id id)
1847catEithers = fmap (either id id)
1849+------------------------------------------------------------------------------
1851+------------------------------------------------------------------------------
1853+-- | Split on an infixed separator element, dropping the separator. The
1854+-- supplied 'Fold' is applied on the split segments. Splits the stream on
1855+-- separator elements determined by the supplied predicate, separator is
1856+-- considered as infixed between two segments:
1858+-- >>> splitOn' p xs = Stream.fold Fold.toList $ Stream.splitOn p Fold.toList (Stream.fromList xs)
1859+-- >>> splitOn' (== '.') "a.b"
1862+-- An empty stream is folded to the default value of the fold:
1864+-- >>> splitOn' (== '.') ""
1867+-- If one or both sides of the separator are missing then the empty segment on
1868+-- that side is folded to the default output of the fold:
1870+-- >>> splitOn' (== '.') "."
1873+-- >>> splitOn' (== '.') ".a"
1876+-- >>> splitOn' (== '.') "a."
1879+-- >>> splitOn' (== '.') "a..b"
1882+-- splitOn is an inverse of intercalating single element:
1884+-- > Stream.intercalate (Stream.fromPure '.') Unfold.fromList . Stream.splitOn (== '.') Fold.toList === id
1886+-- Assuming the input stream does not contain the separator:
1888+-- > Stream.splitOn (== '.') Fold.toList . Stream.intercalate (Stream.fromPure '.') Unfold.fromList === id
1890+{-# INLINE splitOn #-}
1891+splitOn :: Monad m => (a -> Bool) -> Fold m a b -> Stream m a -> Stream m b
1892+splitOn predicate f =
1893+ -- We can express the infix splitting in terms of optional suffix split
1894+ -- fold. After applying a suffix split fold repeatedly if the last segment
1895+ -- ends with a suffix then we need to return the default output of the fold
1896+ -- after that to make it an infix split.
1898+ -- Alternately, we can also express it using an optional prefix split fold.
1899+ -- If the first segment starts with a prefix then we need to emit the
1900+ -- default output of the fold before that to make it an infix split, and
1901+ -- then apply prefix split fold repeatedly.
1903+ -- Since a suffix split fold can be easily expressed using a
1904+ -- non-backtracking fold, we use that.
1905+ foldManyPost (FL.takeEndBy_ predicate f)