Haskell 如何使用optparse applicative创建嵌套/条件选项?
可以使用中的方法创建一个haskell表达式来解析如下程序选项吗Haskell 如何使用optparse applicative创建嵌套/条件选项?,haskell,applicative,optparse-applicative,Haskell,Applicative,Optparse Applicative,可以使用中的方法创建一个haskell表达式来解析如下程序选项吗 program [-a [-b]] ... -a和-b是可选标志(使用开关实现),限制条件是-b选项仅在之前键入-a时有效 谢谢,恐怕不行。这正是Applicative单独无法处理而Monad可以处理的场景:根据早期结果更改后续操作的结构。在应用计算中,“形状”总是需要事先知道;这有一些优点(比如加快so数组组合,或者为命令行选项提供一个可读性很好的帮助屏幕),但在这里它限制了您解析“平面”选项 optparse应用程序的界面也
program [-a [-b]] ...
-a和-b是可选标志(使用开关实现),限制条件是-b选项仅在之前键入-a时有效
谢谢,恐怕不行。这正是Applicative
单独无法处理而Monad
可以处理的场景:根据早期结果更改后续操作的结构。在应用计算中,“形状”总是需要事先知道;这有一些优点(比如加快so数组组合,或者为命令行选项提供一个可读性很好的帮助屏幕),但在这里它限制了您解析“平面”选项
optparse应用程序的界面也有备选方案
,它确实允许依赖解析,尽管是以AndrewC所示的不同方式。这是可能的,只需稍加调整,两种不同的方式:
如果你有-a
,你可以制作一个只允许-b
的解析器,但是你不能坚持-a
优先,因为optparse应用程序的
组合器没有指定顺序
您可以坚持让-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'()(短'a')
,它只是坚持-a
在那里,但是然后使用*>
而不是
忽略返回值()
,只返回选项解析器返回的任何内容,并提供选项-a[-b]
。然后我将用A::也许B->A
标记它,最后我将使整个成为可选的,这样您就有了选项[-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
方式2:命令子parser--b
只能跟在a
您可以使用command
生成一个子parser
,该子parser仅在存在命令字符串时有效。您可以像cabal那样使用它来处理参数,以便cabal安装
和cabal更新
具有完全不同的选项。由于command
接受一个ParserInfo
参数,因此可以使用您可以提供给execParser
的任何解析器,因此您实际上可以任意深度嵌套命令。遗憾的是,命令不能以-
开头,因此它将是程序[a[-b]]…
而不是程序[-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
acommand::解析器A
acommand=subparser$命令“a”(信息(a(助手选项))
(progDesc“如果你愿意,可以用'a'”))
main=execParser(信息(助手可选的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
ghci>:main
没有什么
ghci>:主a
只是(一无所获)
ghci>:主a-b
只是(A(只是B))
ghci>:主-b a
用法:[命令]
***例外:ExitFailure 1
所以你必须在-b
前面加a
你确定吗?我们事先知道这个结构,它只是嵌套的。你不能在a上使用命令
并使用子parser实现b吗?它是固定的,但不适用。您可以通过添加一个类型(如f Bool->(Bool->f r)->f r
)来包含一些静态分支行为,即一个类型约束(>>=)
。谢谢@leftaroundabout。对不起,@leftaroundabout,但我不能同意您的推理。Applicative对于这类事情来说足够强大,否则我们将无法使用Applicative接口来解析c,从而允许=仅出现在标识符之后。您不需要检查标识符的文本就知道=可以跟在它后面,因此不需要绑定。与此类似,您可以解析-a并返回(),(而不是字母a)。您不需要检查值()就知道现在允许使用-b,因此不需要绑定。问题纯粹是在这个上下文中,顺序是不确定的。@leftarounda关于我在第一个方法中使用完全标准的Applicative&Alternative组合符,就在非可选标志“(optional
来自Alternative)之上。我把“使用开关实现”理解为“当前使用开关实现”。我们能否同意“如果您坚持使用开关,恐怕不行”
?我担心的原因是,正如目前编写的那样,它意味着Applicative是一个非常弱的解析接口,而事实并非如此。
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