Yet Another Monad Tutorial

Jeff Newbern jnewbern@nomaware.com
12 Aug 2003 17:20:13 +0100


Alistair,

Thanks for your message regarding the debate about monads and purity.

What do you think about these additions as a discussion of the issue?
Does this address everything you think is needed?  Is there a clearer
way to explain it?

Thanks,
Jeff

In the section "No Way Out":
----------
The IO monad is a familiar example of a one-way monad in Haskell.
Because you can't escape from the IO monad, it is impossible to write a
function that does a computation in the IO monad but returns a
non-monadic value. Not only are functions of the type IO a -> a
impossible to create, but any function whose result type does not
contain the IO type constructor is guaranteed not to use the IO monad.
Other monads, such as List and Maybe, do allow values out of the monad.
So it is possible to write non-monadic functions that internally do
computations in those monads. The one-way nature of the IO monad also
has consequences when combining monads, a topic that is discussed in
part III.
----------

and a little farther down:

----------
Some people argue that using monads to introduce non-pure features into
Haskell disqualifies it from claiming to be a pure functional language.
This subtle question =97 not particularly relevant to the practical
programmer =97 is revisited in the context of the I/O monad later in the
tutorial.
----------

Later, in the section on the I/O monad:
----------
In Haskell, the top-level main function must have type IO (), so that
programs are typically structured at the top level as an
imperative-style sequence of I/O actions and calls to functional-style
code. Revisiting the debate about the purity of Haskell (in a functional
sense), it is important to note that the IO monad only simulates
imperative-style I/O. The functions exported from the IO module do not
perform I/O themselves. They return I/O actions, which describe an I/O
operation to be performed. The I/O actions are combined within the IO
monad (in a purely functional manner) to create more complex I/O
actions, resulting in the final I/O action that is the main value of the
program. The result of the Haskell compiler is an executable function
incorporating the main I/O action. Executing the program "applies" this
ultimate I/O action to the outside world to produce a new state of the
world. This occurs only once per execution of the program, and since the
state of the world changes for each execution, the issue of purity is
neatly side-stepped.
----------

--=20
Jeff Newbern <jnewbern@nomaware.com>
Nomaware, Inc.