We have seen two functions, putStrLn and (>>), belonging to the IO monad. Of these, only (>>) is required of all monads. Both putStrLn and its coworker getLine help give the IO monad its unique capabilities. This section introduces a second function required of all monads and also provides a rather concrete explanation of the parameter a in IO a.
Suppose we want to echo user input. We would want to use the getLine function which obtains a line of user input from the console. But we cannot write
because the type signatures don't match; getLine produces an IO String and putStrLn requires a String. The type signatures don't match because of Haskell's way of dealing with the potential impurity of getLine. Haskell has getLine return a monadic object instead of a string.
Because getLine represents a monadic object it is opaque. That means the string it obtains cannot be seen. The potential impurity of getLine is squashed. The string that getLine obtains is still there but unavailable in any context that would violate referential transparency. Said bluntly, code that invokes getLine cannot tell the difference between different evaluations of getLine.
This situation is something like riding a bicycle and having a car turn left immediately in front of you. Your immediate concern is avoiding the car. If the car hits you, the police will be concerned with finding the driver. When you deal with a monadic object, it is similarly opaque. But there are ways its “door” can be opened and then you are dealing with something on the interior rather than the object as a whole.
I will call the string obtained by an execution of getLine an interior object. It is interior to the monadic object which getLine returns.
The monadic combinator (>>=) produces the context where an interior object can be viewed. Its type signature is
where m is any monad and the types a and b are arbitrary.
An application of (>>=) would look like
where mon is of type m a and f is of type a -> m b. It is worth emphasizing that a and b can, but need not, be different types.
It is f's job to make an object mon2 out of one of mon's interior objects. It is (>>=)'s job to decide what to do with those mon2s.
Returning to the IO monad consider
Here is an explanation of how main is executed.
The runtime system executes getLine on an initial world_1. During this execution getLine fetches an input line s from the console. It returns a world_2 whose interior value is s.
The runtime system evaluates putStrLn on s producing a world remaking function.
Finally the runtime system executes the world remaking function produced in step 2 on the world created in step 1. This creates a world in which the string s has been written on the console screen.
You will benefit by comparing this description with a similar one for the State monad when you get around to reading Section IX.
A major difference between (>>=) and (>>) is that (>>=) can make use of interior objects and (>>) cannot. That (>>) will ignore any argument given to it is expressed in this definition.
This is the normal way to define (>>) and we will assume it from now on.
Because (>>) is defined in terms of (>>=), (>>=) is the more important combinator to talk about.