0

假设我有以下递归定义的 ADT

data GraphType = Character | Colour | Nested GraphType deriving (Show)

我可以递归地为这个结构定义一个解析器(使用optparse-applicative,导入为OA),如下所示:

typeParser :: OA.Parser GraphType
typeParser =
  OA.flag' Colour (OA.long "colour")
    <|> OA.flag' Character (OA.long "character")
    <|> (OA.flag' Nested (OA.long "nested") <*> typeParser)

这让我可以传递参数,例如

  • --colour得到一个值Colour
  • --nested --colour得到一个值Nested Colour
  • --nested --colour得到一个值Nested (Nested Colour)
  • 等等

不幸的是,如果我尝试为解析器生成帮助文本,它会失败。这在一定程度上是有道理的,因为解析器的“结构”是无限大的。但是,我很乐观地认为可能会有某种解决方法,例如转换内部typeParser,这样我们就不会尝试为它生成帮助文本。

可以对该 Parser 进行的最小修改以使其保留工作帮助文本?


除了无法生成帮助文本之外,如果我想将解析器修改为以下内容(添加默认值,但也允许--nested自己解析为Nested Character),这也会挂起,而不是达到默认值:

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

通过将解析器更改为以下内容,我已经能够解决该问题

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

要在此解析器中指定 的值Nested (Nested Colour),您需要传递--nest 2 --colour. 这可行,但并不理想,因为我真的很喜欢“多--nesting参数”命令风格。

4

1 回答 1

0

可以使用 修改问题中的最后一个解析器,以获得“多个--nesting”样式,many如下所示:

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 = length <$> (many $ OA.flag' () (OA.long "nested"))
    unnestedParser =
      OA.flag' Colour (OA.long "colour")
        <|> OA.flag' Character (OA.long "character")
        <|> pure Character

nestDepthParser输出一个[()]长度等于--nested参数数量的列表 ( ),然后可以使用它来应用Nested正确的次数。

这有效(与原始代码不同),因为 optparse-applicative 有一个专门的实现many,它不会挂起。

于 2021-08-10T18:05:03.933 回答