The parser
try p behaves like parser
p, except that
it pretends that it hasn't consumed any input when an error occurs.
This combinator is used whenever arbitrary look ahead is needed. Since
it pretends that it hasn't consumed any input when
p fails,
the (
<|>) combinator will try its second alternative even
when the first parser failed while consuming input.
The
try combinator can for example be used to distinguish
identifiers and reserved words. Both reserved words and identifiers
are a sequence of letters. Whenever we expect a certain reserved word
where we can also expect an identifier we have to use the
try
combinator. Suppose we write:
expr = letExpr <|> identifier <?> "expression"
letExpr = do{ string "let"; ... }
identifier = many1 letter
If the user writes "lexical", the parser fails with:
unexpected
'x', expecting 't' in "let". Indeed, since the (
<|>)
combinator only tries alternatives when the first alternative hasn't
consumed input, the
identifier parser is never tried (because
the prefix "le" of the
string "let" parser is already
consumed). The right behaviour can be obtained by adding the
try combinator:
expr = letExpr <|> identifier <?> "expression"
letExpr = do{ try (string "let"); ... }
identifier = many1 letter