7

是否可以使用optparse-applicative中的方法创建一个 haskell 表达式来解析这样的程序选项?

program [-a [-b]] ...

-a-b是可选标志(使用 实现switch),约束是-b选项只有在-a之前键入时才有效。

谢谢

4

2 回答 2

10

这是可能的,只需稍作调整,有两种不同的方式:

  1. -b您可以制作一个仅在您拥有时才允许的解析器-a,但您不能坚持认为-a首先出现,因为 optparse-applicative 的<*>组合器没有指定顺序。
  2. 您可以坚持该-b选项遵循该a选项,但是您通过a作为命令实现来做到这一点,因此您失去了-它前面的。

Applicative 绝对足够强大,因为不需要检查解析器返回的值来确定是否-b允许,所以>>=没有必要;如果任何输出-a成功,则允许。-b

例子

我将使用数据类型来表示存在哪些参数,但实际上这些会更有意义。

import Options.Applicative

data A = A (Maybe B)   deriving Show 
data B = B             deriving Show

所以我们程序的选项可能包含一个 A,它可能有一个 B,并且总是有一个字符串。

boption :: Parser (Maybe B)
boption = flag Nothing (Just B) (short 'b')

方式1:标准组合器 --b只能附带-a(任何顺序)

我将使用flag' () (short 'a')which 只是坚持-a存在,但随后使用*>而不是<*>忽略返回值(),只返回boption解析器返回的任何内容,并给出 options -a [-b]。然后我会标记它,A :: Maybe B -> A最后我会做整个事情optional,所以你有选择[-a [-b]]

aoption :: Parser (Maybe A)
aoption = optional $ A <$> (flag' () (short 'a' ) *> boption)

main = execParser (info (helper <*> aoption) 
                        (fullDesc <> progDesc "-b is only valid with -a")) 
        >>= print

请注意,由于<*>允许任何订单,我们可以放在-a后面-b(这不是您所要求的,但可以正常工作并且对某些应用程序有意义)。

ghci> :main -a 
Just (A Nothing)
ghci> :main -a -b
Just (A (Just B))
ghci> :main -b -a
Just (A (Just B))
ghci> :main -b
Usage: <interactive> [-a] [-b]
  -b is only valid with -a
*** Exception: ExitFailure 1

方式2:命令子解析器 --b只能跟随a

您可以command用来制作subparser仅在命令字符串存在时才有效的 a。cabal install您可以使用它来处理像 cabal 那样的参数,因此cabal update具有完全不同的选项。由于command需要一个ParserInfo参数,因此可以使用您可以提供的任何解析器execParser,因此您实际上可以任意深度嵌套命令。可悲的是,命令不能以 . 开头-,所以它会program [a [-b]] ...代替program [-a [-b]] ....

acommand :: Parser A
acommand = subparser $ command "a" (info (A <$> (helper <*> boption)) 
                                         (progDesc "you can '-b' if you like with 'a'"))

main = execParser (info (helper <*> optional acommand) fullDesc) >>= print

像这样运行:

ghci> :main 
Nothing
ghci> :main a 
Just (A Nothing)
ghci> :main a -b
Just (A (Just B))
ghci> :main -b a
Usage: <interactive> [COMMAND]
*** Exception: ExitFailure 1

所以你必须在前面-b加上a.

于 2014-08-10T22:09:54.090 回答
3

恐怕你不能。这恰恰是Applicative一个人无法处理的场景,而Monad可以:根据早期的结果改变后面的动作的结构。在应用计算中,总是需要事先知道“形状”;这有一些优点(比如加速 so 数组组合,或者为命令行选项提供一个很好的可读帮助屏幕),但在这里它限制您解析“平面”选项。

optparse-applicative 的接口也有Alternative,它确实允许依赖解析,尽管方式不同,如 AndrewC 所示。

于 2014-08-10T00:14:33.897 回答