scala - 猫从 monad 堆栈中获取值(value)

标签 scala monads monad-transformers scala-cats

我有一个 monad 堆栈,用于使用 cats monad 转换器实现的组件的响应:

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 转换器堆栈来失败 在某些时候没有。因此,您必须解压一层 OptionT[EitherT[Future, Error, ?], A],并改为处理 EitherT[Future, Error, Option[A]] code> 直接:即使您的方法似乎在前一个 monad 堆栈中返回结果,但此 for-compression 中正确的工具是后一个。

回想一下,如果 o: OptionT[F, A],则包装的 o.value 的类型为 F[Option[A]].

因此,如果您简单地在 OptionT[EitherT[Future, Error, ?], A] 上调用 .value,您将获得所需的 EitherT[ future ,错误,选项[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)

关于scala - 猫从 monad 堆栈中获取值(value),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48996530/

相关文章:

haskell - Monad 变压器 : troubles defining bind due to different monads

performance - 来自 monad 变压器基准测试的奇怪结果。一个错误?

java - 无法重定向 STDIN/STDOUT

scala - 喷Json : Convert a Generic type to JsonFormat

java - 为什么 Scala 很复杂?

Haskell - 使用 Reader monad 的二叉树中每个节点的深度

haskell - 列出单子(monad)转换器

postgresql - 使用 slick 访问 postgres 不起作用

haskell - 也许 monad 绑定(bind)函数优先级

haskell - 为 RVarT 实现 MFunctor 实例