Read carefully:
[Selection statement] tries to execute the first parser, and then, if it does not work, tries the second. If either succeeds, the value returned by this parser is also returned.
This means that the first parser is executed first, and if it succeeds, the second parser will NOT be checked at all! This means that the first parser has a higher priority, so <|> is generally not commutative.
A simple counterexample can be created using some sequentially executed parsers, for example
dummy :: Parser Bool dummy = return True <|> return False
The above is equivalent to return True : since the first is successful, the second is immaterial.
In addition, parsec is designed to be committed at an early stage in the first branch when it successfully used some input. This design sacrifices ideal non-determinism for efficiency. Otherwise, parsec often needs to store in memory the entire file that is being processed, because if a parsing error occurs, you must try a new alternative.
For instance,
p = (char 'a' >> char 'b' >> ...) <|> (char 'a' >> char 'c' >> ...)
won't work as you would expect. As soon as 'a' successfully used by the first branch, parsec fixes it. This means that if 'c' follows, then the first branch will fail, but it's too late for the second to be judged. The entire parser just fails.
To solve this problem, you can drop the common prefix, for example
p = char 'a' >> ( (char 'b' >> ...) <|> (char 'c' >> ...) )
or resort to try ,
p = (try (char 'a' >> char 'b') >> ...) <|> (char 'a' >> char 'c' >> ...)
try basically tells parsec not to commit the branch until the entire parser in try succeeds. If this is an abuse, it may cause parsec to store most of the file in memory, but the user at least has some control over it. Theoretically, ideal non-determinism can be restored by always adding try to the entire left branch <|> . This, however, is not recommended because it forces the programmer to write an inefficient parser, both because of a memory problem and because it is easy to write a grammar that requires an exponential number of return paths for successful analysis.