我正在努力教自己Haskell。作为一个示例程序,我正在写一个Spider单人纸牌游戏。
我正在尝试使用System.Console.GetOpt
编写命令行解析器。我知道有更简单的方法为这个程序进行参数解析,但是我想学习如何使用GetOpt
模块,因为我预计稍后我将要编写的其他程序中需要它的复杂性。
我正在尝试添加一个“--help”选项,只打印一个用法消息,然后退出。如果“--games”选项或“--suits”选项的任何一个参数都不是有效整数(游戏> = 1和< = 1000,套装== 1,我还要打印使用消息) 2,或4)。我将生成的Options
数据类型传递给我的程序的其他部分。
我也收到progName
不在范围内的错误。 case
块范围内parseArgs
中的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
答案 0 :(得分:3)
以下是我提出的解决方案:
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
我该如何改善这个?