Hiding the IO Monad

The blessing and curse of the IO monad is that
it is extremely powerful. If we believe that careful use of types helps
us to avoid programming mistakes, then the IO monad should
be a great source of unease. Because the IO monad imposes
no restrictions on what we can do, it leaves us vulnerable to all kinds
of accidents.

How can we tame its power? Let’s say that
we would like guarantee to ourselves that a piece of code can read and
write files on the local filesystem, but it will not access the network.
We can’t use the plain IO monad, because it won’t restrict
us.

Using a newtype

Let’s create a module that provides a
small set of functionality for reading and writing files:

We do the by now familiar trick of
exporting the type constructor and the runHandleIO execution function from our
module, but not the data constructor. This will prevent code running
within the HandleIO monad from getting hold of the
IO monad that it wraps.

All that remains is for us to wrap each of the actions that we want our monad to allow. This is a simple matter of wrapping each ...

The best content for your career. Discover unlimited learning
on demand for around $1/day.