# Dependency Injection in Scala

Given a function `run` and a class `Reader` that wraps it:

``````case class Reader[E,A](run: E => A) {

def map[B](g: A => B): Reader[E,B] = ???

def flatMap[B](g: A => Reader[E,B]): Reader[E,B] = ???
}``````

And given a couple of functions with dependencies:

``````val timesTwo: Int => Int = x => x * 2

val plusTwo: Int => Int = x => x + 2``````

Implement `map` and `flatMap` so that we can use `Reader` in a `for`-comprehension:

``````def get(k: String): Reader[Map[String,Int],Int] =

val program: Reader[Map[String,Int],Int] =
for {
x <- get("x")
a  = timesTwo(x)
y <- get("y")
b  = plusTwo(y)
} yield a * b

println(program.run(Map("x" -> 3, "y" -> 5))) // 42``````

## Bonus

Implement `inject` to automatically lift functions with dependencies into a configuration-specific `Reader`:

``````trait Config {
def x: Int
def y: Int
}

val program2: Reader[Config,Int] =
for {
a <- timesTwo.inject(_.x)
b <- plusTwo.inject(_.y)
} yield a * b

println(program2.run(new Config { val x = 3; val y = 5 })) // 42``````

# Solution

Here is one possible solution.
``````case class Reader[E,A](run: E => A) {

def map[B](g: A => B): Reader[E,B] =

def flatMap[B](g: A => Reader[E,B]): Reader[E,B] =
}``````

## Bonus

``````implicit class ConfigReader[A,B](val f: A => B) {
def inject(g: Config => A): Reader[Config,B] =
new Reader[Config,B](g andThen f)
}``````

## Demo

This file is literate Scala, and can be run using Codedown:

``````\$ curl https://earldouglas.com/posts/exercises/scala-reader.md |
codedown scala |
xargs -0 scala -nc -e
42
42``````