If I have a parser like:
notZeroOrOne :: Parser Char
notZeroOrOne = noneOf ['0' , '1']
Is there a way I can combine the rules of another parser like digitChar so I can get a parser that will only pass if both parsers would pass?
Something like
biggerThanOne :: Parser Char
biggerThanOne = digitChar && notZeroOrOne
As user2407038 suggests in the comments, it's achievable using the lookAhead
function.
biggerThanOne :: Parser Char
biggerThanOne =
lookAhead digitChar *> notZeroOrOne
However, the parsers are sequential by nature, so it's both more efficient and comprehendable to apply the sequential logic. E.g., using the Monad
instance of Parser
:
biggerThanOne :: Parser Char
biggerThanOne =
do
c <- digitChar
if c /= '0' && c /= '1'
then return c
else unexpected "Not bigger than one"
Or MonadPlus
:
biggerThanOne :: Parser Char
biggerThanOne =
mfilter (\c -> c /= '0' && c /= '1') digitChar
which can be refactored to use the Ord
instance of Char
and pretty much clearly express your intent:
biggerThanOne :: Parser Char
biggerThanOne =
mfilter (> '1') digitChar
In the uu-parsinglib there is an amb combinator, which gives you all possible parses. You can use this to see whether you get both parses. If you get only a single parse you can use a monad to fail
p pAnd
q = amb (p <|> q) >>= \ r -> if length r == 2 then return ... else pFail
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With