2011-07-14 6 views
37

en el mapa de Scala y flatMap normales son diferentes en que flatMap devolverá un iterable de los datos aplastados en una lista. Sin embargo, en la documentación de Akka, el mapa y el mapa plano parecen hacer algo diferente.En Scala Akka futuros, ¿cuál es la diferencia entre map y flatMap?

http://akka.io/docs/akka/1.1/scala/futures.html

dice "Normalmente esto funciona bastante bien, ya que significa que hay muy poca sobrecarga de ejecutar una función rápida. Si hay una posibilidad de que la función de tomar una cantidad no trivial de tiempo para procesarlo podría ser mejor que esto se haga al mismo tiempo, y para ello se utilice flatMap:"

val f1 = Future { 
    "Hello" + "World" 
} 

val f2 = f1 flatMap {x => 
    Future(x.length) 
} 

val result = f2.get() 

Puede alguien explicarme cuál es la diferencia entre el mapa y flatMap aquí en futuros Akka?

+0

Creo que esto ayuda a entenderlo mejor - por qué usamos flatMap http://raichoo.blogspot.com/2011/07/from-functions-to-monads-in-scala.html – Phil

Respuesta

59

En Scala "normal" (como se dice), el mapa y la flatMap no tienen nada que ver con listas de verificación de opciones (por ejemplo).

Alexey le dio la respuesta correcta. Ahora, si quiere saber por qué necesitamos ambos, permite la buena sintaxis for al componer futuros. Teniendo en cuenta algo como:

val future3 = for(x <- future1; 
        y <- future2) yield (x + y) 

El compilador reescribe como:

val future3 = future1.flatMap(x => future2.map(y => x+y)) 

Si sigue la firma del método, debería ver que la expresión devolverá algo del tipo Future[A].

Supongamos ahora sólo se utilizó un mapa, el compilador podría haber hecho algo como:

val future3 = future1.map(x => future2.map(y => x+y)) 

Sin embargo, el resultado whould han sido de tipo Future[Future[A]]. Es por eso que debes aplanarlo.

para aprender sobre el concepto detrás, aquí es uno de los mejores que he leído introducción:

http://www.codecommit.com/blog/ruby/monads-are-not-metaphors

+7

No me di cuenta de que aplanar podía aplanar tipos, mi idea era que aplanaba una lista de objetos en una sola lista. Así que desde mi "viejo" pensamiento, pensé que simplemente caminé la lista y la aplané. En realidad, aplanar puede aplanar tipos como dijiste Futuro [Futuro [A]] es análogo a Lista [Lista [A]]. Una vez que hice este paso, puedo entenderlo mejor. – Phil

+0

¡Muchas gracias! ¡Especialmente para la publicación! ¡Ese "punto y coma" hizo explotar mi mente! – noru

34

¿Puede alguien explicar por favor cuál es la diferencia entre el mapa y el mapa plano aquí en Akka futures?

El tipo, básicamente:

flatMap[A](f: T => Future[A]): Future[A] 

map[A](f: T => A): Future[A] 
+0

Exactamente, esto tiene relevancia cuando tiene un método que devuelve un futuro [A], pero en lugar de obtener un futuro [futuro [A]], quiere el futuro [A]. – Mahesh

+0

Si desea conocer más sobre los principios de diseño de 'map' y' flatMap', que están enraizados en la abstracción de Monad, sugiero esta conferencia del creador de Scala, Martin Odersky https://www.coursera.org/ learn/progfun2/lecture/98tNE/lecture-1-4-monads –

1

estoy pegando la aplicación de los dos métodos aquí. la diferencia de términos en inglés está por debajo y devuelve el resultado de la función que el nuevo futuro

  /** Creates a new future by applying a function to the successful result of 
     * this future. If this future is completed with an exception then the new 
     * future will also contain this exception. 
     * 
     * $forComprehensionExamples 
     */ 
     def map[S](f: T => S)(implicit executor: ExecutionContext): Future[S] = { // transform(f, identity) 
     val p = Promise[S]() 
     onComplete { v => p complete (v map f) } 
     p.future 
     } 

     /** Creates a new future by applying a function to the successful result of 
     * this future, and returns the result of the function as the new future. 
     * If this future is completed with an exception then the new future will 
     * also contain this exception. 
     * 
     * $forComprehensionExamples 
     */ 
     def flatMap[S](f: T => Future[S])(implicit executor: ExecutionContext): Future[S] = { 
     import impl.Promise.DefaultPromise 
     val p = new DefaultPromise[S]() 
     onComplete { 
      case f: Failure[_] => p complete f.asInstanceOf[Failure[S]] 
      case Success(v) => try f(v) match { 
      // If possible, link DefaultPromises to avoid space leaks 
      case dp: DefaultPromise[_] => dp.asInstanceOf[DefaultPromise[S]].linkRootOf(p) 
      case fut => fut.onComplete(p.complete)(internalExecutor) 
      } catch { case NonFatal(t) => p failure t } 
     } 
    p.future 
    } 

Desde la implementación de la diferencia es que flatMap realidad llama a la función con resultado cuando la promesa completa.

case Success(v) => try f(v) match 

Para leer un gran artículo: http // danielwestheide.com/blog/2013/01/16/The-neófitos-guía-a-scala-parte-9-promesas-y-futuros-in- práctica.html

Cuestiones relacionadas