LR69149
LR69149

Reputation: 31

How to check the number of command-line arguments?

I have a project in Haskell Language and I am not very experienced in this technology.

My program must take 5 command-line arguments (binary included), it should be like the following line :

./my_program --a 30 --b 20

How can I check the number of arguments (return an error if arguments != 5)?

I know the getargs function but I don't know how to use it.

Upvotes: 3

Views: 916

Answers (1)

sshine
sshine

Reputation: 16125

Here is an example of how you can use getArgs:

module Main where

import System.Environment (getArgs)

main :: IO ()
main = do
  args <- getArgs
  if length args == 5
    then putStrLn "You gave me 5 args!"
    else putStrLn "You didn't give me 5 args!"

Edit: It was length args, not args, thanks.

Edit: But note that getArgs on ./my_program --a 30 --b 20 will, unlike in C, not mention ./my_program as part of the arguments. If you want the program name it's getProgName. Otherwise, the right number is probably 4. For the sake of working with the IO monad, you could extend the program to print out the name of the executable:

import System.Environment (getArgs, ...)

main = IO ()
main = do
  args <- getArgs
  name <- ...

  putStrLn ("Program: " <> show name)
  if length args == 4
    ...

But what you appear to be going for is argument parsing, not just counting.

You could use optparse-generic to auto-generate an argument parser based on a datatype.

There is an example in the documentation for Options.Generic that I turned into a template project here, with the important parts mentioned below for posterity:

{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE TypeOperators #-}

module Main where

import Control.Monad.IO.Class (MonadIO)
import Options.Generic

data Config w = Config
  { bleeps :: w ::: Int <?> "Number of bleeps"
  , bloops :: w ::: Int <?> "Number of bloops"
  } deriving (Generic)

instance ParseRecord (Config Wrapped)
deriving instance Show (Config Unwrapped)

main :: IO ()
main = do
  config <- getConfig
  putStrLn $
    "I got " <> show (bleeps config) <> " bleeps, and "
             <> show (bloops config) <> " bloops."

getConfig :: IO (Config Unwrapped)
getConfig = unwrapRecord "Hello"

If you replace bleeps and bloops with a and b, you can run the program with e.g.

$ stack run -- --a 30 --b 20

Upvotes: 7

Related Questions