Skip to content

Reading from stdin and Writing to stdout

putChar, putStr, and putStrLn

The first three functions you want to use to print stuff on screen are

putChar  :: Char   -> IO ()
putStr   :: String -> IO ()
putStrLn :: String -> IO ()

Neither of them returns anything. You call them only for their effects, which is to make characters appear on your screen. putChar prints a single character. putStr prints a whole string. putStrLn does the same as putStr but adds a newline character at the end to start a new line:

>>> putChar '0'
0>>> putStr "Hello"
Hello>>> putStrLn "Hello"
Hello

The output of the first two actions may not be obvious. They appear before the prompt of the next line, exactly because neither putChar nor putStr adds a newline at the end.

There's not much more to be said about these functions. The one thing to point out is that C programmers are used to using printf to format all kinds of data other than string data:1

int x = 5;
double y = 3.14;

printf("x = %d, y = %lf\n", x, y);

To do the same, Java programmers use the fact that, for example, adding a number to a string automatically converts the number to its string representation.

int x = 5;
double y = 3.14;

System.out.println("x = " + x + ", y = " + y);

Haskell performs none of these automatic conversions. However, we have the good old show function that allows us to convert any value of a type that is an instance of Show into its string representation. Thus,

GHCi
>>> x = 5
>>> y = 3.14
>>> putStrLn $ "x = " ++ show x ++ ", y = " ++ show y
x = 5, y = 3.14

print

The function that GHCi uses to print the values of expressions entered at the prompt is

print :: Show a => a -> IO ()
print = putStrLn . show

print x converts x to its string representation, displays this string representation on screen, and adds a newline at the end, because it uses putStrLn, not putStr, to print the string representation of x:

>>> print x
5
>>> print "Hello"
"Hello"
>>> print Nothing
Nothing

As with any program, printing "on the screen" means printing to stdout, the program's standard output stream. Normally, this is the screen, but for example, if we pipe the output of our program to some other program, then our program's stdout becomes the stdin of the other program, and nothing will be printed on screen. Instead, the other program reads the output our program produces and hopefully does something useful with it.

getChar, getLine, and getContents

Simple interactive programs can be built by reading individual characters or entire strings from the keyboard. Only, they aren't really read from the keyboard but from stdin, our program's standard input stream. This input may be provided by the keyboard or by the stdout stream of another program if we pipe that program's output to our program's input.

We read a single character using

getChar :: IO Char

Note that this is an IO action that takes no arguments. It has type IO Char. In C, this function would have the type getChar :: Char. But in Haskell, a value of type Char is just a value, or at best a zero-argument function that always returns the same result of type Char. The type IO Char means that getChar may return a different result every time we run it. It's an action that returns a value of type Char. That's because IO Char is a wrapper around the function type RealWorld -> (Char, RealWorld). The result returned by getChar depends on the state of the world, and the part of the state of the world that getChar depends on is the last character that was added to our program's stdin.

Here's getChar in action in GHCi:

GHCi
>>> getChar
1'1'

The weird-looking output was produced as follows: I pressed 1 on my keyboard. That echoed the character 1 on the screen. getChar read that 1. Since I was inside GHCi, GHCi printed the result returned by getChar, which was '1'. Just as in C, there exist more fine-grained facilities that allow us to read characters without echoing them to the screen, but they are beyond the scope of this book.

For reading an entire line, we have

getLine :: IO String
GHCi
>>> getLine
This is a line.
"This is a line."

We can also read the entire contents of stdin using

getContents :: IO String

This doesn't work so well in GHCi, but you can use it in compiled programs to read all of stdin. I won't demonstrate the use in GHCi. If you do try, the only thing you can do to get getContents to return is is to press Ctrl+C, and then you get a strange error message. That's a known bug. The problem is that Ctrl+D, the usual method to signal the end of file when entering them on the terminal, sends EOT in GHCi, and getContents simply reads this character without interpreting it as the end of the file. I'm not sure who is to blame here, whether GHCi should actually close stdin upon seeing EOT or whether getContents should interpret it as end-of-file.

We'll look at getContents a little later, when talking about the interaction between Haskell's lazy evaluation and I/O.


  1. For all its archaic syntax of the format string, C's printf is a tried and tested approach to formatting data. Thus, Haskell programmers felt they couldn't really do without such a powerful tool. The Text.Printf module provides Haskell's version of printf. With it, we can print things more or less in C style:

    GHCi
    >>> import Text.Printf
    >>> printf "x = %d, y = %f\n" x y
    x = 5, y = 3.14
    

    I don't use this facility very often. Other Haskell programmers may use it more.