scala之OptionT的笛卡尔生成器

lhb25 阅读:100 2025-06-02 22:19:02 评论:0

我想加入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)(_ + _) 

在这种情况下,将来将并行执行,因此请注意这是否不是您想要的。


标签:Scala
声明

1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

关注我们

一个IT知识分享的公众号