7

我正在寻找一个使用 monad 来抽象命令行参数解析和帮助生成的库。我有以下相当明显的使用模式:

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
  ...

上面的代码包含处理解析、验证和使用生成所需的所有信息,而且 IMO 相当容易理解。不幸的是,在查看了 hackage 并检查了 cmdargs、cmdlib、parseargs、ReadArgs 等软件包之后,我没有找到任何与此相关的东西。但在深入实施之前,我想确保我没有错过任何事情。那么是否有一个图书馆可以利用类似的方法来解决这个问题?

4

2 回答 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

这使您对可以使用的一些漂亮选项以及程序生成的漂亮输出有所了解。

于 2013-07-01T15:08:56.387 回答
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
于 2013-07-04T18:35:09.660 回答