Финальный эффект распространения без тегов
Шаблон tagless-final позволяет нам писать чистые функциональные программы, которые явно описывают эффекты, которые им требуются.
Однако масштабирование этого шаблона может стать сложной задачей. Я постараюсь продемонстрировать это на примере. Представьте себе простую программу, которая читает записи из базы данных и выводит их на консоль. Нам потребуются некоторые пользовательские классы типов Database
а также Console
, в дополнение к Monad
от кошек / скалаз для того, чтобы составить их:
def main[F[_]: Monad: Console: Database]: F[Unit] =
read[F].flatMap(Console[F].print)
def read[F[_]: Functor: Database]: F[List[String]] =
Database[F].read.map(_.map(recordToString))
Проблема начинается, когда я хочу добавить новый эффект к функции во внутренних слоях. Например, я хочу, чтобы мой read
функция для записи сообщения, если записи не найдены
def read[F[_]: Monad: Database: Logger]: F[List[String]] =
Database[F].read.flatMap {
case Nil => Logger[F].log("no records found") *> Nil.pure
case records => records.map(recordToString).pure
}
Но теперь я должен добавить Logger
ограничение для всех абонентов read
вверх по цепочке. В этом надуманном примере это просто main
Но представьте, что это несколько слоев сложного реального приложения.
Мы можем посмотреть на эту проблему двумя способами:
- Мы можем сказать, что это хорошо, что было ясно о наших эффектах, и мы точно знаем, какие эффекты нужны для каждого слоя
- Мы также можем сказать, что это утечка деталей реализации -
main
не заботится о регистрации, он просто нуждается в результатеread
, Кроме того, в реальных приложениях вы видите действительно длинные цепочки эффектов в верхних слоях. Это похоже на запах кода, но я не могу понять, какой другой подход я могу использовать.
Хотелось бы получить ваше понимание этого.
Благодарю.
1 ответ
Можно также сказать, что это приводит к утечке деталей реализации - main не заботится о ведении журнала, ему просто нужен результат чтения. Кроме того, в реальных приложениях вы видите действительно длинные цепочки эффектов в верхних слоях. Это похоже на запах кода, но я не могу понять, какой другой подход я могу использовать.
Я действительно верю в обратное. Одним из ключевых обещаний чистого FP является эквациональное рассуждение как средство извлечения реализации метода из его сигнатуры. Если read
для ведения бизнеса нужен эффект регистрации, тогда он обязательно должен быть декларативно выражен в подписи. Еще одним преимуществом явного описания ваших эффектов является тот факт, что, когда они начинают накапливаться, возможно, нам нужно переосмыслить, что делает этот конкретный метод, и разделить его на более мелкие компоненты? Или этот эффект действительно должен быть использован здесь?
Это правда, что эффекты складываются, но, как упомянуто в комментариях @TravisBrown, обычно это самое высокое место в стеке вызовов, которое должно "страдать от последствий", фактически предоставляя все неявные доказательства для всего дерева вызовов.