Reputation: 375
I am working on a homework manager for personal use, developing it with Haskell. I have, as a start, made the following code for parsing the commandline arguments, code which i should be easily extandable later through adding to dispatch
. The functions themselves are dummies for testing purposes. I do, however, feel that this code can be made simpler, and more failsafe, though i cannot see how. The code is this:
module Main where
import System.Environment
main = getArgs >>= parse
parse :: [String] -> IO ()
parse [] = usage
parse (file:mode:[]) = if mode == "list"
then list file
else case lookup mode dispatch of
Just _ -> putStrLn "That mode requires arguments" >> usage
Nothing -> putStrLn "Please supply a valid mode" >> usage
parse (file:mode:args) = case lookup mode dispatch of
Nothing -> do case lookup file dispatch of
Just _ -> putStrLn "Please supply a data file"
Nothing -> putStrLn "Please supply a valid mode"
usage
Just fun -> fun file args
parse (file:[]) = case lookup file dispatch of
Just _ -> putStrLn "Please supply a datafile" >> usage
Nothing -> list file
usage :: IO ()
usage = mapM_ putStrLn helptext
helptext :: [String]
helptext = ["Homework manager by Marcus Medom Ryding <[email protected]>"
,"Copyright 2013, licensed under BSD3"
,"Usage: homework filepath [mode] [arguments]"]
dispatch :: [(String, String -> [String] -> IO ())]
dispatch = [("new",new)]
new :: String -> [String] -> IO ()
new file args = putStrLn ("NEW: " ++ file) >> mapM_ putStrLn args
list :: String -> IO ()
list file = putStrLn ("LIST: " ++ file)
Upvotes: 0
Views: 237
Reputation: 7155
In addition to the above answer, just based on your code:
module Main where
import System.Environment
main∷ IO ()
main = getArgs »= parse2
parse2 ∷ [String] → IO ()
parse2 [] = usage
parse2 (file:mode:[])
| mode ≡ "list" = list file
| mode ≠ "list" =
case lookup mode dispatch of
Just _ → putStrLn "That mode requires arguments" » usage
Nothing → putStrLn "Please supply a valid mode" » usage
parse2 (file:mode:args) =
case lookup mode dispatch of
Nothing → err (lookup file dispatch) » usage
Just fun → fun file args
where err (Just _) = putStrLn "Please supply a data file"
err Nothing = putStrLn "Please supply a valid mode"
parse2 (file:[]) =
case lookup file dispatch of
Just _ → putStrLn "Please supply a datafile" » usage
Nothing → list file
usage ∷ IO ()
usage = mapM_ putStrLn helptext
helptext ∷ [String]
helptext = ["Homework manager by Marcus Medom Ryding <[email protected]>"
,"Copyright 2013, licensed under BSD3"
,"Usage: homework filepath [mode] [arguments]"]
dispatch ∷ [(String, String → [String] → IO ())]
dispatch = [("new",new)]
new ∷ String → [String] → IO ()
new file args = putStrLn ("NEW: " ⧺ file) » mapM_ putStrLn args
list ∷ String → IO ()
list file = putStrLn ("LIST: " ⧺ file)
Upvotes: 1
Reputation: 15335
Rather than parsing the command line manually, you should use a library. Have a look at cmdargs.
It lets you define command line options in a declarative fashion:
{-# LANGUAGE DeriveDataTypeable #-}
import System.Console.CmdArgs
data MyProg = New {comment :: String}
| Delete {howMany :: Int}
deriving (Show, Data, Typeable)
new = New {comment = "this is a parameter with a default value"}
delete = Delete {howMany = 10}
main = print =<< cmdArgs (modes [new, delete])
This gives something like:
% ./prog new -c "hello world"
New {comment = "hello world"}
% ./prog delete
Delete {howMany = 10}
You also get help for free:
% ./prog --help
The myprog program
myprog [COMMAND] ... [OPTIONS]
Common flags:
-? --help Display help message
-V --version Print version information
myprog new [OPTIONS]
-c --comment=ITEM
myprog delete [OPTIONS]
-h --howmany=INT
The author also has a nice tutorial. You'll want to do something similar to the "Multiple Modes" section.
Upvotes: 4