我想加入2 Future[Option[_]]
:
def foo: Future[Option[Int]] = ???
def baz: Future[Option[Int]] = ???
可以加入一对
Future
:foo |@| baz map( (fooOpt, bazOpt) => ???)
并可以加入
Option
对:Option(1) |@| Option(2) map ( (a, b) => ???)
如何加入
OptionT
对?不能那样工作:OptionT(foo) |@| OptionT(baz) map ( (a, b) => ???)
UPD -这是我的进口商品:
import cats.data.OptionT
import cats.instances.future._
import cats.instances.option._
import cats.syntax.cartesian._
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future
最佳答案
编辑
原来,这是一个非常众所周知的问题,它是由SI-2712引起的。如果您将sbt-partial-unification插件添加到您的项目中,则原始代码就可以正常工作。
如我所说,|@|
已过时,您应该更改以下语法:
import cats.syntax.apply._
(OptionT(foo), OptionT(bar)).mapN(_ + _)
似乎存在一个隐式解决问题。
OptionT
有一个Monad
实例,并且Monad
扩展了Apply
,它扩展了Cartesian
,因此您的代码确实可以正常工作。如果您对编译器有一点帮助,它确实可以工作:import scala.concurrent.{ExecutionContext, Future}
import cats.data.OptionT
import cats.syntax.cartesian._
import cats.instances.future._
trait CartesianOptionTs {
implicit def ec: ExecutionContext
def foo: Future[Option[Int]]
def bar: Future[Option[Int]]
(catsSyntaxCartesian[({type λ[α] = OptionT[Future, α]})#λ, Int](OptionT(foo)) |@| OptionT(bar)).map(_ + _)
}
但是,如果不指定
catsSyntaxCartesian
的类型,则会得到一个有趣的错误:[error] found : cats.data.OptionT[scala.concurrent.Future,Int]
[error] required: ?F[?A]
[error] Note that implicit conversions are not applicable because they are ambiguous:
[error] both method ArrowAssoc in object Predef of type [A](self: A)ArrowAssoc[A]
[error] and method Ensuring in object Predef of type [A](self: A)Ensuring[A]
[error] are possible conversion functions from cats.data.OptionT[scala.concurrent.Future,Int] to ?F[?A]
[error] (catsSyntaxCartesian(OptionT(foo)) |@| OptionT(bar)).map(_ + _)
请注意,现在不赞成使用
|@|
,但是替换mapN
似乎会遇到相同的问题。我可以想到两种解决方法。如果要使用
OptionT
,则将其Apply
实例带入范围并直接使用map2
(您可能要使用类型别名而不是lambda类型): import cats.Apply
Apply[({type λ[α] = OptionT[Future, α]})#λ].map2(OptionT(foo), OptionT(bar))(_ + _)
或者,您可以完全删除
OptionT
并使用Apply.compose
: import cats.instances.option._
Apply[Future].compose[Option].map2(foo, bar)(_ + _)
在这种情况下,将来将并行执行,因此请注意这是否不是您想要的。