繁体   English   中英

猫从单子堆栈中获得价值

[英]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.valueF[Option[A]]

因此,如果仅在OptionT[EitherT[Future, Error, ?], A]上调用.valueOptionT[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有类似的方法,当您需要访问内部OptionEither时,可以使用它们包装和拆开这些类。 例如,我认为您可以执行以下操作:

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.

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