@@ -69,6 +69,11 @@ module Streamly.Internal.Data.Parser.ParserD
69 -- , suffixOf -- match any suffix of a given string
69 -- , suffixOf -- match any suffix of a given string
70 -- , infixOf -- match any substring of a given string
70 -- , infixOf -- match any substring of a given string
72 -- Second order parsers (parsers using parsers)
77 -- Second order parsers (parsers using parsers)
73 -- * Binary Combinators
78 -- * Binary Combinators
@@ -162,7 +167,7 @@ import Streamly.Internal.Data.Tuple.Strict (Tuple'(..))
162import qualified Streamly.Internal.Data.Fold.Types as FL
167import qualified Streamly.Internal.Data.Fold.Types as FL
164import Prelude hiding
169import Prelude hiding
165− (any, all, take, takeWhile, sequence, concatMap, maybe, either)
170+ (any, all, take, takeWhile, sequence, concatMap, maybe, either, span)
166import Streamly.Internal.Data.Parser.ParserD.Tee
171import Streamly.Internal.Data.Parser.ParserD.Tee
167import Streamly.Internal.Data.Parser.ParserD.Types
172import Streamly.Internal.Data.Parser.ParserD.Types
@@ -724,6 +729,53 @@ eqBy cmp str = Parser step initial extract
724 $ "eqBy: end of input, yet to match "
729 $ "eqBy: end of input, yet to match "
725 ++ show (length xs) ++ " elements"
730 ++ show (length xs) ++ " elements"
732+--------------------------------------------------------------------------------
734+--------------------------------------------------------------------------------
736+-- | @span p f1 f2@ composes folds @f1@ and @f2@ such that @f1@ consumes the
737+-- input as long as the predicate @p@ is 'True'. @f2@ consumes the rest of the
740+-- > let span_ p xs = S.parse (FL.span p FL.toList FL.toList) $ S.fromList xs
742+-- >>> span_ (< 1) [1,2,3]
745+-- >>> span_ (< 2) [1,2,3]
748+-- >>> span_ (< 4) [1,2,3]
753+span :: Monad m => (a -> Bool) -> Fold m a b -> Fold m a c -> Parser m a (b, c)
754+span p f1 f2 = noErrorUnsafeSplitWith (,) (takeWhile p f1) (fromFold f2)
756+-- | Break the input stream into two groups, the first group takes the input as
757+-- long as the predicate applied to the first element of the stream and next
758+-- input element holds 'True', the second group takes the rest of the input.
762+{-# INLINE spanBy #-}
765+ => (a -> a -> Bool) -> Fold m a b -> Fold m a c -> Parser m a (b, c)
766+spanBy eq f1 f2 = noErrorUnsafeSplitWith (,) (groupBy eq f1) (fromFold f2)
768+-- | Like 'spanBy' but applies the predicate in a rolling fashion i.e.
769+-- predicate is applied to the previous and the next input elements.
772+{-# INLINE spanByRolling #-}
775+ => (a -> a -> Bool) -> Fold m a b -> Fold m a c -> Parser m a (b, c)
776+spanByRolling eq f1 f2 =
777+ noErrorUnsafeSplitWith (,) (groupByRolling eq f1) (fromFold f2)
727-------------------------------------------------------------------------------
779-------------------------------------------------------------------------------
728-- nested parsers
780-- nested parsers
729-------------------------------------------------------------------------------
781-------------------------------------------------------------------------------