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.