简体   繁体   中英

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 ?

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM