THIS TALK: WHAT AND WHY What: The talk I wished I attended before banging my head against this Why: Because I still remember how it was before knowing it @gabro27 Scala Days 2017 - Copenhagen
THE PROBLEM val x: Future[List[Int]] = ??? futureList.map(list => list.map(f)) ^ ^ |________________| 2 maps 1 function @gabro27 Scala Days 2017 - Copenhagen
futureList.map(f) // not really valid scala | // but you get the point | Functor[Future[List]].map(futureList)(f) @gabro27 Scala Days 2017 - Copenhagen
IN OTHER WORDS when life gives you F[F[A]] you probably wanted flatMap e.g. val f: Future[Future[Int]] = Future(42).map(x => Future(24)) val g: Future[Int] = Future(42).flatMap(x => Future(24)) @gabro27 Scala Days 2017 - Copenhagen
BACK TO THE REAL WORLD def getUser(name: String): Future[Option[User]] // better def getAddress(user: User): Future[Option[Address]] @gabro27 Scala Days 2017 - Copenhagen
flatMap FOR Future[Option[A]] val city: Future[Option[String]] = for { maybeUser maybeCity case Some(user) => getAddress(user).map(_.map(_.city)) case None => Future.successful(None) } } yield maybeCity @gabro27 Scala Days 2017 - Copenhagen
AND USE val f: FutOpt[String] = for { gab address } yield address.city // ! val city: Future[Option[String]] = f.value @gabro27 Scala Days 2017 - Copenhagen
HOW ABOUT case class MyError(msg: String) type ResultT[F[_], A] = EitherT[F, MyError, A]] type FutureResult[A] = ResultT[Future, A] @gabro27 Scala Days 2017 - Copenhagen
TIP #2 keep your transformers for youself def publicApiMethod(x: String): OptionT[Future, Int] = ! def publicApiMethod(x: String): Future[Option[Int]] = " by the way val x: OptionT[Future, Int] = OptionT(Future(Option(42))) val y: Future[Option[Int]] = x.value // Future(Option(42)) @gabro27 Scala Days 2017 - Copenhagen
TIP #3 ! Perf! Wrapping/unwrapping isn't cheap, so if you're concerned about performance, consider benchmarking your code. @gabro27 Scala Days 2017 - Copenhagen
TIP #4 Use them as a ""local optimization"". In case your problem is not "local", consider alternative approaches. @gabro27 Scala Days 2017 - Copenhagen
MONAD TRANSFORMERS: TAKEAWAYS > they end with T > F[G[X]] becomes GT[F[_], X] > can be stacked undefinitely, but gets awkward > they are a tool for working with stacked monads @gabro27 Scala Days 2017 - Copenhagen
FREE MONADS > clearly separate structure and interpretation > effects are separated from program definition http://typelevel.org/cats/datatypes/freemonad.html @gabro27 Scala Days 2017 - Copenhagen
EFF https://github.com/atnos-org/eff-cats "Extensible effects are an alternative to monad transformers for computing with effects in a functional way" based on Freer Monads, More Extensible Effects by Oleg Kiselyov @gabro27 Scala Days 2017 - Copenhagen