Scala Cats从monad堆栈中获取值
我有一个monad堆栈,用于响应使用cats monad transformers实现的组件:Scala Cats从monad堆栈中获取值,scala,monads,monad-transformers,scala-cats,Scala,Monads,Monad Transformers,Scala Cats,我有一个monad堆栈,用于响应使用cats monad transformers实现的组件: type FutureEither[A] = EitherT[Future, Error, A] type FutureEitherOption[A] = OptionT[FutureEither, A] 结果是: Future[Either[Error, Option[A]]] 如何以正确的方式从堆栈中获取值或错误?如何以适当的方式组合并行执行的多个调用的结果?例如,在这种情况下: def f
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
def fooServiceCall:futureetheroption[Foo]
def barServiceCall(f:选项[Foo]):FutureEitherOption[Bar]
为了{
r1您的第二个方法barServiceCall
在其签名中告诉您,它可以直接处理Option[Foo]
,而不是依赖monad transformer堆栈在某一点上以None
失败。因此,您必须解压缩一层OptionT[EitherT[Future,Error,,],A]
,而是直接处理EitherT[Future,Error,Option[A]]
:尽管您的方法似乎在前一个monad堆栈中返回结果,但这方面正确的理解工具是后一个
回想一下,如果o:OptionT[F,A]
,则包装的o.value
为F[Option[A]]
类型
因此,如果您只需在选项[EitherT[Future,Error,a]
上调用.value
,您将获得所需的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)
您可以在选项[F,a]
上调用.value
来获取F[Option[a]]
。只需执行选项()
做相反的操作。我相信EitherT
有类似的方法,当您需要访问内部选项
s或选项
s时,您可以使用这些方法包装和打开这些类。例如,我认为您可以执行以下操作:
val x: FutureEither[Option[Bar]] = for {
r1 <- fooServiceCall.value
r2 <- barServiceCall(r1).value
} yield r2
val result: FutureEitherOption[Bar] = OptionT(x)
val x:futurear[Option[Bar]]=for{
r1谢谢,看起来不错。你能澄清一件事吗?如果fooServiceCall.value
将返回None
,下一个调用将是barservicecoll(None)
?我现在坚持使用它……我认为选项[T]
可能不是一个好的选择。从一方面来说,这是可以的,因为非值不是错误,但从另一方面来说,条形码服务应该处理它,这对我来说并不好。正如我在回答中试图勾勒出的,似乎你基本上是在EitherT[错误,未来,,]
。在程序的某一点上,?
恰好是选项[Foo]
,但由于barServiceCall
能够以一种有意义的方式处理None
,因此您不会失败,而是将None
传递给barServiceCall
。因此,由OptionT
建模的失败模式似乎没有必要:您可以从None
恢复并继续计算可能这里并不真正需要选项,因为它只会妨碍(至少对这两种方法是如此)。@theodor我可以添加一个版本,其中选择的类型构造函数稍有不同,而不是futureitheroption
。但它会变得更“代码审查”那么,我认为你对option
的直觉是正确的。
val x: FutureEither[Option[Bar]] = for {
r1 <- fooServiceCall.value
r2 <- barServiceCall(r1).value
} yield r2
val result: FutureEitherOption[Bar] = OptionT(x)