Как складывать аппликативные функции в Scala
Аппликативные функторы часто упоминаются как альтернатива монадам, когда ваши этапы вычислений независимы. Одним из их часто упоминаемых преимуществ является то, что вам не нужны трансформаторы, если вы хотите укладывать аппликаторы, потому что F[G[X]]
всегда также является аппликативным. Скажем, у меня есть следующие функции:
def getDataOption(): Option[Data]
def getUserFuture(): Future[User]
def process(data: Data, user: User)
Я хотел бы иметь элегантную укладку, чтобы получить Future[Option[User]]
и Future[Option[Data]]
и сопоставить это с process
.
До сих пор я только придумал это (используя Кошек):
Applicative[Future]
.compose[Option]
.map2(
Applicative[Future].pure(getDataOption()),
getUserFuture().map(Applicative[Option].pure))(process)
но я уверен, что это далеко не идеально. Есть ли более элегантный и общий способ добиться того же?
Ответы
Ответ 1
Самое сложное - это вывод типа здесь. Это лучшее, что я мог сделать
// 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 _)