为什么带有扩展方法的代码可以编译?

Why does the code with extension method compile?

我有两个功能:

  override def build_url(dbType: DbDriverType, dbAddr: String, dbName: String): F[DbAddr] = dbType match {
    case PostgresSql =>
      Applicative[F].pure(DbAddr("jdbc:postgresql://" |+| dbAddr |+| "/" |+| dbName))
    case _ => DbDriverError.raiseError[F, DbAddr]
  }

  override def get_db_driver(dbType: DbDriverType): F[DbDriver] = dbType match {
    case PostgresSql =>
      Applicative[F].pure(DbDriver("org.postgresql.Driver"))
    case _ => Applicative.raiseError[F, DbDriver](DbDriverError)
  }

第一个编译,第二个不编译。编译器抱怨:

[error]  found   : io.databaker.db.DbDriverError.type
[error]  required: cats.ApplicativeError[F, _ >: cats.Applicative.type]
[error]     case _ => Applicative.raiseError[F, DbDriver](DbDriverError)

在第一个函数上,我在 DbDriverError.raiseError[F, DbAddr] 上使用了扩展方法,而在第二个函数上没有。对我来说,应该是一样的。

有什么区别?

在第二种情况下 Applicative.raiseError[F, DbDriver](DbDriverError) 您正在 Applicative compaion 对象上使用扩展方法。所以这个

Applicative.raiseError[F, DbDriver](DbDriverError)

实际上是这样

new ApplicativeErrorIdOps[F, Applicative.type](Applicative).raiseError[DbDriver](DbDriverError)(implicitly[ApplicativeError[F, Applicative.type]])

显然没有 ApplicativeError[F, Applicative.type] 实例,如果您的代码类似于@Luis Miguel Mejía Suárez 的 scastei,那么 ApplicativeError[F, Throwable] 的形式为 Sync[F]

在第一个示例中它起作用了,因为 DbDriverError.raiseError[F, DbAddr] 是执行

的扩展方法
new ApplicativeErrorIdOps[F, DbDriverError.type](DbDriverError).raiseError[DbAddr](DbDriverError)(implicitly[ApplicativeError[F, DbDriverError.type]])

假设object DbDriverError extends Exception(或其他Throwable)等于直接调用

implicitly[ApplicativeError[F, Throwable]].raiseError[DbAddr](DbDriverError)

这个隐式也可以采用 MonadError[F, Throwable]Sync[F]ApplicativeError[F, Throwable] 的任何其他实现。由于同伴有召唤方法你可以写:

ApplicativeError[F, Throwable].raiseError[DbDriver](DbDriverError)
// not the same as
// Applicative.raiseError[F, DbDriver](DbDriverError)
// !!!
// See where are square brackets and type parameters!
// And the class doesn't even match!

TLDR:

Applicative[F].sth(调用 Applicative.apply[F[_]](implicit a: Applicative[F]): Applicative[F]Applicative.sth 不同(调用 Applicative 伴随对象上的 method/extension 方法,特别是如果我们需要一个方法来自未在 Applicative 上定义的 ApplicativeError)。