假设:
def doStuff(a: A, b: B): C = ???
val result: M[C] = (ma |@| mb).map(doStuff)
我知道我可以这样做:
flatMap
但我如何flatMap? CartesianBuilder
s中没有def doFancyStuff(a: A, b: B): M[C] = ???
val result: M[C] = (ma |@| mb).flatMap(doFancyStuff)
。
CTrade.OrderModify()
答案 0 :(得分:1)
我认为主要的问题是,flatMap
Future[Either[Error, X]]
EitherT[Future, Error, X]
- monad堆栈中的flatMap
尴尬,因为Future
Future
1}}阻碍了,并且编译器没有寻找可以同时处理Either
和EitherT
组合的monad实例。但是,如果你将期货包裹在(a,b).tupled
中,一切都会顺利进行。
对于猫1.0.1
在下文中,Cartesian.product(a, b)
对应(a, b).mapN
,而(a |@| b).map
对应已弃用的A
。
鉴于类型B
,C
,Error
,M
,以下代码段在cat 1.0.1下编译:
如果你想保留EitherT
(你可能应该)的定义,那么你
通过将所有内容包装在value
然后,可以避免上述问题
提取import scala.util.Either
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global // required by Monad[Future]
import cats.instances.future._ // Monad for `Future`
import cats.syntax.apply._ // `tupled` and `mapN`
import cats.data.EitherT // EitherT monad transformer
type M[X] = Future[Either[Error, X]]
val ma: M[A] = ???
val mb: M[B] = ???
def doStuff(a: A, b: B): C = ???
val result1: M[C] = (EitherT(ma), EitherT(mb)).mapN(doStuff).value
def doFancyStuff(a: A, b: B): M[C] = ???
val result2: M[C] = (for {
ab <- (EitherT(ma), EitherT(mb)).tupled
c <- EitherT(doFancyStuff(ab._1, ab._2))
} yield c).value
:
M
但是,如果这看起来太尴尬了,你可以调整import scala.util.Either
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global // required by Monad[Future]
import cats.instances.future._ // Monad for `Future`
import cats.syntax.apply._ // `tupled` and `mapN`
import cats.data.EitherT // EitherT monad transformer
type M[X] = EitherT[Future, Error, X]
val ma: M[A] = ??? // either adjust signatures, or wrap result in EitherT(res)
val mb: M[B] = ???
def doStuff(a: A, b: B): C = ???
val result1: M[C] = (ma, mb).mapN(doStuff)
def doFancyStuff(a: A, b: B): M[C] = ???
val result2: M[C] = (ma, mb).tupled.flatMap{
case (a, b) => doFancyStuff(a, b)
}
的定义,
以下变体可能会略短:
(ma, mb).tupled
这是因为M[(A, B)]
构建了M
,其中flatMap
是前面提到的monad堆栈,然后(A, B) => M[C]
可以轻松M[C]
函数为Cartesian
。
适用于(ma, mb).tupled
(未经测试)
假设Cartesian.product
对应于已弃用的(ma, mb).mapN
而(ma |@| mb).map
对应于已弃用的result1
,则result2
和val result1: M[C] = (ma |@| mb).map(doStuff)
val result2: M[C] = Cartesian[M].product(ma, mb).flatMap{
case (a, b) => doFancyStuff(a, b)
}
的两个定义相对应在上面的代码片段中,1.0.1转换为:
Cartesian[M].product(ma, mb)
同样,这只是因为M[(A, B)]
从M[A]
和M[B]
构建M[X]
,其中EitherT[Future, Error, X]
定义为Future[Either[Error, X]]
。如果它被定义为flatMap
,则会Future
上调用doFancyStuff
,而不是Either[Error, (A, B)] => Future[Either[Error, C]]
,我们必须传递{{1}}之类的内容,这可能不是你想要的。