@@ -175,9 +175,6 @@
175175
176176module Streamly.Internal.Data.Parser.Type
177177 (
178− -- * Setup
179− -- $setup
180−
181178 -- * Types
182179 Initial (..)
183180 , Step (..)
@@ -441,6 +438,7 @@ newtype ParseError = ParseError String
441438instance Exception ParseError where
442439 displayException (ParseError err) = err
443440
441+-- | Map a function on the result i.e. on @b@ in @Parser a m b@.
444442instance Functor m => Functor (Parser a m) where
445443 {-# INLINE fmap #-}
446444 fmap f (Parser step1 initial1 extract) =
@@ -507,26 +505,30 @@ data SeqParseState sl f sr = SeqParseL !sl | SeqParseR !f !sr
507505-- 'Streamly.Data.Stream.append', it splits the streams using two parsers and
508506-- zips the results.
509507
510−-- | Sequential parser application.
508+-- | Sequential parser application. Apply two parsers sequentially to an input
509+-- stream. The first parser runs and processes the input, the remaining input
510+-- is then passed to the second parser. If both parsers succeed, their outputs
511+-- are combined using the supplied function. If either parser fails, the
512+-- operation fails.
511513--
512−-- Apply two parsers sequentially to an input stream. The first parser runs and
513−-- processes the input, the remaining input is then passed to the second
514−-- parser. If both parsers succeed, their outputs are combined using the
515−-- supplied function. If either parser fails, the operation fails.
514+-- This combinator delivers high performance by stream fusion but it comes with
515+-- some limitations. For those cases use the 'Applicative' instance of
516+-- 'Streamly.Data.ParserK.ParserK'.
516517--
517−-- This implementation is strict in the second argument, therefore, the
518−-- following will fail:
518+-- CAVEAT 1: NO RECURSION. This function is strict in both arguments. As a
519+-- result, if a parser is defined recursively using this, it may cause an
520+-- infintie loop. The following example checks the strictness:
519521--
520−-- >>> Stream.parse (Parser.splitWith const (Parser.satisfy (> 0)) undefined) $ Stream.fromList [1]
522+-- >>> p = Parser.splitWith const (Parser.satisfy (> 0)) undefined
523+-- >>> Stream.parse p $ Stream.fromList [1]
521524-- *** Exception: Prelude.undefined
522525-- ...
523526--
524−-- Although this implementation allows stream fusion, it has quadratic
525−-- complexity, making it suitable only for a small number of compositions.
526−-- As a thumb rule use it for less than 8 compositions, use ParserK otherwise.
527+-- CAVEAT 2: QUADRATIC TIME COMPLEXITY. Static composition is fast due to
528+-- stream fusion, but it works well only for limited (e.g. up to 8)
529+-- compositions, use "Streamly.Data.ParserK" for larger compositions.
527530--
528−-- Below are some common idioms that can be expressed using 'splitWith' and
529−-- other parser primitives:
531+-- Below are some common idioms that can be expressed using 'splitWith':
530532--
531533-- >>> span p f1 f2 = Parser.splitWith (,) (Parser.takeWhile p f1) (Parser.fromFold f2)
532534-- >>> spanBy eq f1 f2 = Parser.splitWith (,) (Parser.groupBy eq f1) (Parser.fromFold f2)
@@ -615,7 +617,12 @@ splitWith func (Parser stepL initialL extractL)
615617-- We can use the compiler to automatically annotate accumulators, terminating
616618-- folds, non-failing parsers and failing parsers.
617619
618−-- | Works correctly only if both the parsers are guaranteed to never fail.
620+-- | Better performance 'splitWith' for non-failing parsers.
621+--
622+-- Does not work correctly for parsers that can fail.
623+--
624+-- ALL THE CAVEATS IN 'splitWith' APPLY HERE AS WELL.
625+--
619626{-# INLINE noErrorUnsafeSplitWith #-}
620627noErrorUnsafeSplitWith :: Monad m
621628 => (a -> b -> c) -> Parser x m a -> Parser x m b -> Parser x m c
@@ -686,6 +693,8 @@ data SeqAState sl sr = SeqAL !sl | SeqAR !sr
686693-- second parser. The output of the parser is the output of the second parser.
687694-- The operation fails if any of the parsers fail.
688695--
696+-- ALL THE CAVEATS IN 'splitWith' APPLY HERE AS WELL.
697+--
689698-- This implementation is strict in the second argument, therefore, the
690699-- following will fail:
691700--
@@ -693,10 +702,6 @@ data SeqAState sl sr = SeqAL !sl | SeqAR !sr
693702-- *** Exception: Prelude.undefined
694703-- ...
695704--
696−-- Although this implementation allows stream fusion, it has quadratic
697−-- complexity, making it suitable only for a small number of compositions.
698−-- As a thumb rule use it for less than 8 compositions, use ParserK otherwise.
699−--
700705-- /Pre-release/
701706--
702707{-# INLINE split_ #-}
@@ -752,7 +757,12 @@ split_ (Parser stepL initialL extractL) (Parser stepR initialR extractR) =
752757 Partial _ _ -> error "split_: Partial"
753758 Continue n s -> return $ Continue n (SeqAL s)
754759
755−-- For backtracking folds
760+-- | Better performance 'split_' for non-failing parsers.
761+--
762+-- Does not work correctly for parsers that can fail.
763+--
764+-- ALL THE CAVEATS IN 'splitWith' APPLY HERE AS WELL.
765+--
756766{-# INLINE noErrorUnsafeSplit_ #-}
757767noErrorUnsafeSplit_ :: Monad m => Parser x m a -> Parser x m b -> Parser x m b
758768noErrorUnsafeSplit_
@@ -807,7 +817,11 @@ noErrorUnsafeSplit_
807817 Partial _ _ -> error "split_: Partial"
808818 Continue n s -> return $ Continue n (SeqAL s)
809819
810−-- | 'Applicative' form of 'splitWith'.
820+-- | READ THE CAVEATS in 'splitWith' before using this instance.
821+--
822+-- >>> pure = Parser.fromPure
823+-- >>> (<*>) = Parser.splitWith id
824+-- >>> (*>) = Parser.split_
811825instance Monad m => Applicative (Parser a m) where
812826 {-# INLINE pure #-}
813827 pure = fromPure
@@ -833,20 +847,26 @@ data AltParseState sl sr = AltParseL !Int !sl | AltParseR !sr
833847-- each subsequent alternative's input element has to go through, therefore, it
834848-- cannot scale to a large number of compositions
835849
836−-- | Sequential alternative. The input is first passed to the first parser, and
850+-- | Sequential alternative. The input is first passed to the first parser,
837851-- if it succeeds, the result is returned. However, if the first parser fails,
838−-- the parser driver backtracks and tries the same input on the second parser,
839−-- returning the result if it succeeds.
852+-- the parser driver backtracks and tries the same input on the second
853+-- (alternative) parser, returning the result if it succeeds.
854+--
855+-- This combinator delivers high performance by stream fusion but it comes with
856+-- some limitations. For those cases use the 'Alternative' instance of
857+-- 'Streamly.Data.ParserK.ParserK'.
840858--
841−-- Note: This implementation is not lazy in the second argument. The following
842−-- will fail:
859+-- CAVEAT 1: NO RECURSION. This function is strict in both arguments. As a
860+-- result, if a parser is defined recursively using this, it may cause an
861+-- infintie loop. The following example checks the strictness:
843862--
844−-- >> Stream.parse (Parser.satisfy (> 0) `Parser.alt` undefined) $ Stream.fromList [1..10]
863+-- >>> p = Parser.satisfy (> 0) `Parser.alt` undefined
864+-- >>> Stream.parse p $ Stream.fromList [1..10]
845865-- *** Exception: Prelude.undefined
846866--
847−-- Although this implementation allows stream fusion, it has quadratic
848−-- complexity, making it suitable only for a small number of compositions.
849−-- As a thumb rule use it for less than 8 compositions, use ParserK otherwise.
867+-- CAVEAT 2: QUADRATIC TIME COMPLEXITY. Static composition is fast due to
868+-- stream fusion, but it works well only for limited (e.g. up to 8)
869+-- compositions, use "Streamly.Data.ParserK" for larger compositions.
850870--
851871-- /Time Complexity:/ O(n^2) where n is the number of compositions.
852872--
@@ -1176,23 +1196,12 @@ dieM err = Parser undefined (IError <$> err) undefined
11761196-- Note: With the direct style parser type, the list in "some" and "many" is
11771197-- accumulated strictly, it cannot be consumed lazily.
11781198
1179−-- | Sequential alternative. The input is first passed to the first parser, and
1180−-- if it succeeds, the result is returned. However, if the first parser fails,
1181−-- the parser driver backtracks and tries the same input on the second parser,
1182−-- returning the result if it succeeds.
1183−--
1184−-- Note: The implementation of '<|>' is not lazy in the second
1185−-- argument. The following code will fail:
1186−--
1187−-- >>> Stream.parse (Parser.satisfy (> 0) <|> undefined) $ Stream.fromList [1..10]
1188−-- *** Exception: Prelude.undefined
1189−-- ...
1199+-- | READ THE CAVEATS in 'alt' before using this instance.
11901200--
1191−-- WARNING! this is not suitable for large scale use. As a thumb rule stream
1192−-- fusion works well for less than 8 compositions of this operation, otherwise
1193−-- consider using 'ParserK'. Do not use recursive parser implementations based
1194−-- on this Alternative instance.
1195−
1201+-- >>> empty = Parser.die "empty"
1202+-- >>> (<|>) = Parser.alt
1203+-- >>> many = flip Parser.many Fold.toList
1204+-- >>> some = flip Parser.some Fold.toList
11961205instance Monad m => Alternative (Parser a m) where
11971206 {-# INLINE empty #-}
11981207 empty = die "empty"
@@ -1211,8 +1220,13 @@ data ConcatParseState sl m a b =
12111220 ConcatParseL !sl
12121221 | forall s. ConcatParseR (s -> a -> m (Step s b)) s (s -> m (Step s b))
12131222
1223+-- XXX Does it fuse completely? Check and update, it cannot fuse the
1224+-- dynamically generated parser.
1225+
12141226-- | Map a 'Parser' returning function on the result of a 'Parser'.
12151227--
1228+-- ALL THE CAVEATS IN 'splitWith' APPLY HERE AS WELL.
1229+--
12161230-- /Pre-release/
12171231--
12181232{-# INLINE concatMap #-}
@@ -1282,6 +1296,12 @@ concatMap func (Parser stepL initialL extractL) = Parser step initial extract
12821296 Partial _ _ -> error "concatMap: extract Partial"
12831297 Continue n s -> return $ Continue n (ConcatParseL s)
12841298
1299+-- | Better performance 'concatMap' for non-failing parsers.
1300+--
1301+-- Does not work correctly for parsers that can fail.
1302+--
1303+-- ALL THE CAVEATS IN 'splitWith' APPLY HERE AS WELL.
1304+--
12851305{-# INLINE noErrorUnsafeConcatMap #-}
12861306noErrorUnsafeConcatMap :: Monad m =>
12871307 (b -> Parser a m c) -> Parser a m b -> Parser a m c
@@ -1354,11 +1374,9 @@ noErrorUnsafeConcatMap func (Parser stepL initialL extractL) =
13541374-- for small number of compositions but for a scalable implementation we need a
13551375-- CPS version.
13561376
1357−-- | See documentation of 'Streamly.Internal.Data.Parser.ParserK.Type.Parser'.
1377+-- | READ THE CAVEATS in 'concatMap' before using this instance.
13581378--
1359−-- Although this implementation allows stream fusion, it has quadratic
1360−-- complexity, making it suitable only for a small number of compositions. As a
1361−-- thumb rule use it for less than 8 compositions, use 'ParserK' otherwise.
1379+-- >>> (>>=) = flip Parser.concatMap
13621380--
13631381instance Monad m => Monad (Parser a m) where
13641382 {-# INLINE return #-}
@@ -1370,6 +1388,7 @@ instance Monad m => Monad (Parser a m) where
13701388 {-# INLINE (>>) #-}
13711389 (>>) = (*>)
13721390
1391+-- | >>> fail = Parser.die
13731392instance Monad m => Fail.MonadFail (Parser a m) where
13741393 {-# INLINE fail #-}
13751394 fail = die
@@ -1385,6 +1404,7 @@ instance Monad m => MonadPlus (Parser a m) where
13851404 mplus = alt
13861405-}
13871406
1407+-- | >>> liftIO = Parser.fromEffect . liftIO
13881408instance (MonadIO m) => MonadIO (Parser a m) where
13891409 {-# INLINE liftIO #-}
13901410 liftIO = fromEffect . liftIO