Scala 隐式参数投影冲突,"Ambigious Implicit Values" 错误

Scala Implicit Parameters Projection Conflict , "Ambigious Implicit Values" Error

我一直在阅读 Bruno 的 TypeClasses 论文,他提到参数列表中的隐式 projected/propagated 进入隐式范围。我按照这个代码的例子:

package theory

import cats.implicits.toShow

import java.io.PrintStream
import java.util.Date

object Equality extends App {
  import cats.Eq

//  assert(123 == "123")
  println(Eq.eqv(123, 123).show)

  implicit val out: PrintStream = System.out

  def log(m: String)(implicit o: PrintStream ): Unit =
    o.println(m)

  def logTime(m: String)(implicit  o: PrintStream): Unit =
    log(s"${new Date().getTime} : $m")

}

关键是这段代码无法编译,其中:

ambiguous implicit values:
 both value out in object Equality of type java.io.PrintStream
 and value o of type java.io.PrintStream
 match expected type java.io.PrintStream
    log(s"${new Date().getTime} : $m")

因此,我假设编译器看到相同隐式的 2 个实例并抱怨。通过将作为参数传递的 PrintStream 作为第二个参数显式添加到 log:

,我能够使编译器静音
def logTime(m: String)(implicit  o: PrintStream): Unit =
    log(s"${new Date().getTime} : $m")(o)

这行得通,但我是不是漏掉了什么?为什么 logTime() 的主体内部会出现混乱?我认为布鲁诺是在暗示来自调用者的隐式将被投射到方法的范围内。他的示例 没有 将额外参数添加到 log() 调用。为什么 scalac 将这些视为 2?我想我假设来自外部方法的隐式会“隐藏” val。不是这样。

如果有人能解释为什么我看到这个,将不胜感激。

回想一下,隐式参数的值是在调用站点确定的。这就是为什么...

Equality.log("log this")

...除非将适当类型的隐式值引入作用域,否则无法编译。

implicit val ps: PrintStream = ...
Equality.log("log this")

logTime() 定义代码是 log() 方法的调用点,因为它是在 Equality 对象中定义的,所以它具有可用的 implicit val out 值给它。但它也是从其调用站点传递的相同类型的 implicit o 值的接收者。因此歧义。编译器应该将 implicit out 值还是 implicit o 值发送到 log() 方法?

现在,接收到的隐式值(来自调用站点)都分配给了一个本地标识符,o插入看起来有点奇怪也进入本地隐式名称空间。事实证明,Scala-3 修改了该行为,您的代码编译没有错误,即使没有新的 given/using 语法。 (我假设 implicit out 值传递给 log() 方法,而不是接收到的 o 值。)