How to stack applicative functors in Scala
Asked Answered
R

1

25

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?

Rolf answered 20/4, 2016 at 18:6 Comment(0)
S
3

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 _)
Swen answered 21/4, 2016 at 7:11 Comment(6)
Thanks, I guess something similar to the Eff/Emm monad would be handy to strip the boilerplate, if it's possible.Rolf
I think that the easiest thing to do here is might be to just grab OptionT, but you probably can do (send(getDataOption) |@| send(getUserFuture)).map(process _).runOption.detach.run to get a final Future[Option[A]] with Eff (and something similar with Emm).Swen
Right. However, I wanted to stay with applicatives. The point of my question was to see a practical application of praised applicative property, that they can be stacked without using transformers.Rolf
They can indeed, but they might not be the easiest thing to do in Scala :-(Swen
Looks like you just added a very nice applicative support to Eff. Thanks, Eric! atnos-org.github.io/eff-cats/…Rolf
I am still amazed that it works at all to be honest! So please report if you find any issues.Swen

© 2022 - 2024 — McMap. All rights reserved.