I'm trying to use the optparse-applicative library in an program which should perform a different action depending on the number of arguments.
For example, the argument parsing for a program which calculates perimeters:
module TestOpts where
import Options.Applicative
type Length = Double
data PerimeterCommand
= GeneralQuadranglePerimeter Length Length Length Length
| RectanglePerimeter Length Length
parsePerimeterCommand :: Parser PerimeterCommand
parsePerimeterCommand = parseQuadPerimeter <|> parseRectPerimeter
parseQuadPerimeter = GeneralQuadranglePerimeter <$>
parseLength "SIDE1" <*>
parseLength "SIDE2" <*>
parseLength "SIDE3" <*>
parseLength "SIDE4"
parseRectPerimeter = RectanglePerimeter <$>
parseLength "WIDTH" <*> parseLength "HEIGHT"
parseLength name = argument auto (metavar name)
Only the first argument to <|>
will ever successfully parse. I think some kind of argument backtracking is required, similar to Parsec's try
combinator.
Any ideas on how to parse alternative sets of arguments, when the first alternative may consume some arguments of the next alternative?
Please note: this answer was written by the optparse-applicative author, Paolo Capriotti.
You can't do this with optparse-applicative directly. The main feature
of optparse-applicative is that options can be parsed in any order. If
you want to work mainly with arguments (which are positional), you are
better off having two levels of parsers: use many argument
in
optparse-applicative, then pass the resulting array to a normal parser
(say using Parsec). If you only have positional arguments, then
optparse-applicative won't buy you very much, and you could just parse
the arguments manually with Parsec.