Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import scala.concurrent.ExecutionContext
- import scala.concurrent.Future
- trait Example[A] {
- type B
- type C
- def doA(a: A): Future[Option[B]]
- def doB(b: B): Future[Option[C]]
- def doC(c: C): Future[Unit]
- // the toLists here are very ugly, but unfotunately needed. This is a deficiency in the stdlib.
- // Perhaps an MR would be accepted upstream to make it work with Option
- def doIt(a: A)(implicit ec: ExecutionContext): Future[Unit] = for {
- bOpt <- doA(a)
- cOpt <- Future.traverse(bOpt.toList)(doB)
- _ <- Future.traverse(cOpt.toList.flatten)(doC)
- } yield ()
- }
- trait CatsExample[A] extends Example[A] {
- import cats.syntax.all.*
- // The cats library brings traverse (and flatTraverse) as extension methods
- // and they work with Option automatically.
- override def doIt(a: A)(implicit ec: ExecutionContext): Future[Unit] = for {
- bOpt <- doA(a)
- cOpt <- bOpt.flatTraverse(doB)
- _ <- cOpt.traverse(doC)
- } yield ()
- // Every other year or so, I switch preferences between for and plain flatMap
- def doItAlternativeNotation(a: A)(implicit ec: ExecutionContext): Future[Unit] =
- doA(a)
- .flatMap(_.flatTraverse(doB)) //flatTraverse does the flatten and the traverse in one go
- .flatMap(_.traverse_(doC)) //traverse_ here discards the result and makes it Unit
- }
- val ex = new CatsExample[Int] {
- type B = Int
- type C = Int
- def doA(a: Int): Future[Option[B]] = Future {
- println(s"doing a $a")
- Some(a).filter(_ >= 1)
- }
- def doB(b: B): Future[Option[C]] = Future {
- println(s"doing b $b")
- Some(b).filter(_ >= 10)
- }
- def doC(c: C): Future[Unit] = Future {
- println(s"doing c $c")
- }
- }
- val myOpt = Option(20)
- implicit val global: ExecutionContext = scala.concurrent.ExecutionContext.global
- myOpt.foreach(ex.doIt)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement