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?
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.