on master help sign in
Re-implement span, spanBy, and spanByRolling as parsers
27d3575Adithya Kumar
benchmark/Streamly/Benchmark/Data/Parser/ParserD.hs+7−20
@@ -175,35 +175,22 @@ longestAllAny value =
175 )
175 )
176
176
177-------------------------------------------------------------------------------
177-------------------------------------------------------------------------------
178−-- Derived parsers
178+-- Spanning
179-------------------------------------------------------------------------------
179-------------------------------------------------------------------------------
180
180
181{-# INLINE span #-}
181{-# INLINE span #-}
182span :: MonadThrow m => Int -> SerialT m Int -> m ((), ())
182span :: MonadThrow m => Int -> SerialT m Int -> m ((), ())
183−span value = IP.parseD (span_ (<= (value `div` 2)) FL.drain FL.drain)
183+span value = IP.parseD (PR.span (<= (value `div` 2)) FL.drain FL.drain)
184−
185− where
186−
187− span_ p f1 f2 = PR.splitWith (,) (PR.takeWhile p f1) (PR.fromFold f2)
188
184
189{-# INLINE spanBy #-}
185{-# INLINE spanBy #-}
190spanBy :: MonadThrow m => Int -> SerialT m Int -> m ((), ())
186spanBy :: MonadThrow m => Int -> SerialT m Int -> m ((), ())
191spanBy value =
187spanBy value =
192− IP.parseD (spanBy_ (\_ i -> i <= (value `div` 2)) FL.drain FL.drain)
188+ IP.parseD (PR.spanBy (\_ i -> i <= (value `div` 2)) FL.drain FL.drain)
193−
194− where
195−
196− spanBy_ c f1 f2 = PR.splitWith (,) (PR.groupBy c f1) (PR.fromFold f2)
197
189
198{-# INLINE spanByRolling #-}
190{-# INLINE spanByRolling #-}
199spanByRolling :: MonadThrow m => Int -> SerialT m Int -> m ((), ())
191spanByRolling :: MonadThrow m => Int -> SerialT m Int -> m ((), ())
200spanByRolling value =
192spanByRolling value =
201− IP.parseD (spanByRolling_ (\_ i -> i <= value `div` 2) FL.drain FL.drain)
193+ IP.parseD (PR.spanByRolling (\_ i -> i <= value `div` 2) FL.drain FL.drain)
202−
203− where
204−
205− spanByRolling_ c f1 f2 =
206− PR.splitWith (,) (PR.groupByRolling c f1) (PR.fromFold f2)
207
194
208-------------------------------------------------------------------------------
195-------------------------------------------------------------------------------
209-- Parsers in which -fspec-constr-recursive=16 is problematic
196-- Parsers in which -fspec-constr-recursive=16 is problematic
@@ -272,8 +259,8 @@ o_1_space_serial value =
272 , benchIOSink value "longest (all,any)" $ longestAllAny value
259 , benchIOSink value "longest (all,any)" $ longestAllAny value
273 ]
260 ]
274
261
275−o_1_space_serial_derived :: Int -> [Benchmark]
262+o_1_space_serial_spanning :: Int -> [Benchmark]
276−o_1_space_serial_derived value =
263+o_1_space_serial_spanning value =
277 [ benchIOSink value "span" $ span value
264 [ benchIOSink value "span" $ span value
278 , benchIOSink value "spanBy" $ spanBy value
265 , benchIOSink value "spanBy" $ spanBy value
279 , benchIOSink value "spanByRolling" $ spanByRolling value
266 , benchIOSink value "spanByRolling" $ spanByRolling value
@@ -313,7 +300,7 @@ main = do
313
300
314 allBenchmarks value =
301 allBenchmarks value =
315 [ bgroup (o_1_space_prefix moduleName) (o_1_space_serial value)
302 [ bgroup (o_1_space_prefix moduleName) (o_1_space_serial value)
316− , bgroup (o_1_space_prefix moduleName) (o_1_space_serial_derived value)
303+ , bgroup (o_1_space_prefix moduleName) (o_1_space_serial_spanning value)
317 , bgroup (o_n_heap_prefix moduleName) (o_n_heap_serial value)
304 , bgroup (o_n_heap_prefix moduleName) (o_n_heap_serial value)
318 , bgroup (o_n_space_prefix moduleName) (o_n_space_serial value)
305 , bgroup (o_n_space_prefix moduleName) (o_n_space_serial value)
319 ]
306 ]
src/Streamly/Internal/Data/Parser/ParserD.hs+53−1
@@ -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
71
71
72+ -- ** Spanning
73+ , span
74+ , spanBy
75+ , spanByRolling
76+
72 -- Second order parsers (parsers using parsers)
77 -- Second order parsers (parsers using parsers)
73 -- * Binary Combinators
78 -- * Binary Combinators
74
79
@@ -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
163
168
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
168
173
@@ -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"
726
731
732+--------------------------------------------------------------------------------
733+--- Spanning
734+--------------------------------------------------------------------------------
735+
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
738+-- input.
739+--
740+-- > let span_ p xs = S.parse (FL.span p FL.toList FL.toList) $ S.fromList xs
741+--
742+-- >>> span_ (< 1) [1,2,3]
743+-- > ([],[1,2,3])
744+--
745+-- >>> span_ (< 2) [1,2,3]
746+-- > ([1],[2,3])
747+--
748+-- >>> span_ (< 4) [1,2,3]
749+-- > ([1,2,3],[])
750+--
751+-- /Internal/
752+{-# INLINE span #-}
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)
755+
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.
759+--
760+-- /Internal/
761+--
762+{-# INLINE spanBy #-}
763+spanBy ::
764+ Monad m
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)
767+
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.
770+--
771+-- /Internal/
772+{-# INLINE spanByRolling #-}
773+spanByRolling ::
774+ Monad m
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)
778+
727-------------------------------------------------------------------------------
779-------------------------------------------------------------------------------
728-- nested parsers
780-- nested parsers
729-------------------------------------------------------------------------------
781-------------------------------------------------------------------------------