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 ֜ඳ: ᎣΡڹ΄ͩ;ΨΔͶ憝͞ͼ͚Ρ͡Ο
IN PRACTICE // create a `Functor[Future[List]]` val futureListF = Functor[Future].compose(Functor[List]) val data: Future[List[Int]] = Future(List(1, 2, 3)) // only one map! futureListF.map(data)(_ + 1) // Future(List(2, 3, 4)) 䋚檭΄πЄϖ
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)) F[F[A]] Ψ憎͵Ο flatMap ;͜͠
A LESS CONTRIVED EXAMPLE def getUser(name: String): Future[User] def getAddress(user: User): Future[Address] val getCity: Future[String] = getUser("Gabriele").flatMap( gab => getAddress(gab).map( address => address.city ) )
EVENTUALLY val city: Future[Option[String]] = for { gab <- getUser("Gabriele") address <- getAddress(gab.get) // } yield address.get.city // get ֵ͵ΟύϮ
WHAT WE WOULD REALLY WANT val city: Future[Option[String]] = for { gab <- maybeUser <- getUser("Gabriele") address <- maybeAddress <- getAddress(gab) } yield address.city ཿͭ͡͵Θ΄
AND USE val f: FutOpt[String] = for { gab <- FutOpt(getUser("Gabriele")) address <- FutOpt(getAddress(gab)) } yield address.city // ! val city: Future[Option[String]] = f.value ֵͼΕΡ
I KNOW THE TRICK! val lameNickname: OptionT[Future, String]] = for { user <- OptionT(getUser("123")) age <- OptionT(getAge(user)) // sorry, nope name <- OptionT(getNickname(user)) // sorry, neither } yield s"$name$age" ͜Δ͚͚ͥ͡
DO YOU EVEN LIFT, BRO? val lameNickname: OptionT[Future, String]] = for { user <- OptionT(getUser("123")) age <- OptionT.liftF(getAge(user)) name <- OptionT.fromOption(getNickname(user)) } yield s"$name$age" lift (ᒶϕϹ) ;ͭ͡ͼ͚?
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)) ϯϗϖ䄜䟵ৼ΅ API ڊ͚ͫΞͯ͜Ρ
FREE MONADS / TAGLESS FINAL > clearly separate structure and interpretation > effects are separated from program definition http://typelevel.org/cats/datatypes/freemonad.html https://blog.scalac.io/exploring-tagless-final.html ᛔኧϯϗϖ΅ϤϺν϶ϭਧ嬝͡Ο֢አΨړ櫝ͯΡ
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 Eff ΅ϯϗϖ䄜䟵ৼ΄դ๊;ΡΘ΄ͽ̵֢አΨ樛හࣳጱ䜷͜