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
值。)
我一直在阅读 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
值。)