on master help sign in
Implement takeBetween
4ee157fAnurag Hooda
src/Streamly/Internal/Data/Parser.hs+27−5
@@ -337,8 +337,30 @@ either = K.toParserK . D.either
337-- | @takeBetween m n@ takes a minimum of @m@ and a maximum of @n@ input
337-- | @takeBetween m n@ takes a minimum of @m@ and a maximum of @n@ input
338-- elements and folds them using the supplied fold.
338-- elements and folds them using the supplied fold.
339--
339--
340−-- Stops after @n@ elements.
340+-- Stops after @m@ elements.
341−-- Fails if the stream ends before @m@ elements could be taken.
341+-- Fails if the stream ends before @n@ elements could be taken.
342+--
343+-- Examples: -
344+--
345+-- @
346+-- takeBetween' low high ls = S.parse prsr (S.fromList ls)
347+-- where prsr = P.takeBetween low high FL.toList
348+-- @
349+--
350+-- >>> takeBetween' 2 4 [1, 2, 3, 4, 5]
351+-- > [1,2,3,4]
352+--
353+-- >>> takeBetween' 2 4 [1, 2]
354+-- > [1,2]
355+--
356+-- >>> takeBetween' 2 4 [1]
357+-- > ParseError "takeBetween: Expecting alteast 2 elements, got 1"
358+--
359+-- >>> takeBetween' 0 0 [1, 2]
360+-- > []
361+--
362+-- >>> takeBetween' 0 1 []
363+-- > []
342--
364--
343-- @takeBetween@ is the most general take operation, other take operations can
365-- @takeBetween@ is the most general take operation, other take operations can
344-- be defined in terms of takeBetween. For example:
366-- be defined in terms of takeBetween. For example:
@@ -350,12 +372,12 @@ either = K.toParserK . D.either
350-- takeGE = takeBetween n maxBound
372-- takeGE = takeBetween n maxBound
351-- @
373-- @
352--
374--
353−-- /Unimplemented/
375+-- /Internal/
354--
376--
355{-# INLINE takeBetween #-}
377{-# INLINE takeBetween #-}
356−takeBetween :: -- MonadCatch m =>
378+takeBetween :: MonadCatch m =>
357 Int -> Int -> Fold m a b -> Parser m a b
379 Int -> Int -> Fold m a b -> Parser m a b
358−takeBetween _m _n = undefined -- K.toParserK . D.takeBetween m n
380+takeBetween m n = K.toParserK . D.takeBetween m n
359
381
360-- | Stops after taking exactly @n@ input elements.
382-- | Stops after taking exactly @n@ input elements.
361--
383--
src/Streamly/Internal/Data/Parser/ParserD.hs+54−1
@@ -43,7 +43,7 @@ module Streamly.Internal.Data.Parser.ParserD
43 -- takeWhileBetween cond m n p = takeWhile cond (takeBetween m n p)
43 -- takeWhileBetween cond m n p = takeWhile cond (takeBetween m n p)
44 --
44 --
45 -- Grab a sequence of input elements without inspecting them
45 -- Grab a sequence of input elements without inspecting them
46− -- , takeBetween
46+ , takeBetween
47 -- , takeLE -- take -- takeBetween 0 n
47 -- , takeLE -- take -- takeBetween 0 n
48 -- , takeLE1 -- take1 -- takeBetween 1 n
48 -- , takeLE1 -- take1 -- takeBetween 1 n
49 , takeEQ -- takeBetween n n
49 , takeEQ -- takeBetween n n
@@ -281,6 +281,59 @@ either parser = Parser step initial extract
281-- Taking elements
281-- Taking elements
282-------------------------------------------------------------------------------
282-------------------------------------------------------------------------------
283
283
284+-- | See 'Streamly.Internal.Data.Parser.takeBetween'.
285+--
286+-- /Internal/
287+--
288+{-# INLINE takeBetween #-}
289+takeBetween :: MonadCatch m => Int -> Int -> Fold m a b -> Parser m a b
290+takeBetween low high (Fold fstep finitial fextract) =
291+
292+ Parser step initial extract
293+
294+ where
295+
296+ initial = Tuple' 0 <$> finitial
297+
298+ step (Tuple' i s) a
299+ | low > high = throwM $ ParseError
300+ $ "takeBetween: lower bound - " ++ show low
301+ ++ " is greater than higher bound - " ++ show high
302+ | high <= 0 = Done 1 <$> fextract s
303+ | i1 < low = do
304+ res <- fstep s a
305+ return
306+ $ case res of
307+ FL.Partial s' -> Continue 0 $ Tuple' i1 s'
308+ FL.Done _ ->
309+ Error
310+ $ "takeBetween: the collecting fold terminated after"
311+ ++ " consuming" ++ show i1 ++ " elements"
312+ | otherwise = do
313+ res <- fstep s a
314+ case res of
315+ FL.Partial s' ->
316+ if i1 >= high
317+ then Done 0 <$> fextract s'
318+ else return $ Partial 0 $ Tuple' i1 s'
319+ FL.Done b -> return $ Done 0 b
320+
321+ where
322+
323+ i1 = i +1
324+
325+ extract (Tuple' i s)
326+ | i >= low && i <= high = fextract s
327+ | otherwise = throwM $ ParseError err
328+
329+ where
330+
331+ err =
332+ "takeBetween: Expecting alteast " ++ show low
333+ ++ " elements, got " ++ show i
334+
335+
336+
284-- | See 'Streamly.Internal.Data.Parser.takeEQ'.
337-- | See 'Streamly.Internal.Data.Parser.takeEQ'.
285--
338--
286-- /Internal/
339-- /Internal/