(TL;DR: Intro to the reader-monad in F# for dependency-injection – see the source)

# intro: the problem

Let’s say you have a function `f`

that needs an object implementing some interface

type InterfaceA = abstract MethodA : string -> string

to do it’s work.

# a dirty solution (not advised)

Another solution that can work is to make the dependency a *mutable* part of your defining module:

module MyModule = let DependencyA = ref DefaultImplementationA let f x = ... use (!DependencyA).MethodA ...

I would not advise using this for obvious reasons (hard to test if tests run parallel, etc.) but it can come handy from time to time.

For example I sometimes like to use these for static-parameters/feature-switches and cross-cutting-concerns like logging – but **really**: use with care.

# the usual solution

Using object oriented techniques you would most likely use constructor-injection to solve this:

type ConstructorInjection (i : InterfaceA) = member __.f x = ... do something with i.MethodA ...

But isn’t that *overkill*? We make a new class only to inject the interface. What’s even worse: we now need an instances of `ConstructorInjection`

to even get the `f`

back.

## just make it explicit

In most cases I just make the dependencies into explicit arguments and deal use using partial application:

let f (i : InterfaceA) (x : X) : Y = ...

let f` x = f myImplementation x

## many dependencies

So what if you have to deal with many dependencies? That’s usually when you start looking for an DI-container to keep track of all the stuff. Keeping it simple you can just collect all dependencies you have in a *dependencies* structure – for example a record like this:

type Dependencies = { interfaceA : InterfaceA ; interfaceB : InterfaceB // ... }

But of course you probably would not want this to *leak* into your modules everywhere (meaning: don’t use `Dependencies`

as parameters to your functions if they really only need `InterfaceA`

). Instead let the caller handle the *projections*:

let deps : Dependencies = ... let f (i : InterfaceA) x = ... ... let res = f deps.interfaceA argX

# the fancy solution

You might have guessed it already: there is a *fancy* solution and yeah it’s involving the **M**-word.

Functions depending on `InterfaceA`

will look something like this: `InterfaceA -> additional args -> result`

. Let’s change this a bit: First flip the arguments into `additional args -> InterfaceA -> result`

which is really `additional args -> (InterfaceA -> result)`

. Then extract the common part into a type:

type UsingA<'result> = InterfaceA -> 'result

Now the types work out into `additional args -> UsingA<'result>`

and if you have no additional arguments it will just be an value of `UsingA`

.

Abstracting it further by making the dependency generic also we end up with:

type ReaderM<'dependency,'result> = 'dependency -> 'result let run (d : 'dependency) (r : ReaderM<'dependency,'result>) : ' result = r d

and our function now has a new type `f : X -> ReaderM<InterfaceA,Y>`

# implementing the usual patterns

It turns out, that `ReaderM`

falls into several patterns, so let’s start collecting some:

## constant readers

It’s useful to have a `ReaderM`

value that does always returns a constant:

let constant (c : 'c) : ReaderM<_,'c> = fun _ -> c

## functor

`ReaderM`

is a functor – let’s give it a `map`

:

let map (f : 'a -> 'b) (r : ReaderM<'d, 'a>) : ReaderM<'d,'b> = r >> f let (<?>) = map

## applicative-functor

let apply (f : ReaderM<'d, 'a->'b>) (r : ReaderM<'d, 'a>) : ReaderM<'d, 'b> = fun dep -> let f' = run dep f let a = run dep r f' a let (<*>) = apply

## monad

Of course `ReaderM`

is a monad 😉

let bind (m : ReaderM<'d, 'a>) (f : 'a -> ReaderM<'d,'b>) : ReaderM<'d, 'b> = fun dep -> f (run dep m) |> run dep let (>>=) m f = bind m f type ReaderMBuilder internal () = member __.Bind(m, f) = bind m f member __.Return(v) = constant v member __.ReturnFrom(v) = v member __.Delay(f) = f () let Do = ReaderMBuilder()

## lifting it

Now let’s make it easier to create `ReaderM<_,_>`

valued computations from functions with dependencies (like our `f`

) above by *lifting* those into the monad:

let lift1 (f : 'd -> 'a -> 'out) : 'a -> ReaderM<'d, 'out> = fun a dep -> f dep a let lift2 (f : 'd -> 'a -> 'b -> 'out) : 'a -> 'b -> ReaderM<'d, 'out> = fun a b dep -> f dep a b let lift3 (f : 'd -> 'a -> 'b -> 'c -> 'out) : 'a -> 'b -> 'c -> ReaderM<'d, 'out> = fun a b c dep -> f dep a b c // ...

And there is another way you can *lift* stuff: Think back on the situation above where you have a function depending on `InterfaceA`

but you wrapped an instance into a `Dependencies`

structure. Here you can lift a `ReaderM<InterfaceA,_>`

computation into a `ReaderM<Dependencies,_>`

computation when you have an *projection* from `Dependencies -> InterfaceA`

:

let liftDep (proj : 'd2 -> 'd1) (r : ReaderM<'d1, 'out>) : ReaderM<'d2, 'out> = proj >> r

# Example

Let’s put this all into a short example:

Imagine you have these two interfaces (and some implementations):

type IResources = abstract GetString : unit -> string let resource = { new IResources with member __.GetString () = "World" } type IOutput = abstract Print : string -> unit let output = { new IOutput with member __.Print s = printfn "%s" s }

We collect them into a `Dependencies`

type – to keep things simple it’s just a tuple of those two:

type Dependencies= IResources * IOutput let config = (resource, output)

Now we need some functions working with these dependencies:

let getWord = lift1 (fun (res : IResources) -> res.GetString) () let print = lift1 (fun (out : IOutput) -> out.Print)

And our task is to get a *word* from the resources using the `GetString`

, prepending `"Hello "`

and printing the result using `Print`

from `IOutput`

:

let computation () = Do { let! text = sprintf "Hello %s" <?> liftDep fst getWord do! liftDep snd (print text) }

Sadly I have to make `computation`

into a function (or give F# some further hints by using it – see the gist) or else I will run into a **Value restriction** (I talked about it before). Anyway here is the output:

> computation () |> run config;; Hello World val it : unit = ()

If you like you can use `(>>=)`

instead:

let computation2 () = sprintf "Hello %s" <?> liftDep fst getWord >>= fmap (liftDep snd) print

This uses a helper function `fmap`

that is really just function-composition or the functor-mapping for `'c ->`

if you want to be fancy:

let fmap (f : 'a -> 'b) (g : 'c -> 'a) : ('c -> 'b) = g >> f