Grokking the Reader Monad
Tags: fsharp, functional, programming, grokking
Published: 2021-05-01 08:10:34

From its name the reader monad doesn’t give too many clues about where it would be useful. In this post we’ll grok it by inventing it ourselves in order to solve a real software problem. From this we’ll see that it’s actually one way of doing dependency injection in functional programming.

# Prerequisites 
There won’t really be any theory here, but it’ll be easier if you’ve already grokked monads. If you haven’t then check out [Grokking Monads](https://dev.to/choc13/grokking-monads-in-f-3j7f) from earlier in this series and then head back over here.

# The scenario
Let’s imagine we’ve been asked to write some code that charges a user’s credit card. To do this we’re going to need to lookup some information from a database and also call a payment provider. 

Our domain model will look like this.

```fsharp
type CreditCard =
   { Number: string
     Expiry: string
     Cvv: string }

type EmailAddress = EmailAddress of string 
type UserId = UserId of string

type User =
    { Id: UserId
      CreditCard: CreditCard
      EmailAddress: EmailAddress }
```

We'll also start with a `Database` module containing a function that can read a User and a `PaymentProvider` module that contains a function that can charge a `CreditCard`. They look something like this.

```fsharp
type ISqlConnection =
    abstract Query : string -> 'T

module Database =

    let getUser (UserId id) : User =
        let connection = SqlConnection("my-connection-string")
        connection.Query($"SELECT * FROM User AS u WHERE u.Id = {id}")

type IPaymentClient =
    abstract Charge : CreditCard -> float -> PaymentId

module PaymentProvider =
    let chargeCard (card: CreditCard) amount = 
        let client = new PaymentClient("my-payment-api-secret")
        client.Charge card amount
```

# Our first implementation
Let’s start off with the easiest solution we can think of. We’ll call the database to lookup the user, get the credit card from their profile and call the payment provider to charge it. 

```fsharp
let chargeUser userId amount =
    let user = Database.getUser userId
    PaymentProvider.chargeCard user.CreditCard amount
```

Super easy, given that we already had `Database.getUser` and `PaymentProvider.chargeCard` ready to use. 

The amount of coupling here is probably making you feel a bit queasy though. Invoking `getUser` and `chargeCard` functions directly isn't itself a problem. The problem really lies further down with how those functions themselves are implemented. In both cases they're instantiating new clients like `SqlConnection` and `PaymentClient` which creates a few problems:

1. Hard coded connection strings mean we're stuck talking to the same database instance in all environments.
1. Connection strings usually contain secrets which are now checked into source control. 
1. Writing unit tests isn't possible because it's going to be calling the production database and payment provider. I suppose that's one way to foot the CI bill when running all of those unit tests 😜

# Inversion of Control 🔄
You’re probably not surprised to learn that the solution to this is to invert those dependencies. Inversion of Control (IoC) transcends paradigms, it’s a useful technique in both OOP and FP. It’s just that whereas OOP tends to utilise constructor injection via reflection in FP we'll see there are other solutions available to us.

What’s the easiest IoC technique for a function then? Just pass those dependencies in as parameters. It's like OOP class dependencies, but at the function level. 

```fsharp
module Database =
    let getUser (connection: ISqlConnection) (UserId id) : User =
        connection.Query($"SELECT * FROM User AS u WHERE u.Id = {id}")

module PaymentProvider =
    let chargeCard (client: IPaymentClient) (card: CreditCard) amount = 
        client.Charge card amount

let chargeUser sqlConnection paymentClient userId amount =
    let user = Database.getUser sqlConnection userId
    PaymentProvider.chargeCard paymentClient user.CreditCard amount
```

No surprises there. We’ve just supplied the necessary clients as parameters and passed them along to the function calls that need them. This solution does have it downsides though. The primary one being that as the number of dependencies grows the number of function parameters can become unruly.

On top of this most applications have some degree of layering to them. As we introduce more layers, to break down and isolate the responsibilities of individual functions, we start needing to pass some dependencies down through many layers. This is typical of any IoC solution, once you flip those dependencies it cascades right through all the layers of your application. [It’s ~~turtles~~ inverted dependencies all the way down](https://en.wikipedia.org/wiki/Turtles_all_the_way_down).

# A *partial* solution
What we’d like to avoid is having to explicitly pass those transitive dependencies into functions like `chargeUser` where they’re not being used directly. On the other hand we don’t want to lose compile time checking by falling back to reflection based dependency injection. 

What if we moved those dependency parameters to the end of the function signature? That way we can use partial application to defer supplying them until the last minute, when we're ready to "wire up the application". Let's try with those service modules first.

```fsharp
module Database =
    let getUser (UserId id) (connection: ISqlConnection) : User =
        connection.Query($"SELECT * FROM User AS u  WHERE u.Id = {id}")

module PaymentProvider =
    let chargeCard (card: CreditCard) amount (client: IPaymentClient) = 
        client.Charge card amount
```

With that we can create a new function that gets the user when passed a connection by simply writing the following.

```fsharp
let userFromConnection: (ISqlConnection -> User) = Database.getUser userId
```

And we can do a similar thing when charging the card.

```fsharp
let chargeCard: (IPaymentClient -> PaymentId) = PaymentProvider.chargeCard card amount
```

Alright, let's stick it together and re-write our `chargeUser` function.

```fsharp
let chargeUser userId amount =
    let user = Database.getUser userId
    // Problem, we haven’t got the user now, but a function that needs a ISqlConnection to get it
    PaymentProvider.chargeCard user.CreditCard amount
    // So the last line can’t access the CreditCard property 
```

It's good, but it's not quite right! We've eliminated the two dependency parameters from the `chargeUser` function, but it won't compile. As the comment points out we don’t have a `User` like we need to, but rather a function that has the type `ISqlConnection -> User`. That's because we've only partially applied `Database.getUser` and to finish that call off and actually resolve a `User`, we still need to supply it with a `ISqlConnection`. 

Does that mean we're going to need to pass in the `ISqlConnection` to `chargeUser` again? Well if we could find a way to lift up `PaymentProvider.chargeCard` so that it could work with `ISqlConnection -> User` instead of just `User` then we could get it to compile. In order to do this we need to create a new function that takes a `ISqlConnection` as well as the function to create a `User` given a `ISqlConnection` and the amount we want to charge the user. 

We don't really have a good name for this function because outside of this context it doesn't really make sense to have a `chargeCard` function that depends on a `ISqlConnection`. So what we can do instead is create an anonymous function, a lambda, inside of `chargeUser` that does this lifting for us.

```fsharp
let chargeUser userId amount: (ISqlConnection -> IPaymentClient -> PaymentId) =
    let userFromConnection = Database.getUser userId

    fun connection ->
        let user = userFromConnection connection
        PaymentProvider.chargeCard user.CreditCard amount
```

I've annotated the return type of `chargeUser` to highlight the fact that it's now returning a new function, that when supplied with both dependencies of `ISqlConnection` and `IPaymentClient`, will charge the user.

At this point, we've managed to defer the application of any dependencies, but the solution is a bit cumbersome still. If, at a later date, we need to do more computations in `chargeUser` that require yet more dependencies, then we're going to be faced with even more lambda writing. For instance imagine we wanted to email the user a receipt with the `PaymentId`. Then we'd have to write something like this.

```fsharp
let chargeUser userId amount =
    let userFromConnection = Database.getUser userId

    fun connection ->
        let user = userFromConnection connection
        let paymentIdFromClient = PaymentProvider.chargeCard user.CreditCard amount

        fun paymentClient ->
            let (PaymentId paymentId) = paymentIdFromClient paymentClient
            let email = EmailBody $"Your payment id is {paymentId}"
            Email.sendMail user.EmailAddress email
```

😱

The nesting is getting out of hand, the code is becoming tiring to write and the number of dependencies we eventually need to supply to this function is getting unwieldy too. We're in a bit of a bind here.

# Binding our way out of a bind
Let's see if we can write a function called `injectSqlConnection` that will allow us to simplify `chargeUser` by removing the need for us to write the lambda that supplies the `ISqlConnection`. The goal of this is to allow us to write `chargeUser` like this.

```fsharp
let chargeUser userId amount =
    Database.getUser userId
    |> injectSqlConnection (fun user -> PaymentProvider.chargeCard user.CreditCard amount)
```

So `injectSqlConnection` needs to take a function that requires a `User` as the first parameter and a function that can create a `User` given a `ISqlConnection` as the second parameter. Let's implement it.

```fsharp
let injectSqlConnection f valueFromConnection =
    fun connection ->
        let value = valueFromConnection connection
        f value
```

In fact, that function doesn't depend on the `ISqlConnection` in anyway. It works for any function `f` that needs a value `a` which can be created when passed some dependency. So let's just call it `inject` from now on to acknowledge that it works for any type of dependency.

# You just discovered the reader monad 🤓
The `inject` function is letting us sequence computations that each depend on a wrapped value returned from the last computation. In this case the value is wrapped in a function that requires a dependency. That pattern should look familiar because we discovered it when [Grokking Monads](https://dev.to/choc13/grokking-monads-in-f-3j7f). It turns out that we've in fact discovered `bind` again, but this time for a new monad.

This new monad is normally called `Reader` because it can be thought of as reading some value from an environment. In our case we could call it `DependencyInjector` because it's applying some dependency to a function in order to return the value we want. The way to bridge the mental gap here it to just think of dependency injection as a way to read a value from some environment that contains the dependencies.

# A little lie 🤥
Actually, the implementation of `inject` above isn't *quite* right. If we rewrite the more complex `chargeUser`, the one that also sends an email, using `inject` Then we’ll see how it breaks.

```fsharp
let chargeUser userId amount =
    Database.getUser userId
    |> inject (fun user -> PaymentProvider.chargeCard user.CreditCard amount)
    |> inject (fun (PaymentId paymentId) -> 
        let email =
            EmailBody $"Your payment id is {paymentId}"

        let address = EmailAddress "a.customer@example.com"
        Email.sendMail address email)
```

This actually fails on the second `inject`. That's because after the first call to `inject` it returns the following type `ISqlConnection -> IPaymentClient -> PaymentId`. Now on the second call to `inject` we have two dependencies to deal with, but our `inject` function has only been designed to supply one, so it all falls down. 

The solution to this is to create a single type that can represent all of the dependencies. Basically we want the `chargeUser` function to have the signature `UserId -> float -> Dependencies -> TransactionId` rather than `UserId -> float -> ISqlConnection -> IPaymentClient -> TransactionId`. If we can do that then we just need to make one small adjustment to `inject` to make things work again.

```fsharp
let inject f valueThatNeedsDep =
    fun deps ->
        let value = valueThatNeedsDep deps
        f value deps
```

Notice how this time we also supply `deps` to `f` on the final line? It's subtle but it changes the return type of `inject` to be `('deps -> 'c)`, where `'deps` is the type of dependencies also required by `valueThatNeedsDep`.

So what's happened here is that we've now constrained the output of `inject` to be a new function that requires the same type of `'deps` as the original function. That's important because it means our dependencies are now unified to a single type and we can happily keep chaining computations that require those dependencies together.

# Uniting dependencies 👭
There are several ways to unite all of the dependencies together in a single type, such as explicitly creating a type with fields to represent each one. One of the neatest with F# though is to use inferred inheritance. Inferred inheritance means we let the compiler infer a type that implements all of the dependency interfaces we require. 

In order to use inferred inheritance we need to add a `#` to the front of the type annotations for each dependency. Let's make that change in the `Database` and `PaymentProvider` modules to see what that looks like.

```fsharp
module Database =
    let getUser (UserId id) (connection: #ISqlConnection) : User =
    // Implementation of getUser

module PaymentProvider =
    let chargeCard (card: CreditCard) amount (client: #IPaymentClient): TransactionId =
    // Implementation of chargeCard
```

All we've changed is to write `#ISqlConnection` instead of `ISqlConnection` and `#IPaymentClient` instead of `IPaymentClient`. From this F# can union these types together for us when it encounters something that needs to satisfy both constraints. Then at the root of the application we just have to create an object that implements both interfaces in order to satisfy the constraint.

The upshot of this is that F# infers the type signature of `chargeUser` to be `UserId -> float -> ('deps -> unit)` and it requires that `'deps` inherit from both `ISqlConnection` and `IPaymentProvider`. 

# A final improvement
We've pretty much reached our stated goal now of eliminating all of the explicit dependency passing between functions. However, I think it's still a bit annoying that we have to keep creating lambdas to access the values like `user` and `paymentId` when calling `inject` to compose the operations. We've seen before, in [Grokking Monads, Imperatively](https://dev.to/choc13/grokking-monads-imperatively-394a), that it's possible to write monadic code in an imperative style by using computation expressions. 

All we have to do is create the computation expression builder using the `inject` function we wrote earlier, as that's our monadic `bind`. We'll call this computation expression `injector` because that's more relevant to our use case here, but typically it would be called `reader`.

```fsharp
type InjectorBuilder() =
    member _.Return(x) = fun _ -> x
    member _.Bind(x, f) = inject f x
    member _.Zero() = fun _ -> ()
    member _.ReturnFrom x = x

let injector = InjectorBuilder()

let chargeUser userId amount =
    injector {
        let! user = Database.getUser userId
        let! paymentId = PaymentProvider.chargeCard user.CreditCard amount
        let email =
            EmailBody $"Your payment id is {paymentId}"

        return! Email.sendMail user.Email email
    }
```

😍
By simply wrapping the implementation in `injector { }` we’re basically back to our very first naïve implementation, except this time all of the control is properly inverted. Whilst the transitive dependencies are nicely hidden from sight they’re still being type checked. In fact if we added more operations to this later that required new dependencies then F# would automatically add them to the list of required interfaces that must be implemented for the `'deps` type in order to finally invoke this function.

When we're finally ready to call this function, say at the application root where we have all of the config to hand in order to create the dependencies, then we can do it like this.

```fsharp
type IDeps =
    inherit IPaymentClient
    inherit ISqlConnection
    inherit IEmailClient

let deps =
    { new IDeps with
        member _.Charge card amount =
            // create PaymentClient and call it

        member _.SendMail address body =
            // create SMTP client and call it

        member _.Query x =
            // create sql connection and invoke it 
            }

let paymentId = chargeUser (UserId "1") 2.50 deps
```

Where we use an object expression to implement our new `IDeps` interface on the fly so that it satisfies all of the inferred types required by `chargeUser`.

# Quick recap 🧑‍🎓 
We started off by trying to achieve inversion of control to remove hardcoded dependencies and config. We saw that doing this naïvely can lead to an explosion in the number of function parameters and that it can cascade right through the application. In order to solve this we started out with partial application to defer supplying those parameters until we were at the application root where we had the necessary config to hand. However, this solution meant that we couldn't easily compose functions that required dependencies and it was even more tricky when they required different types of dependencies.

So we invented an `inject` function that took care of this plumbing for us and realised that we'd actually discovered a new version of `bind` and hence a new type of monad. This new monad is commonly known as `Reader` and it's useful when you need to compose several functions that all require values (or dependencies) that can be supplied by some common environment type.

If you want to use the reader monad in practice then you can find an implementation that's ready to roll in the [FSharpPlus](https://fsprojects.github.io/FSharpPlus/reference/fsharpplus-data-reader.html) library.

## Appendix
The format of the reader monad is often a little different in practice to how it was presented here. Expand the section below if you want more details.

{% details %}

Usually when implementing the reader monad we create a new type to signify it, called `Reader`, in order to distinguish it from a regular function type. I left it out above because it's not an important detail when it comes to grokking the concept, but if you're looking to use the technique then you'll likely encounter it in this wrapped form. It's a trivial change and the code would just look like this instead.

```fsharp
type Reader<'env, 'a> = Reader of ('env -> 'a)

module Reader =
    let run (Reader x) = x
    let map f reader = Reader((run reader) >> f)

    let bind f reader =
        Reader
            (fun env ->
                let a = run reader env
                let newReader = f a
                run newReader env)

    let ask = Reader id

type ReaderBuilder() =
    member _.Return(x) = Reader (fun _ -> x)
    member _.Bind(x, f) = Reader.bind f x
    member _.Zero() = Reader (fun _ -> ())
    member _.ReturnFrom x = x

let reader = ReaderBuilder()

let chargeUser userId amount = 
    reader {
        let! (sqlConnection: #ISqlConnection) = Reader.ask
        let! (paymentClient: #IPaymentClient) = Reader.ask
        let! (emailClient: #IEmailClient) = Reader.ask
        let user = Database.getUser userId sqlConnection
        let paymentId = PaymentProvider.chargeCard user.CreditCard amount paymentClient

        let email =
            EmailBody $"Your payment id is {paymentId}"

        return Email.sendMail user.Email email emailClient
    }
```

The return type of `chargeUser` is now `Reader<'deps, unit>` where `'deps` will have to satisfy all of those interfaces marked with `#` as before. 

I've also had to use `Reader.ask` to actually get dependencies out of the environment in this case. The reason for this is because functions like `Database.getUser` do not return a `Reader` in their current form. We could create a `Reader` on the fly by doing `Reader (Database.getUser userId)` but sometimes that can also be cumbersome, especially if we're working with client classes rather than functions, which is often the case. So having `ask` in our toolkit can be a nice way to just get hold of the dependency and use it explicitly in the current scope.

{% enddetails %}