Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save przemek-pokrywka/4590235 to your computer and use it in GitHub Desktop.
Save przemek-pokrywka/4590235 to your computer and use it in GitHub Desktop.
Reader Monad dependency injection when each of injected functions depends on something other. The goal is to assess, how good does Reader Monad fit into this context.
case class Reader[Conf, Res](obtainResult: Conf => Res) {
def map[NewRes](transform: Res => NewRes) =
Reader {
(config: Conf) =>
transform(this obtainResult config)
}
def flatMap[NewRes](createReader: Res => Reader[Conf, NewRes]) =
Reader {
(config: Conf) =>
val newReader = createReader(this obtainResult config)
newReader obtainResult config
}
}
/** Demonstrates usage of Reader Monad for dependency injection
* when each of injected functions depends on something other
*/
object Demo extends App {
// Some "domain model"
trait GUI { def display(s: String): Unit }
trait DB { def crud(a: Any): Unit }
case class ConsoleGUI extends GUI { def display(s: String) = println(s) }
case class SimpleDB extends DB { def crud(a: Any) = println("cruded " + a) }
// "business logic"
// Reader Monad requires it in form of curried functions
// Point of this exercise is that the functions have different dependencies
// - first depends on GUI, second on DB
val blink = (times: Int) => (gui: GUI) =>
(1 to times).map(_.toString).foreach(gui.display _)
val saveAll = (times: Int) => (db: DB) =>
(1 to times).foreach(db.crud _)
// Plumbing required by Reader Monad in this case.
// A type that groups together all dependencies to be injected
type Ctx = (GUI, DB)
// Conversions needed to use "business logic" functions unchanged
implicit def guiFun2CtxFun(guiFn: GUI => Unit): Ctx => Unit =
ctx => guiFn(ctx._1)
implicit def dbFun2CtxFun(dbFn: DB => Unit): Ctx => Unit =
ctx => dbFn(ctx._2)
// Program preparation
val program = for {
_ <- Reader[Ctx, Unit](blink(2))
_ <- Reader[Ctx, Unit](saveAll(5))
} yield ()
// Injection and execution at once
program obtainResult ((ConsoleGUI(), SimpleDB()))
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment