簡體   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