class: center, middle # Advanced Scala ## What's in a for? Neville Li @sinisa_lyh Sep 2016 --- # Map and flatMap ```scala trait List[A] { map(f: A => B): List[B] flatMap(f: A => GenTraversableOnce[B]): List[B] } ``` -- ```scala trait Option[A] { map(f: A => B): Option[B] flatMap(f: A => Option[B]): Option[B] } ``` -- ```scala trait Future[A] { map(f: A => B): Future[B] flatMap(f: A => Future[B]): Future[B] } ``` --- # Handling options ```scala def plus(x: Option[Int], y: Option[Int]): Option[Int] = if (x.isDefined && y.isDefined) Some(x.get + y.get) else None ``` -- ```scala def plus(x: Option[Int], y: Option[Int], z: Option[Int]): Option[Int] = if (x.isDefined && y.isDefined && z.isDefined) Some(x.get + y.get + z.get) else None ``` -- ### Ugh... -- ```scala def plus(x: Option[Int], y: Option[Int]): Option[Int] = x.flatMap(a => y.map(b => a + b)) ``` ```scala def plus(x: Option[Int], y: Option[Int], z: Option[Int]): Option[Int] = x.flatMap(a => y.flatMap(b => z.map(c => a + b + c))) ``` -- ### Not much better... --- # For to the rescue ```scala for(x <- c1; y <- c2; z <-c3) {...} ``` is translated to -- ```scala c1.foreach(x => c2.foreach(y => c3.foreach(z => {...}))) ``` -- - - - ```scala for(x <- c1; y <- c2; z <-c3) yield {...} ``` is translated to -- ```scala c1.flatMap(x => c2.flatMap(y => c3.map(z => {...}))) ``` - - - -- [http://docs.scala-lang.org/tutorials/FAQ/yield.html]() --- # List comprehensions ```scala scala> for (x <- List("a", "b", "c"); y <- List(1, 2, 3)) yield (x + y) res0: List[String] = List(a1, a2, a3, b1, b2, b3, c1, c2, c3) ``` -- equals ```scala List("a", "b", "c").flatMap(x => List(1, 2, 3).map(y => x + y)) ``` -- - - - ```scala def plus(a: Option[Int], b: Option[Int], c: Option[Int]): Option[Int] = for (x <- a; y <- b; z <- c) yield (x + y + z) ``` -- equals ```scala a.flatMap(x => b.flatMap(y => (c.map(z => x + y + z)))) ``` --- # More list comprehensions ```scala val f1: Future[Response1] = backend1.request(payload) val f2: Future[Response2] = backend2.request(payload) def compute(r1: Response1, r2: Response2): Response = /* ... */ val response: Future[Reponse] = for { r1 <- f1 r2 <- f2 } yield (compute(r1, r2)) ``` Because `Future[T]` has `map` and `flatMap`. -- - - - ```scala val g: Gen[(Double, Double)] = for { x <- Gen.choose(-1.0, 1.0) y <- Gen.choose(-1.0, 1.0) } yield (x, y) ``` Because `Gen[T]` has `map` and `flatMap`. --- class: center, middle # The End ## Happy Yielding