为什么添加 import `import cats.instances.future._` 会导致隐式 Functor[Future] 的编译错误
Why adding import `import cats.instances.future._` will result an compilation error for implicit Functor[Future]
scala 代码使用猫并且运行良好:
import cats.implicits._
import cats.Functor
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future
object Hello extends App {
Functor[Future].map(Future("hello"))(_ + "!")
}
但是如果我添加这个导入:
import cats.instances.future._
会报这样的编译错误:
Error:(18, 10) could not find implicit value for parameter instance: cats.Functor[scala.concurrent.Future]
Functor[Future].map(Future("hello"))(_ + "!")
为什么会发生,我该如何调试它来找到原因?我用了各种我知道的方法,还是找不到。
build.sbt
文件是:
name := "Cats Implicit Functor of Future Compliation Error Demo"
version := "0.1"
organization := "org.my"
scalaVersion := "2.12.4"
sbtVersion := "1.0.4"
libraryDependencies ++= Seq(
"org.typelevel" %% "cats-core" % "1.0.1"
)
问题是实例被导入了两次,这意味着 scalac 无法消除它们之间的歧义并且不知道使用哪一个然后失败。
因此,要么使用 implicits._
导入,要么使用 instances.<datatype>._
导入特定实例,但绝不能同时使用!
您可以在此处更深入地了解猫的进口情况:https://typelevel.org/cats/typeclasses/imports.html
作为线性超类型的对象 cats.implicits
has the FutureInstances
trait。 FutureInstances
有一个隐式的 catsStdInstancesForFuture
方法,它产生一个 Monad[Future]
,而后者又是一个 Functor[Future]
.
另一方面,对象cats.instances.future
也混入了FutureInstances
,所以它又提供了一个隐式方法catsStdInstancesForFuture
,但是通过另一条途径。
现在编译器有两种可能生成 Functor[Future]
:
- 通过调用
cats.instances.future.catsStdInstancesForFuture
- 通过调用
cats.implicits.catsStdInstancesForFuture
由于无法决定选择哪一个,因此会退出并显示一条错误消息。
为避免这种情况,请不要将 cats.implicits._
与 cats.instances.future._
一起使用。要么省略其中一个导入,要么使用
`import packagename.objectname.{member1name, member2name}`
到 select 只有那些你需要的暗示。
将 "-print"
添加到 scalacOptions
可以 帮助调试隐式:
scalacOptions ++= Seq(
...
"-print",
...
)
它将打印出脱糖后的代码,并在各处添加 cats.implicits.
和 cats.instances.
块。不幸的是,它往往会产生很多噪音。
发生这种情况的更根本原因是无法在导致 [= 的两个(等效)路径之间定义 higher-dimensional-cells(kind-of "homotopies") 17=]。如果我们有可能告诉编译器采用哪条路径并不重要,那么一切都会好得多。由于我们做不到,所以我们必须确保始终只有一种方法可以生成隐式 Functor[Future]
.
scala 代码使用猫并且运行良好:
import cats.implicits._
import cats.Functor
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future
object Hello extends App {
Functor[Future].map(Future("hello"))(_ + "!")
}
但是如果我添加这个导入:
import cats.instances.future._
会报这样的编译错误:
Error:(18, 10) could not find implicit value for parameter instance: cats.Functor[scala.concurrent.Future]
Functor[Future].map(Future("hello"))(_ + "!")
为什么会发生,我该如何调试它来找到原因?我用了各种我知道的方法,还是找不到。
build.sbt
文件是:
name := "Cats Implicit Functor of Future Compliation Error Demo"
version := "0.1"
organization := "org.my"
scalaVersion := "2.12.4"
sbtVersion := "1.0.4"
libraryDependencies ++= Seq(
"org.typelevel" %% "cats-core" % "1.0.1"
)
问题是实例被导入了两次,这意味着 scalac 无法消除它们之间的歧义并且不知道使用哪一个然后失败。
因此,要么使用 implicits._
导入,要么使用 instances.<datatype>._
导入特定实例,但绝不能同时使用!
您可以在此处更深入地了解猫的进口情况:https://typelevel.org/cats/typeclasses/imports.html
作为线性超类型的对象 cats.implicits
has the FutureInstances
trait。 FutureInstances
有一个隐式的 catsStdInstancesForFuture
方法,它产生一个 Monad[Future]
,而后者又是一个 Functor[Future]
.
另一方面,对象cats.instances.future
也混入了FutureInstances
,所以它又提供了一个隐式方法catsStdInstancesForFuture
,但是通过另一条途径。
现在编译器有两种可能生成 Functor[Future]
:
- 通过调用
cats.instances.future.catsStdInstancesForFuture
- 通过调用
cats.implicits.catsStdInstancesForFuture
由于无法决定选择哪一个,因此会退出并显示一条错误消息。
为避免这种情况,请不要将 cats.implicits._
与 cats.instances.future._
一起使用。要么省略其中一个导入,要么使用
`import packagename.objectname.{member1name, member2name}`
到 select 只有那些你需要的暗示。
将 "-print"
添加到 scalacOptions
可以 帮助调试隐式:
scalacOptions ++= Seq(
...
"-print",
...
)
它将打印出脱糖后的代码,并在各处添加 cats.implicits.
和 cats.instances.
块。不幸的是,它往往会产生很多噪音。
发生这种情况的更根本原因是无法在导致 [= 的两个(等效)路径之间定义 higher-dimensional-cells(kind-of "homotopies") 17=]。如果我们有可能告诉编译器采用哪条路径并不重要,那么一切都会好得多。由于我们做不到,所以我们必须确保始终只有一种方法可以生成隐式 Functor[Future]
.