Skip main navigation

I/O and a First Encounter with Monads

How does Haskell handle basic input and output operations? In this article, Dr Jeremy Singer begins to introduce the concept of the IO Monad.
Mainframe panel with input switches and output lights
© University of Glasgow

Pure Functions

So far, we have concentrated on pure functions. These kinds of functions take values as arguments, do some processing of those values, then return a result value. A pure function does not depend on the ‘state of the world’. The computation is entirely self-contained and independent. Given the same arguments, a pure function will always return the same result.

I/O is Impure

Input and output (I/O) operations are impure. They influence and interact with the ‘outside world’. Essentially, this is the only way to make computers do interesting things.

So far we have looked at the getLine function, which reads
input from the user and returns it as a special
kind of String value — an IO String.
We have also used the putStrLn function, which takes a String
input and prints it to the terminal, returning an empty IO value, i.e. IO ().

The point of IO types is that we don’t want to mix up pure and
impure functions — the type system keeps us honest.
We know from a function’s type whether it is involved with
I/O.

Sequencing Actions

Look at this simple function below.

let greet() = do 
planet <- getLine
home <- getLine
putStrLn ("greetings " ++ planet ++ "ling.")
putStrLn ("I am from " ++ home ++ ".")
putStrLn "Take me to your leader."

In our tryhaskell web interpreter, you would need to enter it as a (very long!) one-liner:

do { planet <- getLine; home <- getLine; putStrLn ("greetings " ++ planet ++ "ling."); putStrLn ("I am from " ++ home ++ "."); putStrLn "Take me to your leader."}

Let’s try this out… copy and paste the one-liner into our tryhaskell online system. NB check there are no trailing space characters in your pasted expression — use backspace to remove them. Press enter to evaluate the one-liner, then at the > prompt type Earth (enter) then Mars (enter). You should then see:

greetings Earthling.
I am from Mars.
Take me to your leader.

Notice that the ordering is important here:

  1. we want the first getLine call to get the name of the planet we have
    landed on
  2. we want the second getLine call to get the name of
    where we are from.

Order of function evaluation doesn’t matter in pure code –
e.g.

let a = reverse "winston"
b = reverse "churchill"
in "sir " ++ a ++ " " ++ b

Again, in tryhaskell, we should use a lengthy one-liner:

let a= reverse "winston"; b = reverse "churchill" in "sir " ++a ++" "++ b

It doesn’t matter whether we do the first reverse before the
second — the result of the expression is still the same. However this is not the case where I/O is concerned. Sequencing
is vital for I/O actions.

One more thing to notice: inside the do, we associate results of IO functions with names using <-. Inside the let, we associate pure function results with names using =.

Monads are Hiding Below

The do notation allows us to sequence actions. This looks
just like a sequence of commands in an imperative
programming language.
However, do is only syntactic sugar. Underneath, it is
rewritten as a chain of function calls where the output
of the first function becomes the input of the second function.
The bind operator accomplishes this function sequencing. It
is a key part of the IO monad. We are starting to scratch
the surface of Haskell IO and discover it is highly complex.
We will reserve discussion of Monads and bind operators for later
in the course.

Summary

For now, all we need to understand is:

  • I/O operations are impure
  • use do to specify a sequence of actions
  • use <- inside a do to associate input values with names
  • any value or function that involves I/O has IO in its type
  • a sequence of I/O actions is described as being in the IO Monad
© University of Glasgow
This article is from the free online

Functional Programming in Haskell: Supercharge Your Coding

Created by
FutureLearn - Learning For Life

Our purpose is to transform access to education.

We offer a diverse selection of courses from leading universities and cultural institutions from around the world. These are delivered one step at a time, and are accessible on mobile, tablet and desktop, so you can fit learning around your life.

We believe learning should be an enjoyable, social experience, so our courses offer the opportunity to discuss what you’re learning with others as you go, helping you make fresh discoveries and form new ideas.
You can unlock new opportunities with unlimited access to hundreds of online short courses for a year by subscribing to our Unlimited package. Build your knowledge with top universities and organisations.

Learn more about how FutureLearn is transforming access to education