Вот простой пример сервиса, методы которого возвращают читателя:
trait Service1_1{
def s1f1:Reader[Map[String,Int],Int] =
Reader(_("name"))
def s1f2:Reader[Map[String,Int],Int] =
Reader(_("age"))
}
Вот сервис-потребитель, который принимает параметр map и также возвращает сам ридер:
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
})
}
Хорошо, чтобы использовать Service1_2.s12f1, у меня должна быть карта в списке параметров:
object s1 extends Service1_1
object s2 extends Service1_2
val r = s2.s12f1(3, Map("age"-> 1, "name"-> 2)).run(s1)
Вопрос: как реализовать Service1_2.s12f2
:
trait Service1_2 {
def s2f2 = ???
}
Для того, чтобы иметь возможность запустить его как:
s2.s2f2(2)
.run(s1)
.run(Map("age"-> 1, "name"-> 2))
Основная идея - отложить передачу зависимости к исполнению. Это должно позволить получить лучшую композицию и отложенное исполнение. Как заставить это работать? Каковы лучшие практики с Readers, если есть вложенные вызовы с такими зависимостями. Например, представьте себе сервис Service1_3
, который в одном методе будет использовать Service1_2.s2f2
и Service1_1.s1f1
ОБНОВЛЕНИЕ Хорошо, я мог бы реализовать это, но выглядит сложнее:
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
}))
Вопрос, есть ли лучший подход? Или хотя бы синтаксис? Потому что с несколькими уровнями зависимости это будет выглядеть странно.