Search code examples
scalamonadsmonad-transformersscala-cats

Stacking M, Either and Writer


I'm currently stacking Futures and Eithers using EitherT:

type ErrorOr[A] = Either[Error, A]

def getAge: Future[ErrorOr[Int]] = ???
def getDob(age: Int): ErrorOr[LocalDate] = ???

for {
  age <- EitherT(getAge)
  dob <- EitherT.fromEither[Future](getDob(age))
} yield dob

I would now like to introduce the Writer monad i.e.

type MyWriter[A] = Writer[Vector[String], ErrorOr[A]]

def getAge: Future[MyWriter[Int]] = ???
def getDob(age: Int): MyWriter[LocalDate] = ???

My question is, what is the best way to sequence the getAge and getDob calls? I know monads can be stacked i.e. Future -> Writer -> Either but can I continue to use EitherT in this scenario? if so how?


Solution

  • Yeah, you can continue using both using the WriterT monad transformers like this:

    type FutureErrorOr[A] = EitherT[Future, Error, A]
    type MyStack[A] = WriterT[FutureErrorOr, Vector[String], A]
    

    If you unpack this type, it's analogous to Future[Either[Error, Writer[Vector[String], A]]

    Now the tricky part is lifting your functions into this base monad, so here are some examples:

    def getAge: FutureErrorOr[Int] = ???
    def getDob(age: Int): ErrorOr[LocalDate] = ???
    
    for {
      age <- WriterT.liftF(getAge)
      dob <- WriterT.liftF(EitherT.fromEither(getDob(age)))
    } yield dob
    

    To make this easier you can have a look at cats-mtl.