Фьючерсы в Scala действительно функциональны?
Я читаю этот пост в блоге, который утверждает Futures
не являются "функциональными", так как они являются просто обертками для побочных вычислений. Например, они содержат вызовы RPC, HTTP-запросы и т. Д. Это правильно?
В блоге приведен следующий пример:
def twoUsersFeed(a: UserHandle, b: UserHandle)
(implicit ec: ExecutionContext): Future[Html] =
for {
feedA <- usersFeed(a)
feedB <- usersFeed(b)
} yield feedA ++ feedB
you lose the desired property: consistent results (the referential transparency). Also you lose the property of making as few requests as possible. It is difficult to use multi-valued requests and have composable code.
Боюсь, я не понимаю. Не могли бы вы объяснить, как мы теряем consistent result
в этом случае?
1 ответ
Сообщение в блоге не в состоянии провести надлежащее различие между Future
сам и способ, которым это обычно используется, IMO. Вы можете написать чисто функциональный код с Future
если бы ты только написал Future
s, которые называются чистыми, полными функциями; такой код будет ссылочно прозрачным и "функциональным" во всех отдаленно разумных смыслах этого слова.
Что правда в том, что Future
s дают вам ограниченный контроль над побочными эффектами, если вы используете их с методами, которые имеют побочные эффекты. Если вы создаете Future
упаковка webClient.get
затем создаем Future
отправит вызов HTTP. Но это не факт о Future
это факт о webClient.get
!
В этом посте есть доля правды. Отделение выражения вашего вычисления от его выполнения полностью, например, с помощью бесплатной монады, может привести к более эффективному и более тестируемому коду. Например, вы можете создать "язык запросов", где вы выражаете такую операцию, как "получить фотографии профиля всех общих друзей А и Б", фактически не запуская его. Это облегчает проверку правильности вашей логики (потому что очень легко сделать, например, тестовую реализацию, которая может "запускать" одни и те же запросы - или даже просто проверять "объект запроса" напрямую) и, как я думаю, в блоге пытается предложить, означает, что вы можете, например, объединить несколько запросов для получения одного и того же профиля. (Это даже не просто проблема функционального программирования - некоторые ОО-книги имеют идею "шаблона команд" - хотя инструменты функционального программирования IME, такие как for
/yield
синтаксис делает работу намного проще). Принимая во внимание, что если все, что у вас есть, это fetchProfile
метод, который при запуске немедленно запускает HTTP-запрос, а затем, если ваша логика кода запрашивает один и тот же профиль дважды, нет способа избежать выборки одного и того же профиля дважды.
Но это не совсем Future
По сути, и IMO, этот пост в блоге больше сбивает с толку, чем полезно.