Смешивая будущее и F [] внутри для понимания - PullRequest
0 голосов
/ 30 января 2020

Я столкнулся с проблемой для понимания следующим образом:


  def doSomething(): F[String] = {

    for {
      _ <- Future.traverse(items)(item => doSomeWork(item)) // Future[]
      _ <- doSomeOtherWork(42)  //F[]
    } yield (())

  }

Функция doSomeWork выглядит следующим образом:

  def doSomeWork(item: Item): Future[Unit] =
         // some work done inside a Future
    )

, а функция doSomeOtherWork выглядит следующим образом :

    def doSomeOtherWork(i : Int): F[Unit]

Поэтому, когда я пытаюсь скомпилировать, я сталкиваюсь со следующей ошибкой:

[error]  found   : F[Int]
[error]  required: scala.concurrent.Future[?]
[error]       
[error]         ^
[error] type mismatch;
[error]  found   : scala.concurrent.Future[Nothing]
[error]  required: F[Int]

Разве мне не разрешено смешивать F [] и Future внутри для такого компа? 1015 *

Ответы [ 2 ]

5 голосов
/ 30 января 2020

Нет, вы не можете.
A для понимания - это просто сахарный синтаксис для вызовов на flatMap & map. И они работают только с одной и той же монадой.

Лучшее, что вы можете сделать, если вы не можете изменить doSomeWork, чтобы вернуть F, - это конвертировать ваше фьючерсы в Fs в for.

Вот пример того, как вы можете это сделать.
(мне пришлось придумать много деталей, потому что ваши вопросы были очень расплывчаты)

import cats.effect.{Async, ContextShift, Sync}
import cats.instances.list._ // Provides the Foldable[List] instance into scope.
import cats.syntax.flatMap._ // Provides the flatMap method (used in the for).
import cats.syntax.foldable._ // Provides the traverse_ method.
import cats.syntax.functor._ // Provides the map method (used in the for).
import scala.concurrent.Future

final case class Item(id: Int, name: String)

def doSomeWork(item: Item): Future[Unit] = ???

def doSomeOtherWork[F[_] : Sync](i: Int): F[Unit] = ???

def doSomething[F[_]](items: List[Item])(implicit F: Async[F], cs: ContextShift[F]): F[Unit] =
  for {
    _ <- items.traverse_(item => Async.fromFuture(F.delay(doSomeWork(item))))
    _ <- doSomeOtherWork(42)
  } yield ()

Проверено с эффект кошки 2.0.0.

0 голосов
/ 30 января 2020

Нет, это невозможно. Поскольку для понимания это просто syntacti c сахар для вызовов map и flatMap, ваша программа на самом деле выглядит следующим образом:

(_: Future[Int]).flatMap(doSomeOtherWork).map(())

И поскольку Future.flatMap ожидает функцию, возвращающую Future снова, ваша программа отклоняется компилятором.

...