Here is a simple service example, whose methods return reader:
trait Service1_1{
def s1f1:Reader[Map[String,Int],Int] =
Reader(_("name"))
def s1f2:Reader[Map[String,Int],Int] =
Reader(_("age"))
}
Here is a service-consumer, that accepts parameter, map, and also returns reader itself:
trait Service1_2 {
def s12f1(i:Int, map:Map[String,Int]):Reader[Service1_1, Int] =
Reader(s => {
val r = for {
r1 <- s.s1f1
r2 <- s.s1f2
} yield r1 + r2
r.run(map) + i
})
}
Ok, to use Service1_2.s12f1 I must have map in the parameter list:
object s1 extends Service1_1
object s2 extends Service1_2
val r = s2.s12f1(3, Map("age"-> 1, "name"-> 2)).run(s1)
The question: how to implement Service1_2.s12f2
:
trait Service1_2 {
def s2f2 = ???
}
In order to be able to run it like:
s2.s2f2(2)
.run(s1)
.run(Map("age"-> 1, "name"-> 2))
The main idea is to postpone passing of dependency to the execution. This should allow to get a better composition and deferred execution. How to get it work? What are the best practices with Readers, in case there are nested calls with such dependencies. For instance, imagine service, Service1_3
, which in one method, will use both Service1_2.s2f2
and Service1_1.s1f1
UPDATE, ok, I could implement it, but it looks, over complicated:
def s2f2(i:Int): Reader[Service1_1, Reader[Map[String,Int],Int]] =
Reader(s => Reader(map => {
val r = for {
r1 <- s.s1f1
r2 <- s.s1f2
} yield r1 + r2
r.run(map) + i
}))
The question, is there a better approach? Or at least syntax? Cause with several levels of dependency, it will look strange.