Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Combining `OptionT` and `EitherT` to handle `Future[Either[Error, Option[T]]]`

I want to use Cats EitherT and OptionT to handle the type Future[Either[Error, Option[T]]. Suppose the following methods:

def findTeacher(id: Int): Future[Either[String, Option[Teacher]]]
def findSchool(teacher: Teacher): Future[Either[String, Option[School]]]

Now if I want to call them subsequently in a for-comprehension I can use EitherT and OptionT like this:

def getSchoolByTeacherId(id: Int): Future[Either[String, Option[School]]] = {
  val result = for {
    maybeTeacher <- EitherT(findTeacher(id))
    schoolF = maybeTeacher.map(findSchool).getOrElse(Future.successful(Right(None)))
    school <- EitherT(schoolF)
  } yield {
    school
  }

  result.value
}

I wonder if it's possible to make it more concise maybe by combining OptionT with EitherT?

like image 333
Amir Karimi Avatar asked Dec 28 '17 16:12

Amir Karimi


1 Answers

If understand your question correctly, you want to build a combined monad-transformer of EitherT and OptionT. Using Cats you may try something like this:

type FutureEither[X] = EitherT[Future, String, X]
type OResult[X] = OptionT[FutureEither, X]

object OResult {

  implicit def apply[A](value: Future[Either[String, Option[A]]]): OResult[A] = OptionT[FutureEither, A](EitherT(value))

  implicit class OResultOps[A](val value: OResult[A]) extends AnyVal {
    @inline
    def directValue: Future[Either[String, Option[A]]] = value.value.value
  }

}

And then you may re-write your getSchoolByTeacherId as

import OResult._
def getSchoolByTeacherId(id: Int): Future[Either[String, Option[School]]] = {
  val result = for {
    teacher <- OResult(findTeacher(id))
    school <- findSchool(teacher)
  } yield school

  result.directValue
}

Unfortunately, even though OResult.apply is implicit you still have to write it explicitly in the first line of your for-comprehension but this allows skipping it on the further lines.

like image 128
SergGr Avatar answered Sep 28 '22 02:09

SergGr