What is the best way to write such a parser? Ideally I would like to reuse standard Parsec parsers such a angles and use applicative as much as possible.
In applicative style, your parser would be
foo = angles $ Foo <$> bar <* comma <*> bar
Going inside out, a bar
is parsed, then a comma
, which is discarded, and another bar
, then the constructor Foo
is applied to the two parsed bar
s. Finally, all is wrapped into the angles
combinator, so that a string of the form
< bar , bar >
is parsed (bar
should probably consume trailing whitespace).
Combining parsers ignoring the result of one with the *>
and <*
applicative combinators eliminates the need for the pair
combinator and easily generalises to constructors taking an arbitrary number of arguments.
As C.A. McCann mentioned in a comment, the (<$)
combinator (which is part of GHC's implementation of the Functor
class, with the default implementation (<$) = fmap . const
; but it's not part of the language standard) is useful too, if you want to ignore a leading token. Using that, you can write
Foo <$ ignoreMe <*> bar <* comma <*> baz
which is nicer than using parentheses
Foo <$> (ignoreMe *> bar) <* comma <*> baz
or pure
,
pure Foo <* ignoreMe <*> bar <* comma <*> baz
as would be required in some form without it.