Question

I have four types A,B, C and D, an initial value x of the type Future[Option[A]] and three functions: f1: A => Option[B] , f2: B => Future[Option[C]] and f3: C => D.

How can I write a for comprehension starting with x that results in a value of the type Future[Option[D]] that would be the "composition" of the three functions?

Was it helpful?

Solution

You can use monad transformers (from Scalaz) for this:

import scalaz.OptionT
import scalaz.std.option._
import scalaz.syntax.monad._
val result: Future[Option[D]] = (for {
  a <- OptionT(x)
  b <- OptionT(f1(a).point[Future])
  c <- OptionT(f2(b))
} yield f3(c)).run

You'll need a monad instance for Future; there's one in scalaz-contrib.

OTHER TIPS

This isn't necessarily the best solution, but it's what I've come up with. I started by trying to find a common type to work with

type N[X, Y] = Option[X] => Future[Option[Y]]

...then converting f1, f2, and f3 to that common type.

val f1: (A => Option[B]) = ???
val f1N: N[A, B] = {
  case None => Future.successful(None)
  case Some(a) => Future.successful(f1(a))
}

val f2: (B => Future[Option[C]]) = ???
val f2N: N[B, C] = {
  case None => Future.successful(None)
  case Some(b) => f2(b)
}

val f3: C => D = ???
val f3N: N[C, D] = {
  case None => Future.successful(None)
  case Some(c) => Future.successful(Some(f3(c)))
}

Now that I've created f1N, f2N, and f3N, I can use them in a nice-looking for-comprehension.

val y: Future[Option[D]] = for {
  aOpt <- x
  bOpt <- f1N(aOpt)
  cOpt <- f2N(bOpt)
  dOpt <- f3N(cOpt)
} yield dOpt
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top