Scala:Cats、OptionT[Future, T] 和 ApplicativeError

Scala: Cats, OptionT[Future, T] and ApplicativeError

前段时间我开始使用 Cats,发现 OptionT 在大多数情况下与 Future[Option[T]] 一起工作非常有用。但是我遇到了一个缺点,要使用 AplicativeError 我需要定义类型别名 type FutureOption[T] = OptionT[Future, X] 以匹配 AplicativeError 所需的 F[_] 并将表达式的类型明确指定为 FutureOption[T].

type FutureOption[T] = OptionT[Future, T] // definition to match F[_] kind

val x = OptionT.liftF(Future.failed(new Exception("error"))) : FutureOption[String] // need to specify type explicitly
x.recover {
  case NonFatal(e) => "fixed"
}

如果我删除表达式的类型定义和显式类型说明,recover 将不可用,因为 OptionT[Future, T] 不匹配 F[_],因此无法转换隐含地 AplicativeErrorOps.

不幸的是,下面的示例将无法运行,因为没有 recover 方法。

val x = OptionT.liftF(Future.failed(new Exception("error")))
x.recover {
  case NonFatal(e) => "fixed"
}

有什么办法可以避免这种样板代码吗?至少我想避免将表达式类型明确指定为 FutureOption[T]

是的,至少有两种方法可以应对类型归属。

  • 使用 lambda 类型(这可能很吓人):

    val a: { type λ[A] = OptionT[Future, A] }#λ
    
  • 使用像 kind-projector 这样的编译器插件,示例用法:

    val a: Lambda[A => OptionT[Future, A]]
    

但是如果你想调用 Futurerecover,你总是可以这样做:

val x = OptionT.liftF(Future.failed(new Exception("error")))
x.value.recover ...

除了其他答案之外,我还建议您确保为您的构建启用 -Ypartial-unification

这是针对 partial unification of type constructors. You can find a more detailed explanation about the fix here 的修复。

启用部分统一后,您在问题中提供的代码可以正常编译。请注意,如果您使用的是 IDE(例如 Intellij),您可能会得到 "false negatives"(代码带有下划线表示不正确且代码完成不起作用),但 scalac/sbt/gradle 将编译就好了