1

I have this program which just prints out the command line arguments.

echoArgs :: IO ()
echoArgs = do
        line <- getArgs
        print line

What I wanted to know is that why does this fail when I type:

echoArgs :: IO ()
echoArgs = do
            line <- getArgs
            putStrLn line

and also why doesn't it work when I change it to:

echoArgs :: IO String
    echoArgs = do
                line <- getArgs
                let line' = read line :: String
                putStrLn line'
Will Ness
  • 70,110
  • 9
  • 98
  • 181
Rahat
  • 305
  • 1
  • 4
  • 10
  • 1
    Paying attention to the error messages you receive can be helpful in determining what went wrong. –  Jan 18 '20 at 16:34

2 Answers2

6

Because

getArgs :: IO [String]

so line in do { line <- getArgs ; ... } is

line    ::    [String]

but putStrLn :: String -> IO () expects a String argument, not a list of Strings.

Similarly, read :: Read a => String -> a also expect a String argument, not a list of Strings argument.

See also: The Guide to Types in do-notation, In Vivid Colors.

Will Ness
  • 70,110
  • 9
  • 98
  • 181
1

print produces a String from whatever argument you give it.

putStrLn, on the other hand, expects a String as an argument. (Indeed, print = putStrLn . show.) Similarly, read expects a String as an argument; in effect, it deserializes when what you are trying to do is serialize the list.

getArgs has type IO [String], which means that line is not a String, but both String and Show a => [a] have a Show instance which print can use to make a String out of it.

chepner
  • 497,756
  • 71
  • 530
  • 681