#The Reader Monad is a Monad
This article about dependency injection
is concerned about the reader monad compromising separation of interface and implementation. In fact, this simply reveals the need to use Scala’s most powerful capability: higher-kinded types.
This is a general pattern: there are many other “effects” that we might want to keep track of in different implementations of an interface:
We can use all these implementations and more with the same client code, because all these things are monads:
use different effect stacks? No problem, we can use
to handle both:
The end result is that we make testing very easy: our unit tests can follow the exact same code paths as live code, but without having to worry about any effects.
Our effects – dependencies via Reader, but also things like remoting, audit logging, database access or possible failures – are minimal overhead in day-to-day code (just the difference between
). But they’re not entirely invisible: we can look at the type of a function and see exactly what kind of effects it might have or depend on. If we’re using the Reader monad, that means we can see exactly what dependencies any call has, just by mousing over it in our IDE – which in turn means we can easily see when something’s not quite right (“why does logging in need the
?”). The end result is code that’s very concise, but without any “magic” or reflection: everything’s plain old code, which is the easiest kind to maintain.