@@ -92,6 +92,7 @@ module Streamly.Internal.Data.Parser
9292 , escapedFrameBy
9393 , wordBy
9494 , groupBy
95+ , groupByRolling
9596 , eqBy
9697 -- | Unimplemented
9798 --
@@ -595,6 +596,38 @@ wordBy f = K.toParserK . D.wordBy f
595596groupBy :: MonadCatch m => (a -> a -> Bool) -> Fold m a b -> Parser m a b
596597groupBy cmp = K.toParserK . D.groupBy cmp
597598
599+-- | Unlike 'groupBy' this combinator performs a rolling comparison of two
600+-- successive elements in the input stream. Assuming the input stream to the
601+-- parser is @[a,b,c,...]@ and the comparison function is @cmp@, the parser
602+-- first assigns the element @a@ to the first group, then if @a \`cmp` b@ is
603+-- 'True' @b@ is also assigned to the same group. If @b \`cmp` c@ is 'True'
604+-- then @c@ is also assigned to the same group and so on. When the comparison
605+-- fails the parser is terminated. Each group is folded using the 'Fold' @f@ and
606+-- the result of the fold is the result of the parser.
607+--
608+-- * Stops - when the comparison fails.
609+-- * Fails - never.
610+--
611+-- > runGroupsByRolling eq =
612+-- > Stream.toList
613+-- > . Stream.parseMany (groupByRolling eq Fold.toList)
614+-- > . Stream.fromList
615+--
616+-- >>> runGroupsByRolling (<) []
617+-- []
618+--
619+-- >>> runGroupsByRolling (<) [1]
620+-- [[1]]
621+--
622+-- >>> runGroupsByRolling (<) [3, 5, 4, 1, 2, 0]
623+-- [[3, 5], [4], [1, 2], [0]]
624+--
625+-- /Internal/
626+--
627+{-# INLINABLE groupByRolling #-}
628+groupByRolling :: MonadCatch m => (a -> a -> Bool) -> Fold m a b -> Parser m a b
629+groupByRolling eq = K.toParserK . D.groupByRolling eq
630+
598631-- | Match the given sequence of elements using the given comparison function.
599632--
600633-- >>> S.parse $ S.eqBy (==) "string" $ S.fromList "string"