Why doesn't Parsec backtrack when one part of the parser succeeds and the rest fails?

假如想象 提交于 2020-01-04 13:11:31

问题


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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!