Let's say I want to match the strings "a" or "aa" followed by "ab". Let's just go ahead and write that the most trivially obviously correct way:
thing = (string "a" <|> string "aa") <> string "ab"
Woo! See how easy it is? ... except that's utterly broken in any parsec-derived library. They don't backtrack. There's nothing in the world you can do to make them backtrack. The only thing you can do is refactor the structure of the grammar to reflect the parser's limitations.Yes, this example is artificial, but that makes it easy to understand. The broader issue of which this is one example is that you cannot apply distributive laws in parsec or its derivatives.
(a <*> c) <|> (b <*> c)
Is not interchangeable with (a <|> b) <*> c
On the other hand, (a <*> b) <|> (a <*> c)
Is interchangeable with a <*> (b <|> c)
This might be good for efficiency, but it's not very good for making it pleasant to write parsers.