0

I have hit a problem withe my for comprehension as follows:


  def doSomething(): F[String] = {

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

  }

The function doSomeWork looks like:

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

and the function doSomeOtherWork work looks like:

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

So when I try to compile I hit the following error:

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

Am i not allowed to mix F[] and Future inside a for comp like this?

Mojo
  • 1,152
  • 1
  • 8
  • 16

2 Answers2

5

No, you can't.
A for comprehension is just sugar syntax for calls to flatMap & map. And those only work on the same monad.

The best you can do, if you can not change doSomeWork to return an F, is to convert your futures into Fs on the for.

Here is an example of how you may do that.
(I had to invent many details because your questions was very vague)

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 ()

Tested with cats-effect 2.0.0.

0

No, this is not possible. Since a for comprehension is just syntactic sugar for map and flatMap calls, your program actually looks like this:

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

And since Future.flatMap expects a function returning a Future again, your program is rejected by the compiler.

cbley
  • 4,538
  • 1
  • 17
  • 32