Haskell — A Simple Example of MonadIO

Steven Leiva
2 min readOct 14, 2017

--

In this post, I want to explain how to use the MonadIO typeclass in Haskell. Note that this post is an explanation of what MonadIO does for us, not how it does it.

In fact, more than anything, this is going to be an example of using the substitution model and equational reasoning to understand a small program.

Some Real Code via Scotty

The code that we are going to be looking at is this:

If you have stack installed, you can play around with this by creating a new stack project with the scotty-hello-world template:

ScottyM Monad

Our main function above, the entry point for our program, is defined as scotty 3000 <second argument here>. Let's look at the type of scotty:

Based on the type of scotty, we know that our second argument - what I labeled <second argument here> - must have the type ScottyM ().

do Notation

The second argument to scotty is a value of type ScottyM (). That value was built using do notation, which we know to be syntactic sugar for >> and >>=. That means that we need to "play by the rules of" those operators. What are those rules? Well, specializing those operators to the ScottyM monad that we are in, they are:

Printing in the Middle of the ScottyM Monad

Let’s say that we wanted to modify our code so that, whenever someone makes a request to our web server, we print that out. A first pass at that would look like this:

Notice that we added putStrLn "hello" right in the middle of our monad.

That, however, won’t type check. The reason is that putStrLn "hello" :: IO (), and, based on the types of >> and >>=, each line must be a value of type ScottyM a. We can't just plop a value of type IO () in the middle of our do block.

liftIO

This brings us, finally, to the motiviation of this post, MonadIO.

You can look up the information for this typeclass on your own. For our purposes, suffice it to say that liftIO is the only method in the MonadIO typeclass. It has the signature liftIO :: Monad m => IO a -> m a. This means that it takes any IO a value and turns that into another monad that, when ran, produces a value of type a.

In our specific case, liftIO will take our IO () and return back a ScottyM (). A value of type ScottyM () is exactly the type we need in order to plop it down in the middle of our do block.

Finally

Originally published at gist.github.com.

--

--