前段时间我开始使用Cats,发现OptionT
在大多数情况下对Future[Option[T]]
非常有用。但我遇到一个缺点,使用AplicativeError
我需要将类型别名type FutureOption[T] = OptionT[Future, X]
定义为F[_]
所需的匹配AplicativeError
,并明确指定我的表达式类型为{{ 1}}。
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"
}
。
答案 0 :(得分:5)
除了其他答案之外,我建议您确保为您的版本启用-Ypartial-unification
。
这是对partial unification of type constructors的修正。您可以找到有关修复here的详细说明。
启用部分统一后,您在问题中提供的代码编译得很好。请注意,如果您使用的是IDE(例如Intellij),您可能会收到“漏报”(代码加下划线标记为错误且代码完成无效),但scalac / sbt / gradle会将其编译得很好。
答案 1 :(得分:0)
是的,至少有两种方法可以应对类型归属。
使用lambdas类型(这可能是令人生畏的):
val a: { type λ[A] = OptionT[Future, A] }#λ
使用像kind-projector这样的编译器插件,示例用法:
val a: Lambda[A => OptionT[Future, A]]
但如果您想致电Future
的{{1}},您可以随时执行:
recover