> it's a stretch to call parser combinator code in Haskell simple or legible
Parser combinators in Haskell are exactly simple and legible.
When you think of them as an embedded DSL, Haskell is just a well-suited medium because it allows for very clean syntax: Function application is whitespace, and currying and partial application allows for a high degree of composability simply with parentheses and value bindings.
They're simple and legible, if you just want to know what a combinator does, and you don't need to understand how they work underneath. And you could argue that you don't need to to make practical use of them, just like you don't need to understand how LINQ works in C# to use and value them.
The catch comes with the incomprehensible error messages that are a consequence of the DSL being embedded: Once you forget a partial application, or you put a parenthesis the wrong way, you'll not understand why or where it goes wrong. So no, they're not as easy to work with as they are simple and legible.