Help! My Monads are Nesting!

Nov 17 2016

Do you build reactive applications using Scala? Then chances are you’ve had to deal with a Future[Monad[T]], where Monad could be Option, Either, or something more wonderful like Or. While these monads do nest as expected, the syntax and code flow can start to get pretty messy (motivating example below).

Enter FutureOr! This utility makes it super-simple to sequence several Future[Or[T]] calls. It’s also fairly easy to implement, so you could easily clone this and customize for your favorite nested monad combination.

//three service calls which return Future[Or[T]] and depend on the previous call
trait IntService{
  def callA: Future[Int Or One[ErrorMessage]]
  def callB(int a): Future[Int Or One[ErrorMessage]]
  def callC(int b): Future[Int Or One[ErrorMessage]]
}
val service: IntService = ...

//without FutureOr, really ugly!  I wouldn't wish this on my worst enemy!
val result: Future[Int Or One[ErrorMessage]] = 
     service.callA.flatMap{ a =>
          a.flatMap{
               case Good(goodA) => service.callB(goodA).flatMap { b =>
                    b.flatMap {
                         case Good(goodB) => service.callC(goodB)
                         case Bad(e) => Future.successful(Bad(e))
                    }
               }
               case Bad(e) => Future.successful(Bad(e))
          }
     }


//with FutureOr, so much better!
val result: Future[Int Or One[ErrorMessage]] =
     (for {
          a <- FutureOr(service.callA)
          b <- FutureOr(service.callB(a))
          c <- FutureOr(service.callC(b)
     } yield c).future

Share: Twitter Facebook LinkedIn

comments powered by Disqus