7 Dec

Output

putStr :: String -> IO () prints the given string to stdout:

> putStr "Hello, World!\n"
Hello, World!

It takes a String and does an IO action which produces no result, indicated by the empty parentheses ().

Multiple actions can be chained together using the >> operator:

> putStr "Hello" >> putChar ',' >> putStrLn " World!"
Hello, World!

Input

getLine :: IO String consumes one line from from stdin:

> getLine
abc  -- input followed by <enter>
"abc"  -- the result from calling getLine

If the input string would be "abc\nxy", after calling getLine, "xy" would be left

Multiple actions can be combined using the bind operator >>=:

> getLine >>= \str -> putChar (head str)
abc  -- input followed by <enter>
a  -- just the first letter

Input-Output

A function which yells everything you enter

loudEcho :: IO ()
loudEcho = getLine >>= \line ->
             if line == "." then  -- stop the loop on period
               return ()  -- because loudEcho always returns an IO ()
             else
               putStr (map toUpper line) >>  -- "yell" the input
               putStrLn "!" >>
               loudEcho  -- keep looping

return :: a -> IO a does nothing, but produces a value. For the input string "abc", calling return "!" would produce "!" and leave the input unchanged ("abc").

> loudEcho
hello  -- input followed by <enter>
HELLO!!
world  -- input followed by <enter>
WORLD!!
.   -- break the loop
>

Do notation

Sequencing IO actions can also be done using the do notation.

greet :: IO () greets the user:

greet = do
  putStr "Please enter your name: "
  getLine
  putStrLn "Hello, there!"

It asks for your name but shows the same greeting regardless of input:

> greet
Please enter your name: Stefan   -- input followed by <enter>
Hello, there!

personalGreet :: IO () offers a more personal touch:

personalGreet :: IO ()
personalGreet = do
  putStr "Please enter your name: "
  name <- getLine
  let nameExcl = name ++ "!"  -- no need for "in" in do notation
  putStrLn ("Hello, " ++ nameExcl)

It doesn’t ignore the input given:

> personalGreet
Please enter your name: Stefan
Hello, Stefan!

Relation to bind >>=

For example,

do {
  var1 <- expr1;
  var2 <- expr2;
  expr3;
  expr4;
}

becomes:

expr1 >>= \var1 ->
expr2 >>= \var2 ->
expr3 >>
expr4

Brackets { } create a separating block. Semicolons ; separate multiple actions are written on the same row.

loudEcho rewritten in do notation:

loudEcho' :: IO ()
loudEcho' = do
  line <- getLine
  if line == "." then  -- stop the loop on period
    return ()
  else do
    putStr (map toUpper line)  -- "yell" the input
    putStrLn "!!"
    loudEcho'  -- keep looping