结合`OptionT`和`EitherT`来处理`Future[Either[Error, Option[T]]]`
Combining `OptionT` and `EitherT` to handle `Future[Either[Error, Option[T]]]`
我想使用 Cats EitherT
和 OptionT
来处理类型 Future[Either[Error, Option[T]]
。假设有以下方法:
def findTeacher(id: Int): Future[Either[String, Option[Teacher]]]
def findSchool(teacher: Teacher): Future[Either[String, Option[School]]]
现在,如果我想随后在理解中调用它们,我可以像这样使用 EitherT
和 OptionT
:
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
}
我想知道是否可以通过将 OptionT
与 EitherT
结合起来使其更简洁?
如果正确理解你的问题,你想构建一个 EitherT
和 OptionT
的组合 monad-transformer。使用猫你可以尝试这样的事情:
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.apply
是 implicit
你仍然必须在 for-comprehension 的第一行明确地写它,但这允许在后面的行中跳过它。
我想使用 Cats EitherT
和 OptionT
来处理类型 Future[Either[Error, Option[T]]
。假设有以下方法:
def findTeacher(id: Int): Future[Either[String, Option[Teacher]]]
def findSchool(teacher: Teacher): Future[Either[String, Option[School]]]
现在,如果我想随后在理解中调用它们,我可以像这样使用 EitherT
和 OptionT
:
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
}
我想知道是否可以通过将 OptionT
与 EitherT
结合起来使其更简洁?
如果正确理解你的问题,你想构建一个 EitherT
和 OptionT
的组合 monad-transformer。使用猫你可以尝试这样的事情:
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.apply
是 implicit
你仍然必须在 for-comprehension 的第一行明确地写它,但这允许在后面的行中跳过它。