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

时间:2014-08-09 23:12:53

标签: haskell applicative optparse-applicative

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

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

-a -b 是可选项标记(使用switch实现),约束为 -b 选项只有在以前输入 -a 时才有效。

由于

2 个答案:

答案 0 :(得分:6)

这可以通过轻微的调整,以两种不同的方式实现:

  1. 如果你有-b,你可以创建一个仅允许-a的解析器,但是你不能坚持认为-a是第一个,因为optparse-applicative's {{ 1}} combinator没有指定订单。
  2. 您可以坚持<*>选项遵循-b选项,但是您可以通过将a作为命令来执行此操作,这样您就会失去a前面的-它。
  3. 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')坚持-a的{​​{1}},然后使用*>代替<*>来忽略返回值()和只返回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
    

    请注意,由于<*>允许任何订单,我们可以将-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:命令subparser - -b只能跟随a

    您可以使用command创建subparser,仅在命令字符串存在时才有效。您可以使用它来处理像cabal那样的参数,以便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
    

    运行方式如下:

    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

答案 1 :(得分:3)

我担心你不能。这恰恰是ApplicativeMonad可以处理时无法处理的情况:根据早期结果更改后续操作的结构。在一个应用计算中,&#34;形状&#34;总是需要事先知道;这有一些优点(比如加速这样的数组组合,或为命令行选项提供一个很好的可读帮助屏幕),但这里限制你解析&#34; flat&#34;选项。

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