This more of a style question, rather than a how to.
So I\'ve got a program that needs two command line arguments: a string and an integer.
I implemented it this
I suggest using a case
expression:
main :: IO ()
main = do
args <- getArgs
case args of
[aString, aInteger] | [(n,_)] <- reads aInteger ->
doStuffWith aString n
_ -> do
name <- getProgName
hPutStrLn stderr $ "usage: " ++ name ++ " "
exitFailure
The binding in a guard used here is a pattern guard, a new feature added in Haskell 2010 (and a commonly-used GHC extension before that).
Using reads
like this is perfectly acceptable; it's basically the only way to recover properly from invalid reads, at least until we get readMaybe
or something of its ilk in the standard library (there have been proposals to do it over the years, but they've fallen prey to bikeshedding). Using lazy pattern matching and conditionals to emulate a case
expression is less acceptable :)
Another possible alternative, using the view patterns extension, is
case args of
[aString, reads -> [(n,_)]] ->
doStuffWith aString n
_ -> ...
This avoids the one-use aInteger
binding, and keeps the "parsing logic" close to the structure of the argument list. However, it's not standard Haskell (although the extension is by no means controversial).
For more complex argument handling, you might want to look into a specialised module — System.Console.GetOpt is in the standard base
library, but only handles options (not argument parsing), while cmdlib and cmdargs are more "full-stack" solutions (although I caution you to avoid the "Implicit" mode of cmdargs, as it's a gross impure hack to make the syntax a bit nicer; the "Explicit" mode should be just fine, however).