Posted by
Niklas Leopold
on September 26, 2020 ·
11 mins read
About the post
I recently read a nice blog post about the Reader monad written by Kyle Corbelli. The post uses Haskell for it’s example so I decided to translate it to Scala using the Cats library and put my own words to it.
The problem
Have you ever noticed a function that takes input parameters that it’s not using it self, the function only forwards them to other function that it calls.
This post is all about that and how to use the Reader monad to get well like, more readable code.
The Core
In the example provided by Kyle we are developing a web page using our own small little library. The core of the library looks like this:
Three simple small functions that we will use to build the more complex structure that forms our web page.
The page
The page will have the following component hierarchy:
view
page
topnav
content (needs email)
left
right
article
widget (needs email)
As we can see it’s a pretty standard page.
Notice that some of the components are marked with “needs email”? Since this is a dynamic page we will need to provide the email address each time it’s rendered (the address varies each time).
First attempt
So let’s try and implement it:
The result if we invoke the view with an email address is:
The code will do the job, but don’t you find it irritating that we have to pass the email address all the way down the hierarchy? Take for example the article function, it doesn’t use the mail address for anything, it just passes it on to widget. The code feels a little bit dirty don’t you think?
In fact wouldn’t it be nicer if widget somehow just could ask for the email address and let artice go about it’s own business?
Something like this:
However we still want the function to be pure, i.e. only depend on the input it is given, can we still do it? Can we use some magic?
Turn’s out that we can!
So why don’t you just ask for it?
Let’s refactor widget so that it’s using the Reader monad:
If we squint our eyes just like so, is this not almost the same as:
The magic is provided by the Reader monad and the ask helper function.
As you can see we are no longer returning HTML, instead we wrap HTML in the Reader monad together with a Context that contains the email address.
To get the HTML we need to provide the context to the Reader by invoking it’s run method.
Have we succeeded? Can we just ask for it and still be pure? I say
Let’s apply it to the rest
So let’s apply the same pattern to the rest of the code:
And that’s it.
Conclusion
If you find you’re self providing input arguments to functions that are only forwarded, the Reader monad could be something for you.
Once again, here is the original blog post that I translated to Scala and put some other words to.