[英]Cats get value from the monad stack
我有一个monad堆栈,用于响应使用cats monads变压器实现的组件的响应:
type FutureEither[A] = EitherT[Future, Error, A]
type FutureEitherOption[A] = OptionT[FutureEither, A]
结果是有效的:
Future[Either[Error, Option[A]]]
如何以适当的方式从此堆栈中获取值或错误? 如何合并以适当方式并行执行的多个调用的结果? 例如在这种情况下:
def fooServiceCall: FutureEitherOption[Foo]
def barServiceCall(f: Option[Foo]): FutureEitherOption[Bar]
for {
r1 <- fooServiceCall
r2 <- barServiceCall(r1)
} yield r2
您的第二个方法barServiceCall
在其签名中告诉它可以直接处理Option[Foo]
,而不是依赖monad转换器堆栈在某些时候失败并显示None
。 因此,您必须拆开一层OptionT[EitherT[Future, Error, ?], A]
EitherT[Future, Error, Option[A]]
,然后直接处理EitherT[Future, Error, Option[A]]
:即使您的方法似乎在前者是monad堆栈,这种理解的正确工具是后者。
回想一下,如果o: OptionT[F, A]
,则包装的o.value
为F[Option[A]]
。
因此,如果仅在OptionT[EitherT[Future, Error, ?], A]
上调用.value
, OptionT[EitherT[Future, Error, ?], A]
获得所需的EitherT[Future, Error, Option[A]]
。 这是它在代码中的工作方式:
import scala.concurrent.Future
import scala.util.Either
import cats.instances.future._
import cats.instances.either._
import cats.instances.option._
import cats.data.EitherT
import cats.data.OptionT
import scala.concurrent.Await
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration._
type Error = String // or whatever...
type Foo = (Int, Int) // whatever...
type Bar = (String, Float) // whatever...
type FutureEither[A] = EitherT[Future, Error, A]
type FutureEitherOption[A] = OptionT[FutureEither, A]
def fooServiceCall: FutureEitherOption[Foo] = ???
def barServiceCall(f: Option[Foo]): FutureEitherOption[Bar] = ???
val resFut: Future[Either[Error, Option[Bar]]] = (for {
r1 <- fooServiceCall.value // : EitherT[Future, Error, Option[Foo]]
r2 <- barServiceCall(r1).value // : EitherT[Future, Error, Option[Bar]]
} yield r2).value
val res: Either[Error, Option[Bar]] = Await.result(resFut, 10.seconds)
现在,结果非常简单,您可以直接对其进行处理。
另外,如果您不想在此时此地解压缩结果,可以将其再次包装到OptionT
并继续使用FutureEitherOption[Bar]
:
val res2: FutureEitherOption[Bar] =
OptionT(for {
r1 <- fooServiceCall.value
r2 <- barServiceCall(r1).value
} yield r2)
您可以在OptionT[F, A]
上调用.value
以获得F[Option[A]]
。 只需执行OptionT()
即可完成相反操作。 我相信EitherT
有类似的方法,当您需要访问内部Option
或Either
时,可以使用它们包装和拆开这些类。 例如,我认为您可以执行以下操作:
val x: FutureEither[Option[Bar]] = for {
r1 <- fooServiceCall.value
r2 <- barServiceCall(r1).value
} yield r2
val result: FutureEitherOption[Bar] = OptionT(x)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.