Supposing I have the following recursively defined ADT
data GraphType = Character | Colour | Nested GraphType deriving (Show)
I can define an Parser for this structure (using optparse-applicative, imported as OA), recursively, as follows:
typeParser :: OA.Parser GraphType
typeParser =
OA.flag' Colour (OA.long "colour")
<|> OA.flag' Character (OA.long "character")
<|> (OA.flag' Nested (OA.long "nested") <*> typeParser)
This lets me pass arguments such as
--colourto get a value ofColour--nested --colourto get a value ofNested Colour--nested --colourto get a value ofNested (Nested Colour)- and so on
Unfortunately, if I try to generate help text for ths parser, it fails.
This makes a degree of sense, because the "structure" of the parser is infinitely large.
However, I'm optimistic that there might be a some kind of work around for this, for instance transforming the inner typeParser so that we don't try to generate help text for it.
What's the smallest modification that can be made to this Parser to leave it with working help text?
In addition to not being able to generate help text, if I wanted to modify the parser to the following (to add a default, but also allow --nested by itself to parse as Nested Character), this will also hang, as opposed to reaching the default:
typeParser :: OA.Parser GraphType
typeParser =
OA.flag' Colour (OA.long "colour")
<|> OA.flag' Character (OA.long "character")
<|> (OA.flag' Nested (OA.long "nested") <*> typeParser)
<|> pure Character
I've already been able to work around the problem, by changing the Parser to the following
typeParser :: OA.Parser GraphType
typeParser = iter Nested <$> nestDepthParser <*> unnestedParser
where
iter f 0 v = v
iter f n v = iter f (n - 1) (f v)
nestDepthParser = OA.option OA.auto (OA.long "nest") <|> pure 0
unnestedParser =
OA.flag' Colour (OA.long "colour")
<|> OA.flag' Character (OA.long "character")
<|> pure Character
To specify a value of Nested (Nested Colour) in this parser, you'd pass --nest 2 --colour.
This works, but it's not ideal, as I really like the "multiple --nesting arguments" style of command.
It's possible to modify the last parser in the question, to get the "multiple
--nesting" style, usingmany, as follows:nestDepthParseroutputs a list ([()]) with a length equal to the number of--nestedarguments, which can then be used to applyNestedthe correct number of times.This works (unlike the original code) because optparse-applicative has a specialized implementation of
many, which doesn't hang.