我得到了一个奇怪的编译器错误,关于一个隐含的实际存在但无法找到的原因。所以我构建了一个能够再现神秘行为的小测试案例。为什么在某些情况下忽略高阶含义?
trait Hide {
type T
}
object HideString extends Hide {
override type T = String
}
object HideBool extends Hide {
override type T = Boolean
}
简单类型用作隐式转换的明确目标。
def id[H <: Hide, C](x : C)(implicit ev : C => H#T) : H#T = ev(x)
def drop[H <: Hide, C](x : C)(implicit ev : C => H#T) : Int = {
println(ev(x))
1
}
def idSeq[H <: Hide, C](x : Seq[C])(implicit ev : Seq[C] => Seq[H#T]) : Seq[H#T] = ev(x)
def dropSeq[H <: Hide, C](x : Seq[C])(implicit ev : Seq[C] => Seq[H#T]) : Int = {
println(ev(x))
1
}
依赖于隐式转换的方法。它基本上是2x2矩阵。 id
方法返回转换类型和drop
方法内部使用转换并返回一些常量。正常方法在精确隐式转换类型上运行,并且方法对序列进行操作。
implicit def exString(x : String) : HideString.type#T = x
implicit def highString[F[_]](x : F[String]) : F[HideString.type#T] = x
上述隐式转换highString
用高阶类型定义。
val s1 = id("sdf")
val s2 = drop("aero")
val r1 = idSeq(Seq("a", "bc"))
val r2 = dropSeq(Seq("i", "IO"))
试图实际使用的转换给我带来了一个错误:
ImplicitResolution.scala:98: error: No implicit view available from Seq[String] => Seq[test.implicits.HighReduction.Hide#T].
val r2 = dropSeq(Seq("i", "IO"))
这可能会在下面的矩阵来概括:
| | id | drop |
|--------+------+------|
| normal | pass | pass |
| seq | pass | fail |
如果我用精确定义的隐式转换为dropSeq
方法通常会发现:
implicit def seqBool(x : Seq[Boolean]) : Seq[HideBool.type#T] = x
val a1 = idSeq(Seq(true, false))
val a2 = dropSeq(Seq(false, true))
,此外,如果我明确地指定隐含参数dropSeq
开始工作:
val r2i = dropSeq(Seq("i", "IO"))(highString[Seq] _)
这是奇怪的事情。隐含符合所有要求。它被声明为implicit
,所以它应该被编译器找到。并且在idSeq
的情况下它实际上被发现。那么,为什么它在dropSeq
的情况下被忽略?
如果您提交的问题是您所描述的“Scala编译器中的角落案例”,那么我更倾向于奖励您的赏金。我认为这是一些特例,但是你仍然没有提供足够的信息来知道这是否是预期的行为,或者它确实是编译器中的错误。这也将是很好的,如果你摆脱了悬挂'}'... – DaoWen
你的两个函数具有相同的签名,除了返回类型,但你使用r1和r2的类型推断(因此返回类型不能用于隐式解析)。如果可以使用可用的类型信息解析r1的隐式表达式,则可以解析r2的隐式:假定该下拉工作并且dropSeq没有,那么问题可能与通用类型和类型投影有关。 – Edmondo1984
使用'-Xlog-implicits'会产生一些有趣的错误。 –