2012-05-28 41 views
1

我想教自己的Haskell。作爲示例程序,我正在寫一個蜘蛛紙牌遊戲。使用getOpt解析Haskell的命令行參數

我想寫一個命令行解析器使用System.Console.GetOpt。我知道有更簡單的方法可以爲此程序進行參數解析,但我想了解如何使用GetOpt模塊,因爲我預計稍後將在其他將要編寫的程序中使用它的複雜性。

我想添加一個「 - 幫助」選項,只是打印一個用法消息,然後退出。如果「--games」選項或「--suits」選項的任一參數不是有效整數(遊戲> = 1和< = 1000,適合== 1,2,或4)。我將把所產生的Options數據類型傳遞給我的程序的其他部分。

我也遇到了一個錯誤,progName不在範圍內。是否case聲明parseArgsdo塊的範圍內?

這裏是我的代碼,從例子中拼湊在"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 
+5

範圍的事情是因爲where子句附加到'parseArgs',其中'progName'不在作用域中(它被綁定在do-block中)。如果你多縮進'where',它將附加到'case',並且'progName'在範圍內。 –

+0

(如果除「爲什麼會出現此錯誤」之外還有其他問題,則應明確說明該問題。) –

+0

謝謝。我縮進了'where'語句,直到它比第二個case('(_,_,errs)')多一個縮進級別並且它能夠工作,但是我認爲值'header'和'helpMessage'不會是在第一個案件條款的範圍內。我將它們移動到'do'塊的'let'值上,而不是'where'。 – Ralph

回答

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 

我該如何提高呢?