Home > Enterprise >  Command line arguments as Ints in Haskell
Command line arguments as Ints in Haskell

Time:09-17

I have a Haskell program which accepts 2 or 3 Ints from the command line:

-- test.hs

main :: IO ()
main = do
    args <- fmap (read . head) getArgs
    case args of
        [x,y,a] -> doGeneration x y a
        [x,y]   -> doGeneration x y 10
        _       -> usage

However, when I run it with arguments:

$ ./test 100 200
divide: Prelude.read: no parse

Why?

CodePudding user response:

getArgs :: IO [String] returns a list of Strings, by taking the head and then args and it will then read that item.

You however never specified to what it should read, since you use args in a case … of … clause with [x,y,a] and [x, y], it will try to read it as a list of numbers (the type of the number is specified by the doGeneration signature. This thus means that you should write it as:

$ ./test [100,200]

But I think it makes not much sense to do that, you can rewrite the parsing part to:

main :: IO ()
main = do
    args <- fmap (map read) getArgs
    case args of
        [x,y,a] -> doGeneration x y a
        [x,y]   -> doGeneration x y 10
        _       -> usage

This means that it will read every parameter individually, and construct a list with the parsed items, and then we can pattern match on the parsed parts of the program parameters. In that case we thus can still use:

$ ./test 100 200

CodePudding user response:

Your running code is equivalent to

     ....
     case (read "100") of 
         [x,y,a :: Int] -> doGeneration x y a
         [x,y   :: Int] -> doGeneration x y 10
     ....

but reading a string "100" as a list of Ints is impossible, a.k.a. "there's no parse". That's why.

The Int comes from doGeneration's signature which you haven't included. But it must be a Num since you use a and 10 interchangeably.

It's better to use more variables in your do block instead of fmap, when you learn Haskell. It lessens the cognitive load and lets you see clearer what's going on:

main :: IO ()
main = do
    args <- getArgs           -- getArgs :: IO [String]
                              -- args    ::    [String]
    let arg1 = head args      -- arg1    ::     String
        val1 = read arg1
    case val1 of
        [x,y,a] -> doGeneration x y a
        [x,y]   -> doGeneration x y 10
        _       -> usage
  • Related