(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