结合`OptionT`和`EitherT`来处理`Future [[Error,Option [T]]]`

Ami*_*imi 7 scala scalaz scala-cats

我想使用Cats EitherTOptionT处理该类型Future[Either[Error, Option[T]].假设有以下方法:

def findTeacher(id: Int): Future[Either[String, Option[Teacher]]]
def findSchool(teacher: Teacher): Future[Either[String, Option[School]]]
Run Code Online (Sandbox Code Playgroud)

现在,如果我想随后在for-comprehension中调用它们,我可以使用EitherTOptionT喜欢这样:

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
}
Run Code Online (Sandbox Code Playgroud)

我不知道是否有可能通过合并,使之更简洁,也许OptionTEitherT

Ser*_*gGr 6

如果正确地理解你的问题,你想建立的组合单子变压器EitherTOptionT.使用Cats,您可以尝试这样的事情:

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
  }

}
Run Code Online (Sandbox Code Playgroud)

然后你可以重写你getSchoolByTeacherId

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
}
Run Code Online (Sandbox Code Playgroud)

不幸的是,即使OResult.applyimplicit你仍然有它在你换理解的第一行明确写入但这允许跳过它的进一步线.