如何使用optparse-applicative创建嵌套/条件选项?

The*_*ten 4 haskell applicative optparse-applicative

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

program [-a [-b]] ...
Run Code Online (Sandbox Code Playgroud)

-a-b是选项标志(使用实现switch),约束条件是-b选项仅在以前键入-a时有效.

谢谢

And*_*ewC 6

通过轻微的调整,这有两种不同的方式:

  1. 你可以做一个解析器,只允许-b如果你有-a,但你不能再坚持的是-a至上的,因为optparse,应用性的<*>组合子不指定顺序.
  2. 您可以坚持-b选项后面的a选项,但是您可以通过实现a命令来实现,因此您将失去它-的前面.

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

例子

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

import Options.Applicative

data A = A (Maybe B)   deriving Show 
data B = B             deriving Show
Run Code Online (Sandbox Code Playgroud)

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

boption :: Parser (Maybe B)
boption = flag Nothing (Just B) (short 'b')
Run Code Online (Sandbox Code Playgroud)

方式1:标准组合器 - -b只能带-a(任何订单)

我将使用flag' () (short 'a')它只是坚持-a存在,但然后使用*>而不是<*>忽略返回值(),只返回boption解析器返回的任何内容,给出选项-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
Run Code Online (Sandbox Code Playgroud)

请注意,既然<*>允许任何订单,我们可以放在-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
Run Code Online (Sandbox Code Playgroud)

方式2:命令subparser - -b只能跟随a

您可以使用command一个subparser仅在命令字符串存在时有效的.您可以使用它像阴谋做处理参数,因此cabal installcabal 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
Run Code Online (Sandbox Code Playgroud)

哪个运行如下:

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
Run Code Online (Sandbox Code Playgroud)

所以,你必须先-ba.