猫从 monad 堆栈中获取价值
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]]
:即使你的方法看起来 return 导致前一个 monad 堆栈,这个 EitherT[Future, Error, Option[A]]
中的正确工具=35=]是后一个。
回想一下,如果 o: OptionT[F, A]
,则包装的 o.value
是 F[Option[A]]
类型。
因此,如果您简单地在 OptionT[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)
现在结果很简单,你可以直接处理它。
或者,如果您不想立即解压结果,您可以将其再次包装到 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
s 或 Either
s 时,您可以使用这些方法来包装和解开这些 类。例如,我认为您可以这样做:
val x: FutureEither[Option[Bar]] = for {
r1 <- fooServiceCall.value
r2 <- barServiceCall(r1).value
} yield r2
val result: FutureEitherOption[Bar] = OptionT(x)
我有一个 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]]
:即使你的方法看起来 return 导致前一个 monad 堆栈,这个 EitherT[Future, Error, Option[A]]
中的正确工具=35=]是后一个。
回想一下,如果 o: OptionT[F, A]
,则包装的 o.value
是 F[Option[A]]
类型。
因此,如果您简单地在 OptionT[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)
现在结果很简单,你可以直接处理它。
或者,如果您不想立即解压结果,您可以将其再次包装到 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
s 或 Either
s 时,您可以使用这些方法来包装和解开这些 类。例如,我认为您可以这样做:
val x: FutureEither[Option[Bar]] = for {
r1 <- fooServiceCall.value
r2 <- barServiceCall(r1).value
} yield r2
val result: FutureEitherOption[Bar] = OptionT(x)