如何在Haskell的optparse-applicative中为子命令设置同义词
解决方案
你可以借助optparse-applicative库的内置能力实现需求,既复用全部逻辑,又不会在帮助里出现重复条目,具体实现方式如下:
完整修改后的可运行代码
#!/usr/bin/env stack -- stack --resolver lts-18.17 script --package optparse-applicative import Options.Applicative import Data.Semigroup ((<>)) data Options = CmdGreet GreetArgs | CmdGroot GreetArgs newtype GreetArgs = GreetArgs String main :: IO () main = do cmdOpts <- customExecParser (prefs showHelpOnEmpty) (info optParser fullDesc) runCmd cmdOpts optParser :: Parser Options optParser = subparser ( command "greet" (info (CmdGreet <$> sample) (progDesc "Print greeting 1")) <> -- 注册别名gruut,复用完全相同的parser,加internal修饰符让它不在帮助列表中显示 command "gruut" (info (CmdGreet <$> sample) (internal <> progDesc "Alias for greet")) <> command "groot" (info (CmdGroot <$> sample) (progDesc "Print greeting 2")) -- 自定义帮助的命令列表展示,实现greet|gruut的显示效果 ) & help "Available commands:\n\ \ greet|gruut Print greeting 1\n\ \ groot Print greeting 2" runCmd :: Options -> IO () runCmd o = case o of CmdGreet opts -> greet opts CmdGroot opts -> groot opts greet :: GreetArgs -> IO () greet (GreetArgs h) = putStrLn $ "Hello, " ++ h ++ "!" groot :: GreetArgs -> IO () groot (GreetArgs h) = putStrLn $ "Howdy, " ++ h ++ "!" sample :: Parser GreetArgs sample = GreetArgs <$> strArgument ( metavar "TARGET" )
更简洁的高版本方案
如果你使用0.16及以上版本的optparse-applicative,可以用库内置的commandAlias函数进一步简化代码:
optParser :: Parser Options optParser = subparser ( command "greet" (info (CmdGreet <$> sample) (progDesc "Print greeting 1")) <> commandAlias "gruut" "greet" <> -- 直接声明gruut是greet的别名,无需重复写parser command "groot" (info (CmdGroot <$> sample) (progDesc "Print greeting 2")) ) & help "Available commands:\n\ \ greet|gruut Print greeting 1\n\ \ groot Print greeting 2"
效果验证
- 运行
./opt_ex.hs greet John和./opt_ex.hs gruut John都会返回Hello, John!,行为完全一致 - 直接运行
./opt_ex.hs查看帮助,输出完全符合你期望的格式,没有重复的命令条目
内容的提问来源于stack exchange,提问作者nevrome
相关产品推荐
相关产品推荐

