on master help sign in
Re-implement span, spanBy, and spanByRolling as parsers
commit27d357585526d29aa49c78a1a2fd2e0e5d61ac00 authorAdithya Kumar <adithya@composewell.com> dateTue 9 Feb 2021, 23:28 (6 years ago) parentde51477
2 files changed+60−21
benchmark/Streamly/Benchmark/Data/Parser/ParserD.hs+7−20 src/Streamly/Internal/Data/Parser/ParserD.hs+53−1
benchmark/Streamly/Benchmark/Data/Parser/ParserD.hs+7−20
@@ -175,35 +175,22 @@ longestAllAny value =
175175 )
176176
177177-------------------------------------------------------------------------------
178−-- Derived parsers
178+-- Spanning
179179-------------------------------------------------------------------------------
180180
181181{-# INLINE span #-}
182182span :: MonadThrow m => Int -> SerialT m Int -> m ((), ())
183−span value = IP.parseD (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)
183+span value = IP.parseD (PR.span (<= (value `div` 2)) FL.drain FL.drain)
188184
189185{-# INLINE spanBy #-}
190186spanBy :: MonadThrow m => Int -> SerialT m Int -> m ((), ())
191187spanBy value =
192− IP.parseD (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)
188+ IP.parseD (PR.spanBy (\_ i -> i <= (value `div` 2)) FL.drain FL.drain)
197189
198190{-# INLINE spanByRolling #-}
199191spanByRolling :: MonadThrow m => Int -> SerialT m Int -> m ((), ())
200192spanByRolling value =
201− IP.parseD (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)
193+ IP.parseD (PR.spanByRolling (\_ i -> i <= value `div` 2) FL.drain FL.drain)
207194
208195-------------------------------------------------------------------------------
209196-- Parsers in which -fspec-constr-recursive=16 is problematic
@@ -272,8 +259,8 @@ o_1_space_serial value =
272259 , benchIOSink value "longest (all,any)" $ longestAllAny value
273260 ]
274261
275−o_1_space_serial_derived :: Int -> [Benchmark]
276−o_1_space_serial_derived value =
262+o_1_space_serial_spanning :: Int -> [Benchmark]
263+o_1_space_serial_spanning value =
277264 [ benchIOSink value "span" $ span value
278265 , benchIOSink value "spanBy" $ spanBy value
279266 , benchIOSink value "spanByRolling" $ spanByRolling value
@@ -313,7 +300,7 @@ main = do
313300
314301 allBenchmarks value =
315302 [ 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)
317304 , bgroup (o_n_heap_prefix moduleName) (o_n_heap_serial value)
318305 , bgroup (o_n_space_prefix moduleName) (o_n_space_serial value)
319306 ]
src/Streamly/Internal/Data/Parser/ParserD.hs+53−1
@@ -69,6 +69,11 @@ module Streamly.Internal.Data.Parser.ParserD
6969 -- , suffixOf -- match any suffix of a given string
7070 -- , infixOf -- match any substring of a given string
7171
72+ -- ** Spanning
73+ , span
74+ , spanBy
75+ , spanByRolling
76+
7277 -- Second order parsers (parsers using parsers)
7378 -- * Binary Combinators
7479
@@ -162,7 +167,7 @@ import Streamly.Internal.Data.Tuple.Strict (Tuple'(..))
162167import qualified Streamly.Internal.Data.Fold.Types as FL
163168
164169import Prelude hiding
165− (any, all, take, takeWhile, sequence, concatMap, maybe, either)
170+ (any, all, take, takeWhile, sequence, concatMap, maybe, either, span)
166171import Streamly.Internal.Data.Parser.ParserD.Tee
167172import Streamly.Internal.Data.Parser.ParserD.Types
168173
@@ -724,6 +729,53 @@ eqBy cmp str = Parser step initial extract
724729 $ "eqBy: end of input, yet to match "
725730 ++ show (length xs) ++ " elements"
726731
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+
727779-------------------------------------------------------------------------------
728780-- nested parsers
729781-------------------------------------------------------------------------------