An easy way to parse program arguments

I've seen some approaches to parsing program arguments. They seem too complicated. I need a simple solution. But I also want to be able (preferably, not required) to refer to arguments by name. Therefore, if the command looks like this:

./MyApp --arg1Name arg1Value --arg2Name arg2Value

      

then I would like to treat them like args["arg1Name"]

and args["arg2Name"]

to get their values. I know this is not valid Haskell code. What I have now is not much:

main = do
  [args] <- getArgs

      

Again, I would like a simple solution, preferably without any third party haskell libraries involved.

+1


source to share


2 answers


How easy it is to disassemble them in pairs and add them to the map:

simpleArgsMap :: [String] -> Map String String
simpleArgsMap [] = Map.empty
simpleArgsMap (('-':'-':name):value:rest)
    = Map.insert name value (simpleArgsMap rest)
simpleArgsMap xs = error $ "Couldn't parse arguments: " ++ show xs

      



A simple wrapper to show this work:

module Args where

import System.Environment ( getArgs )
import Control.Applicative ( (<$>) )

import qualified Data.Map as Map
import Data.Map ( Map )

main = do
  argsMap <- simpleArgsMap <$> getArgs
  print $ Map.lookup "foo" argsMap

      

+3


source


optparse-applicative

great for parsing arguments and very easy to use! Writing your own argument parser is going to be much harder to get right, modify, extend, or otherwise manage than if you take 10 minutes to write the parser with optparse-applicative

.

Start by importing the module Options.Applicative

.

import Options.Applicative

      

Then create a data type for your command line configuration.

data Configuration = Configuration
                     { foo :: String
                     , bar :: Int
                     }

      

Now for the workhorse, we create a parser using combinators exported from optparse-applicative

. Read the documentation Options.Applicative.Builder

for a complete experience.



configuration :: Parser Configuration
configuration = Configuration
            <$> strOption
                ( long "foo"
               <> metavar "ARG1"
                )
            <*> option
                ( long "bar"
               <> metavar "ARG2"
                )

      

We can now execute ours Parser Configuration

in action IO

to get our command line data.

main :: IO ()
main = do 
          config <- execParser (info configuration fullDesc)
          putStrLn (show (bar config) ++ foo config)

      

And you're done! You can easily extend this parser to support the argument --help

for printing usage documentation (make a new parser from helper <*> configuration

and pass it to info

), you can add default values ​​for specific arguments (including <> value "default"

in arguments strOption

or option

), you can support flags or subparallels, or generate tab completion data.

Libraries are a power multiplier! The investment you make in learning the basics of a good library will pay dividends for what you can accomplish, and tasks will often be easier (and faster!) With the right tool than with a "quick" solution piled together from duct tape.

+5


source







All Articles