Attribute parser for a constructor with two arguments

I want to write a parser for a pair of values ​​separated by commas in angle brackets. I got it to work with the following approach:

pair p1 p2 = do x1 <- p1 comma x2 <- p2 return (x1, x2) data Foo = Foo (Bar, Bar) foo :: Parser Foo foo = Foo <$> (angles $ pair bar bar) 

However, I would prefer the Foo constructor to use two parameters rather than a tuple:

 data Foo = Foo Bar Bar 

What is the best way to write such a parser? Ideally, I would like to use standard Parsec parsers like angles and use as much as possible.

+2
source share
1 answer

What is the best way to write such a parser? Ideally, I would like to use standard Parsec parsers at such angles and make the most of the applicative capabilities.

In an applicative style, your parser will

 foo = angles $ Foo <$> bar <* comma <*> bar 

Coming from the inside, a bar parsed, then comma discarded, and another bar discarded, then the Foo constructor is applied to two parses of bar s. Finally, everything is wrapped in an angles combinator, so the form string

 < bar , bar > 

parsed ( bar should probably consume trailing spaces).

The combination of parsers that ignore the result of one with the applicative combinators *> and <* eliminates the need for a pair combinator and easily generalizes constructors that take an arbitrary number of arguments.

Like CA McCann mentioned in the comment, the combinator (<$) (which is part of the Functor GHC implementation with the default implementation (<$) = fmap . const , but it is not part of the standard language) is also useful if you want to ignore the leading token. Using this, you can write

 Foo <$ ignoreMe <*> bar <* comma <*> baz 

which is better than using parentheses

 Foo <$> (ignoreMe *> bar) <* comma <*> baz 

or pure

 pure Foo <* ignoreMe <*> bar <* comma <*> baz 

as it would be necessary in some form without him.

+8
source

All Articles