问题
I have this parsec parser :
a = optionMaybe $ do {try $ spaceornull *> string "hello";string "No"}
Where spaceornull
is ((:[]) <$> try space) <|> string ""
When I test a with input " " I get :
Left (line 1, column 2):
unexpected end of input
expecting "hello"
I don't understand this, spaceornull *> string "hello"
should fail because there is no "hello", then with try
parsec backtracks and now there is no consumed input but try
fails anyway so the parser passed to optionMaybe
(the one inside do
) fails altogether, it shouldn't try to consume farther input, so we end up with a failed parser without consuming any input so I should get Right Nothing
.
But the error message says it, the space is consumed so try
didn't really backtrack, does try
not backtrack when part of parser succeeds ? and how to make it backtrack with the above ?
回答1:
try
has nothing to do with whether failure is allowed or not. It merely makes it possible to backtrack in case of failure†, but to commence the backtracking you need to provide an alternative parser to start at that point. The usual way to do that is with the <|> operator:
a = optionMaybe $ (try $ spaceornull *> string "hello") <|> string "No"
OTOH, your code is equivalent to
a = optionMaybe $ (try $ spaceornull *> string "hello") >> string "No"
where the monadic chaining operator >> (same as *>) will in the case of parsec check if the LHS succeeds, then go on and also run the RHS parser. So it must be, because you could also write:
a = optionMaybe $ do
s <- try $ spaceornull *> string "hello"
string $ "No"++s
Here I've used the result of the first parser (which you simply threw away, by not <-
-matching it to any variable) in deciding what the second one should look for. This clearly is only possible of the first actually succeeded!
†Basically, <|>
only works if either the LHS immediately fails right at the first character, or if you set a backtracking point with try
. The reason this is required is that it would be very inefficient if parsec would need to leave a backtracking point before each and every alternative that needs to be ckecked.
来源:https://stackoverflow.com/questions/39057940/why-doesnt-parsec-backtrack-when-one-part-of-the-parser-succeeds-and-the-rest-f