I have a Haskell program which accepts 2 or 3 Int
s 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 String
s, 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 Int
s 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