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

问题描述 投票:7回答:1

我想用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]]]

现在,如果我想随后在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
}

我想知道是否有可能通过将OptionTEitherT相结合使其更简洁?

scala scalaz scala-cats
1个回答
6
投票

如果正确理解你的问题,你想建立一个EitherTOptionT的组合monad-transformer。使用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
  }

}

然后你可以重写你的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
}

不幸的是,即使OResult.applyimplicit,你仍然必须在你的理解的第一行明确地写它,但这允许在更多的线上跳过它。

© www.soinside.com 2019 - 2024. All rights reserved.