Как объединить Futures разных типов в одно Future без использования zip ()

Я хочу создать будущее типа Future[(Class1,Class2,Class3)] из кода ниже. Однако я нашел единственный способ сделать это - использовать zip (). Я считаю решение некрасивым и не оптимальным. Может кто-нибудь просветил меня.

val v = for (
    a <- {
        val f0:Future[Class1] = process1
        val f1:Future[Class2] = process2
        val f2:Future[Class3] = process3
        f0.zip(f1).zip(f2).map(x => (x._1._1,x._1._2,x._2))
    } yield a  // Future[(Class1,Class2,Class3)]

Я также пытался использовать Future.sequence(List(f0, f1, f2)), но это не сработает, так как новое будущее будет иметь тип Future[List[U]], где U - это lub Class1/2/3, тогда как мне нужен 3-кортеж, сохраняющий исходные типы


person Peter Lerche    schedule 22.06.2012    source источник
comment
Помимо ответа @oxbow_lakes, вот общая интуиция для аппликативов: когда у вас есть функция f типа (A, B, ...) => Z и вы хотите поднять ее до функции типа (F[A], F[B], ...) => F[Z], вам нужен аппликативный. В вашем случае f = (_, _, _) и F = Future.   -  person missingfaktor    schedule 22.06.2012


Ответы (4)


Если вы используете akka, посмотрите на поток данных: http://doc.akka.io/docs/akka/2.0.2/scala/dataflow.html

вам нужно использовать плагин Delimited Continuations (но с sbt это легко), а затем что-то вроде:

val f:Future[(Class1,Class2,Class3)] = flow {
  val f0 = process1
  val f1 = process2
  val f2 = process3
  (f0(), f1(), f2())
}

должен компилироваться.

в build.sbt:

autoCompilerPlugins := true

addCompilerPlugin("org.scala-lang.plugins" % "continuations" % "2.9.1")
person Ido Tamir    schedule 22.06.2012

Вы также можете использовать кошек:

import cats._
import cats.instances.future._

есть несколько полезных способов сделать это:

Первый более универсальный вариант:

Applicative[Future].map3(f0, f1, f2){ 
  (f0r, f1r, f2r) => //do something with results
}

и проще :), который просто вернет кортеж Future [(f0.type, f1.type, f2.type)

Applicative[Future].tuple3(f0, f1, f2)
person Scalway    schedule 10.04.2018

person    schedule
comment
Разве это не приведет к тому, что вычисления будут выполняться последовательно, а не параллельно? - person huynhjl; 22.06.2012
comment
Нет, если бы вы поместили вызовы processX внутрь for-computing, это было бы так, поскольку будет использоваться flatMap. Поскольку fX - это Future, это означает, что processX начнет вычисление и немедленно вернет Future. - person Viktor Klang; 23.06.2012
comment
вау, гениально! Исходя из опыта объектно-ориентированного проектирования, я так отстал в функциональном программировании и будущем ... у вас есть какие-нибудь шпаргалки для всех этих сопоставлений? :) - person Zennichimaro; 20.10.2017
comment
@Zennichimaro Некоторые из этих шаблонов я описал в своем блоге: viktorklang.com/blog - person Viktor Klang; 21.10.2017

person    schedule
comment
oxbow_lakes Я не уверен, что понимаю: разве Scalaz не должен включать синтаксис по умолчанию? Он предоставляет только конструктор Applicative, но не предоставляет уже созданный аппликативный модуль для Future или других стандартных типов Scala? - person Sebastien Lorber; 30.03.2017