kciesielski
kciesielski

Reputation: 1188

How to stack applicative functors in Scala

Applicative functors are often mentioned as an alternative to monads when your computation steps are independent. One of their often-mentioned advantages is that you don't need transformers when you want to stack applicatives, because F[G[X]] is always also an applicative. Let's say I have following functions:

def getDataOption(): Option[Data]
def getUserFuture(): Future[User]
def process(data: Data, user: User)

I would like to have elegant stacking in order to get a Future[Option[User]] and Future[Option[Data]] and map that with process.

So far I only came up with this (using Cats):

Applicative[Future]
  .compose[Option]
    .map2(
      Applicative[Future].pure(getDataOption()),
      getUserFuture().map(Applicative[Option].pure))(process)

but I'm sure it's far from ideal. Is there a more elegant and generic way to achieve the same?

Upvotes: 25

Views: 1058

Answers (1)

Eric
Eric

Reputation: 15557

The most difficult thing is type inference here. This is the best I could do

  // for the Applicative[Future[Option[?]]
  import cats.Applicative

  implicit val fo = {
    import cats.std.future._
    import cats.std.option._
    Applicative[Future].compose[Option]
  }

  // for the |@| syntax
  import cats.syntax.cartesian._

  // to guide type inference
  type FutureOption[A] = Future[Option[A]]

  ((Future(getDataOption): FutureOption[Data]) |@|
    getUserFuture.map(Option.apply)).map(process _)

Upvotes: 3

Related Questions