See the general notes about parsing in the Streamly.Data.Parser module.
This (ParserK) module implements a Continuation Passing Style (CPS) wrapper
over the fused Streamly.Data.Parser module. It is a faster CPS parser than
attoparsec.
The ParserK type represents a stream-consumer as a composition of function
calls, therefore, a function call overhead is incurred at each composition.
It is reasonably fast in general but may be a few times slower than the
fused Streamly.Data.Parser.Parser type. However, unlike fused parsers, it
allows for scalable dynamic composition, especially, ParserK can be used
in recursive calls. Operations like splitWith on ParserK type have
linear (O(n)) performance with respect to the number of compositions.
ParserK is preferred over the fused Streamly.Data.Parser.Parser when
extensive applicative, alternative and monadic composition is required, or
when recursive or dynamic composition of parsers is required. ParserK also
allows efficient parsing of a stream of byte arrays, it can also break the
input stream into a parse result and the remaining stream so that the stream
can be parsed independently in segments.
How to parse a stream?
All the fused parsers from the Streamly.Data.Parser module can be
converted to the CPS ParserK, for use with different types of parser
drivers, using
the toParserK combinators -
Streamly.Data.Array.Streamly.Data.Array.toParserK,
Streamly.Data.StreamK.Streamly.Data.StreamK.toParserK, and
Streamly.Data.Array.Generic.Streamly.Data.Array.Generic.toParserK
To parse a stream of unboxed arrays, use
Streamly.Data.Array.Streamly.Data.Array.parse for running the parser, this
is the preferred and most efficient way to parse chunked input. The
Streamly.Data.Array.Streamly.Data.Array.parseBreak function returns the
remaining stream as well along with the parse result.
To parse a stream of boxed arrays, use
Streamly.Data.Array.Generic.Streamly.Data.Array.Generic.parse or
Streamly.Data.Array.Generic.Streamly.Data.Array.Generic.parseBreak to run
the parser.
To parse a stream of individual elements, use
Streamly.Data.StreamK.Streamly.Data.StreamK.parse and
Streamly.Data.StreamK.Streamly.Data.StreamK.parseBreak to run the parser.
Applicative Composition
Applicative parsers are simpler but we cannot use lookbehind as we can in
the monadic parsers.
If we have to parse "9a" or "a9" but not "99" or "aa" we can use the
following Applicative, backtracking parser:
Monad composition can be used to implement lookbehind parsers, we can dynamically
compose new parsers based on the results of the previously parsed values.
In the previous example, we know that if the first parse resulted in a digit
at the first place then the second parse is going to fail. However, we
waste that information and parse the first character again in the second
parse only to know that it is not an alphabetic char. By using lookbehind
in a Monad composition we can make dynamic decisions based on previously
parsed information and avoid redundant work:
Example1 expression
>>> data DigitOrAlpha = Digit Char | Alpha Char
Example1 expression
>>> :{lookbehind :: Monad m => ParserK Char m Stringlookbehind = do x1 <- StreamK.toParserK $ Digit <$> Parser.satisfy isDigit <|> Alpha <$> Parser.satisfy isAlpha -- Note: the parse depends on what we parsed already x2 <- StreamK.toParserK $ case x1 of Digit _ -> Parser.satisfy isAlpha Alpha _ -> Parser.satisfy isDigit return $ case x1 of Digit x -> [x,x2] Alpha x -> [x,x2]:}
Monadm => Monad (ParserKam)Defined in streamly-core-0.3.1 · Streamly.Internal.Data.ParserK.Type
Monad composition can be used for lookbehind parsers, we can dynamically
compose new parsers based on the results of the previously parsed values.
Functorm => Functor (ParserKam)Defined in streamly-core-0.3.1 · Streamly.Internal.Data.ParserK.Type
Map a function on the result i.e. on b in Parser a m b.
Monadm => MonadFail (ParserKam)Defined in streamly-core-0.3.1 · Streamly.Internal.Data.ParserK.Type
Monadm => Applicative (ParserKam)Defined in streamly-core-0.3.1 · Streamly.Internal.Data.ParserK.Type
f <$> p1 <*> p2 applies parsers p1 and p2 sequentially to an input
stream. The first parser runs and processes the input, the remaining input
is then passed to the second parser. If both parsers succeed, their outputs
are applied to the function f. If either parser fails, the operation
fails.
Monadm => Alternative (ParserKam)Defined in streamly-core-0.3.1 · Streamly.Internal.Data.ParserK.Type
p1 <|> p2 passes the input to parser p1, if it succeeds, the result is
returned. However, if p1 fails, the parser driver backtracks and tries the
same input on the alternative parser p2, returning the result if it
succeeds.
Monadm => MonadPlus (ParserKam)Defined in streamly-core-0.3.1 · Streamly.Internal.Data.ParserK.Type
mzero is same as empty, it aborts the parser. mplus is same as
<|>, it selects the first succeeding parser.
MonadIOm => MonadIO (ParserKam)Defined in streamly-core-0.3.1 · Streamly.Internal.Data.ParserK.Type