det-parse is a library of deterministic parser combinators. It is
based on the material presented in Frank Huch’s functional programming
lecture at Kiel University. To use it, you build a Parser a
using the provided combinators and then apply it to a string using
parse
. The simplest parsers are provided by the primitives
yield
, failure
, anyChar
and
check
.
yield
always results in the given value, consuming no
input. yield 1
will successfully parse the empty string to
the value 1
. failure
is a parser that always
fails. anyChar
is a parser that consumes a single character
and uses it as the parse result. check
takes a parser and a
predicate on the result type of the parser. From these, it builds a new
parser that applies the existing parser and succeeds only if the
predicate holds for the parse result.
char
and word
build parsers for single
characters and whole strings from these primitives.
char 'c'
is a parser that consumes the single character
c
and results in the unit value ()
.
word "hello"
consumes the string hello
and
results in the unit value. empty
is a parser that
recognizes an empty string and results in the unit value.
The operators *>
and <*
are provided
to combine parsers into more comples ones. *>
applies
two parsers and returns the result of the second one if both were
successful. char 'a' *> yield 1
is successful if applied
to the string a
and results in the value 1
.
<*
applies two parsers in the same order, i.e. left to
right, but returns the result of the first one.
<|>
combines two parsers by applying them both. If
the first one is successful, it returns its result. If it is not, but
the second one is, then it returns the result of the second one. If both
are unsuccessful, the combined parser is unsuccessful as well. The
parser
char 'a' *> yield 1 <|> char 'b' *> yield 2
parses the string a
to the value 1
and the
string b
to the value 2
.
<!>
works similarly to <|>
, but
does not backtrack. That is, it only tries the second parser if the
first one was unsuccessful, and only on the remaining input. It can be
used if the alternatives do not overlap. The above example would also
work if <|>
were replaced by <!>
,
while
word "ab" *> yield 1 <!> word "abc" *> yield 2
would fail to parse abc
into the value 2
since
the first alternative has already consumed ab
.
<$>
builds a new parser from an existing parser by
applying a function to the result of that parser. For example,
(+ 1) <$> (char 'a' *> yield 1)
is a parser that
parses the string a
into the value 2
.
<*> :: Parser (a -> b) -> Parser a -> Parser b
combines two parsers, one that results in a function from a
to b
, and one that results in an a
value. It
applies the parsers in order and then applies the function result of the
first parser to the value result of the second parser.
many :: Parser a -> Parser [a]
builds a parser that
parses whatever the original parser parses arbitrarily many times.
some
is similar, but requires that the original parser
succeed at least once. Applying
many (char 'a' *> yield 1)
to the string
aaaa
results in the value [1,1,1,1]
.