【问题标题】:Parsing command line arguments in Haskell using getOpt使用 getOpt 在 Haskell 中解析命令行参数
【发布时间】:2012-05-28 15:22:38
【问题描述】:

我正在尝试自学 Haskell。作为一个示例程序,我正在编写一个蜘蛛纸牌播放器。

我正在尝试使用System.Console.GetOpt 编写命令行解析器。我知道有更简单的方法可以对这个程序进行参数解析,但我想学习如何使用 GetOpt 模块,因为我预计稍后在我将要编写的其他程序中需要它的复杂性。

我正在尝试添加一个“--help”选项,它只打印一条使用消息然后退出。如果“--games”选项或“--suits”选项的任何一个参数不是有效整数(游戏> = 1和Options 数据类型传递给我程序的其他部分。

我还收到progName 不在范围内的错误。 parseArgs中的case语句不是在do块的范围内吗?

这是我的代码,由"Real World Haskell"Haskell wiki 中的示例拼凑而成:

module Main (main) where

import System.Console.GetOpt
import System.Environment(getArgs, getProgName)

data Options = Options {
    optGames :: Int
  , optSuits :: Int
  , optVerbose :: Bool
  } deriving Show

defaultOptions = Options {
    optGames  = 1
  , optSuits = 4
  , optVerbose = False
  }

options :: [OptDescr (Options -> Options)]
options =
  [ Option ['g'] ["games"]
      (ReqArg (\g opts -> opts { optGames = (read g) }) "GAMES")
      "number of games"
  , Option ['s'] ["suits"]
      (ReqArg (\s opts -> opts { optSuits = (read s) }) "SUITS")
      "number of suits"
  , Option ['v'] ["verbose"]
      (NoArg (\opts -> opts { optVerbose = True }))
      "verbose output"
  ]

parseArgs :: IO Options
parseArgs = do
  argv <- getArgs
  progName <- getProgName
  case getOpt RequireOrder options argv of
    (opts, [], []) -> return (foldl (flip id) defaultOptions opts)
    (_, _, errs) -> ioError (userError (concat errs ++ helpMessage))
  where
    header = "Usage: " ++ progName ++ " [OPTION...]"
    helpMessage = usageInfo header options

main :: IO ()
main = do
  options <- parseArgs
  putStrLn $ show options

【问题讨论】:

  • 作用域是因为where 子句附加到parseArgs,其中progName 不在作用域内(它绑定在do 块中)。如果您将where 缩进一点,它就会附加到case,并且progName 在范围内。
  • (如果有“为什么会出现这个错误”以外的问题,您应该明确说明该问题。)
  • 谢谢。我缩进了whereclause,直到它比第二种情况((_, _, errs))多一个缩进级别并且它起作用了,但是我假设值headerhelpMessage将不在第一种情况的范围内条款。我将它们向上移动到 do 块的 let 值,并删除了 where

标签: getopt haskell


【解决方案1】:

这是我想出的解决方案:

module Main (main) where

import Control.Monad
import Control.Monad.Error
import System.Console.GetOpt
import System.Environment(getArgs, getProgName)

data Options = Options {
    optGames :: Int
  , optSuits :: Int
  , optVerbose :: Bool
  } deriving Show

defaultOptions = Options {
    optGames  = 1
  , optSuits = 4
  , optVerbose = False
  }

options :: [OptDescr (Options -> Either String Options)]
options =
  [ Option ['g'] ["games"]
      (ReqArg (\g opts ->
        case reads g of
          [(games, "")] | games >= 1 && games <= 1000 -> Right opts { optGames = games }
          _ -> Left "--games must be a number between 1 and 1000"
        ) "GAMES")
      "number of games"
  , Option ['s'] ["suits"]
      (ReqArg (\s opts ->
        case reads s of
          [(suits, "")] | suits `elem` [1, 2, 4] -> Right opts { optSuits = suits }
          _ -> Left "--suits must be 1, 2, or 4"
        ) "SUITS")
      "number of suits"
  , Option ['v'] ["verbose"]
      (NoArg (\opts -> Right opts { optVerbose = True }))
      "verbose output"
  ]

parseArgs :: IO Options
parseArgs = do
  argv <- getArgs
  progName <- getProgName
  let header = "Usage: " ++ progName ++ " [OPTION...]"
  let helpMessage = usageInfo header options
  case getOpt RequireOrder options argv of
    (opts, [], []) ->
      case foldM (flip id) defaultOptions opts of
        Right opts -> return opts
        Left errorMessage -> ioError (userError (errorMessage ++ "\n" ++ helpMessage))
    (_, _, errs) -> ioError (userError (concat errs ++ helpMessage))

main :: IO ()
main = do
  options <- parseArgs
  putStrLn $ show options

我该如何改进?

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-01-26
    • 2013-03-06
    • 2021-07-26
    • 2023-03-07
    • 2015-03-23
    • 1970-01-01
    • 2021-11-05
    相关资源
    最近更新 更多