命令行参数读取Monad库

7
我正在寻找一个库,它使用单子来抽象出命令行参数解析和帮助生成的繁琐过程。我已经想好了以下相当明显的用法模式:
main = do
  portOrSocket <- Args.run $ do
    mbSocket <- Args.read $ Args.Arg "s" "socket" "Description"
    mbPort <- Args.read $ Args.Arg "p" "port" "Description"
    case mbSocket of
      Just socket -> return $ Right socket
      Nothing -> case mbPort of
        Just port -> return $ Left port
        Nothing -> return $ Left defaultPort
  ...

以上代码包含了处理解析、验证和生成用法所需的所有信息,我认为相当容易理解。不幸的是,在研究 Hackage 并查看类似 cmdargs、cmdlib、parseargs 和 ReadArgs 等软件包之后,我发现没有任何一个与此相近的东西。但在开始实现之前,我想确保自己没有漏掉什么。因此,是否有类似于此问题的解决方案库?


8
你尝试过使用 optparse-applicative 吗? - Gabriella Gonzalez
4
optparse-applicative 给予 +1。它非常棒。 - jtobin
1
如果参数依赖于其他参数的值,似乎几乎不可能生成自动帮助消息。这可能是为什么 optparse-applicative 使用 Applicative 的原因。 - Petr
@PetrPudlák 是的。在实际尝试实现之后,我得出了同样的结论。看起来需要一个Arrow,而 optparse-applicative 似乎已经有了。 - Nikita Volkov
1
@GabrielGonzalez 谢谢!看起来这是唯一的候选方案。您介意发布它作为答案,展示您如何使用该库解决所提出的问题吗? - Nikita Volkov
2个回答

8
您可以使用optparse-applicative。最常见的使用模式如下(我只是从一个我使用的小实用程序中复制和粘贴):
options :: Parser (String, String)
options = (,)
    <$> (strOption $ mconcat [
        short 'n',
        long "node",
        metavar "NODE",
        value "127.0.0.1",
        showDefaultWith id,
        completer (bashCompleter "hostname"),
        help "AMQP node to connect to" ] )
    <*> (strOption $ mconcat [
        short 'q',
        long "queue",
        metavar "QUEUE",
        value "1.0.0",
        showDefaultWith id,
        help "Queue to initialize" ] )

main = do
    (hostName, queue) <-
        execParser $ info (helper <*> options) $ mconcat [
            fullDesc,
            header "The Suns setup utility",
            progDesc "Sets up an AMQP node",
            footer "Report bugs to Gabriel439@gmail.com" ]
    ...

当我使用-h运行编译后的程序时,会得到以下结果:

$ suns-admin -h
The Suns setup utility

Usage: suns-admin [-n|--node NODE] [-q|--queue QUEUE]
  Sets up an AMQP node

Available options:
  -h,--help                Show this help text
  -n,--node NODE           AMQP node to connect to (default: 127.0.0.1)
  -q,--queue QUEUE         Queue to initialize (default: 1.0.0)

Report bugs to Gabriel439@gmail.com

这让你了解到一些你可以使用的巧妙选项和程序生成的漂亮输出。

2

如果有人对使用optparse-applicative解决问题感兴趣,下面是我实现的方法:

import Options.Applicative

getOptions :: Int -> IO (Either Int String)
getOptions defaultPort = 
  execParser $ 
  info (helper <*> parser defaultPort) $
    fullDesc <>
    progDesc "Run a content-db server on a socket or a port" <>
    header "Run a content-db server" 

parser :: Int -> Parser (Either Int String)
parser defaultPort = 
  portOrSocket <$> 
    (optional . strOption)
      ( short 's' <>
        long "socket" <>
        help "Socket" )
    <*>
    option
      ( short 'p' <>
        long "port" <>
        help "Port" <>
        value defaultPort )
  where
    portOrSocket (Just socket) _ = Right socket
    portOrSocket _ port = Left port

main = do
  getOptions 43400 >>= \o -> case o of
    Left port -> print port
    Right socket -> print socket

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接