Reader Monad для внедрения зависимостей: множественные зависимости, вложенные вызовы

Когда спрошено о Внедрении Зависимости в Scala, довольно много ответов указывают на то, что вы используете Монаду Читателя, либо Scalaz, либо просто свой собственный. Есть ряд очень четких статей, описывающих основы подхода (например,Разговор рунара, Блог Джейсона), но мне не удалось найти более полный пример, и я не вижу преимуществ этого подхода по сравнению, например, с. более традиционный «ручной» DI (см.руководство, которое я написал). Скорее всего, я упускаю какой-то важный момент, отсюда и вопрос.

В качестве примера давайте представим, что у нас есть эти классы:

trait Datastore { def runQuery(query: String): List[String] }
trait EmailServer { def sendEmail(to: String, content: String): Unit }

class FindUsers(datastore: Datastore) {
  def inactive(): Unit = ()
}

class UserReminder(findUser: FindUsers, emailServer: EmailServer) {
  def emailInactive(): Unit = ()
}

class CustomerRelations(userReminder: UserReminder) {
  def retainUsers(): Unit = {}
}

Здесь я моделирую вещи, используя классы и параметры конструктора, что очень хорошо сочетается с «традиционными» подходами DI, однако у этого дизайна есть несколько хороших сторон:

каждая функциональность имеет четко перечисленные зависимости. Мы как бы предполагаем, что зависимости действительно необходимы для правильной работы функциональностизависимости скрыты между функциями, напримерUserReminder понятия не имеет, чтоFindUsers нуждается в хранилище данных. Функциональные возможности могут быть даже в отдельных единицах компиляциимы используем только чистую Scala; реализации могут использовать неизменяемые классы, функции высшего порядка, методы «бизнес-логики» могут возвращать значения, заключенные вIO монада, если мы хотим запечатлеть эффекты и т. д.

Как это можно смоделировать с помощью монады Reader? Было бы хорошо сохранить приведенные выше характеристики, чтобы было ясно, какие зависимости нужны каждой функциональности, и скрывать зависимости одной функциональности от другой. Обратите внимание, что с помощьюclasses - это больше детали реализации; возможно, «правильное» решение с использованием монады Reader будет использовать что-то еще.

Я нашелнесколько связанный вопрос что предполагает либо:

использование единого объекта среды со всеми зависимостямииспользуя местную средуузор "парфе"карты с индексированными типами

Однако, помимо того, что (но это субъективно) немного слишком сложно, как для такой простой вещи, во всех этих решениях, например.retainUsers метод (который вызываетemailInactive, который вызываетinactive чтобы найти неактивных пользователей) необходимо знать оDatastore зависимость, чтобы можно было правильно вызывать вложенные функции - или я не прав?

В каких аспектах использование Reader Monad для такого «бизнес-приложения» будет лучше, чем просто использование параметров конструктора?

Ответы на вопрос(2)

Ваш ответ на вопрос