为什么这个隐式解决方案失败了?
Why is this implicit resolution failing?
我有一个隐式转换 - 如下 - 感觉它肯定应该工作但绝对不是。任何人都可以阐明吗?我知道 implicitly
在使用类型优化时有时会失败 - 问题出在这里吗?
trait GetItem[A[_], T, R] {
type Out
def ret(a: A[T], ref: R): Out
}
object GetItem {
implicit def ifRefIsInt[A[_], T]: GetItem[A, T, Int] { type Out = A[T] } = new GetItem[A, T, Int] {
type Out = A[T]
def ret(a: A[T], ref: Int): Out = a
}
}
import GetItem._
//this works fine:
val t: GetItem[List, Double, Int] { type Out = List[Double] } = ifRefIsInt[List, Double]
// so does this:
implicitly[GetItem[List, Double, Int] { type Out = List[Double] }](t)
// this does not:
implicitly[GetItem[List, Double, Int] { type Out = List[Double] }]
// Could not find implicit parameter for value e: Example.Main.GetItem[List, Double, Int]{type Out = List[Double]}
非常感谢任何帮助,我已经盯着这个看了一段时间但收效甚微。
不知道为什么它不能那样工作,但是解决这类问题的一个好方法是使用 Aux 模式来提升 将成员 键入 类型参数 ,从而提高分辨率。
trait GetItem[A[_], T, R] {
type Out
def ret(a: A[T], ref: R): Out
}
object GetItem {
type Aux[A[_], T, R, O] = GetItem[A, T, R] { type Out = O }
implicit def ifRefIsInt[A[_], T]: Aux[A, T, Int, A[T]] = new GetItem[A, T, Int] {
type Out = A[T]
def ret(a: A[T], ref: Int): Out = a
}
}
你可以这样测试:
implicitly[GetItem.Aux[List, Double, Int, List[Double]]]
// res: GetItem.Aux[List, Double, Int, List[Double]] = ...
implicitly[GetItem[List, Double, Int]]
// res: GetItem[List, Double, Int] = ...
似乎是过度约束隐式的另一个例子 ( 2 3 )。对于一步中的隐式来说,这似乎工作量太大了。编译器不喜欢类型细化中的复杂类型,如 (A, B)
、H :: L
和 A[T]
(在我们的例子中)。如果我们替换
implicit def ifRefIsInt[A[_], T]: GetItem[A, T, Int] { type Out = A[T] } =
new GetItem[A, T, Int] {
type Out = A[T]
def ret(a: A[T], ref: Int): Out = a
}
和
implicit def ifRefIsInt[A[_], T, O](implicit
ev: A[T] =:= O
): GetItem[A, T, Int] { type Out = O } = new GetItem[A, T, Int] {
type Out = O
def ret(a: A[T], ref: Int): Out = a
}
然后
implicitly[GetItem.Aux[List, Double, Int, List[Double]]]
implicitly[GetItem[List, Double, Int] { type Out = List[Double] }]
编译:https://scastie.scala-lang.org/P5iXP2ZfQUCKEIMukYyqIg (Scala 2.13.3)
出于某种原因,编译器吞下了警告(-Xlog-implicits
已打开)。如果我手动触发隐式搜索
import scala.language.experimental.macros
import scala.reflect.macros.{whitebox, contexts}
def foo[A]: Unit = macro fooImpl[A]
def fooImpl[A: c.WeakTypeTag](c: whitebox.Context): c.Tree = {
import c.universe._
val context = c.asInstanceOf[contexts.Context]
val global: context.universe.type = context.universe
val analyzer: global.analyzer.type = global.analyzer
val callsiteContext = context.callsiteTyper.context
val typ = weakTypeOf[A]
val search = new analyzer.ImplicitSearch(
tree = EmptyTree.asInstanceOf[global.Tree],
pt = typ.asInstanceOf[global.Type],
isView = false,
context0 = callsiteContext.makeImplicit(reportAmbiguousErrors = true),
pos0 = c.enclosingPosition.asInstanceOf[scala.reflect.internal.util.Position]
)
println(s"allImplicits=${search.allImplicits}")
q""
}
然后
foo[GetItem[List, Double, Int] { type Out = List[Double] }]
产生警告
App.this.GetItem.ifRefIsInt is not a valid implicit value for App.GetItem[List,Double,Int]{type Out = List[Double]} because:
hasMatchingSymbol reported error: polymorphic expression cannot be instantiated to expected type;
found : [A[_], T]App.GetItem[A,T,Int]{type Out = A[T]}
required: App.GetItem[List,Double,Int]{type Out = List[Double]}
scalac: allImplicits=List()
即A
、T
未推断。
我有一个隐式转换 - 如下 - 感觉它肯定应该工作但绝对不是。任何人都可以阐明吗?我知道 implicitly
在使用类型优化时有时会失败 - 问题出在这里吗?
trait GetItem[A[_], T, R] {
type Out
def ret(a: A[T], ref: R): Out
}
object GetItem {
implicit def ifRefIsInt[A[_], T]: GetItem[A, T, Int] { type Out = A[T] } = new GetItem[A, T, Int] {
type Out = A[T]
def ret(a: A[T], ref: Int): Out = a
}
}
import GetItem._
//this works fine:
val t: GetItem[List, Double, Int] { type Out = List[Double] } = ifRefIsInt[List, Double]
// so does this:
implicitly[GetItem[List, Double, Int] { type Out = List[Double] }](t)
// this does not:
implicitly[GetItem[List, Double, Int] { type Out = List[Double] }]
// Could not find implicit parameter for value e: Example.Main.GetItem[List, Double, Int]{type Out = List[Double]}
非常感谢任何帮助,我已经盯着这个看了一段时间但收效甚微。
不知道为什么它不能那样工作,但是解决这类问题的一个好方法是使用 Aux 模式来提升 将成员 键入 类型参数 ,从而提高分辨率。
trait GetItem[A[_], T, R] {
type Out
def ret(a: A[T], ref: R): Out
}
object GetItem {
type Aux[A[_], T, R, O] = GetItem[A, T, R] { type Out = O }
implicit def ifRefIsInt[A[_], T]: Aux[A, T, Int, A[T]] = new GetItem[A, T, Int] {
type Out = A[T]
def ret(a: A[T], ref: Int): Out = a
}
}
你可以这样测试:
implicitly[GetItem.Aux[List, Double, Int, List[Double]]]
// res: GetItem.Aux[List, Double, Int, List[Double]] = ...
implicitly[GetItem[List, Double, Int]]
// res: GetItem[List, Double, Int] = ...
似乎是过度约束隐式的另一个例子 ((A, B)
、H :: L
和 A[T]
(在我们的例子中)。如果我们替换
implicit def ifRefIsInt[A[_], T]: GetItem[A, T, Int] { type Out = A[T] } =
new GetItem[A, T, Int] {
type Out = A[T]
def ret(a: A[T], ref: Int): Out = a
}
和
implicit def ifRefIsInt[A[_], T, O](implicit
ev: A[T] =:= O
): GetItem[A, T, Int] { type Out = O } = new GetItem[A, T, Int] {
type Out = O
def ret(a: A[T], ref: Int): Out = a
}
然后
implicitly[GetItem.Aux[List, Double, Int, List[Double]]]
implicitly[GetItem[List, Double, Int] { type Out = List[Double] }]
编译:https://scastie.scala-lang.org/P5iXP2ZfQUCKEIMukYyqIg (Scala 2.13.3)
出于某种原因,编译器吞下了警告(-Xlog-implicits
已打开)。如果我手动触发隐式搜索
import scala.language.experimental.macros
import scala.reflect.macros.{whitebox, contexts}
def foo[A]: Unit = macro fooImpl[A]
def fooImpl[A: c.WeakTypeTag](c: whitebox.Context): c.Tree = {
import c.universe._
val context = c.asInstanceOf[contexts.Context]
val global: context.universe.type = context.universe
val analyzer: global.analyzer.type = global.analyzer
val callsiteContext = context.callsiteTyper.context
val typ = weakTypeOf[A]
val search = new analyzer.ImplicitSearch(
tree = EmptyTree.asInstanceOf[global.Tree],
pt = typ.asInstanceOf[global.Type],
isView = false,
context0 = callsiteContext.makeImplicit(reportAmbiguousErrors = true),
pos0 = c.enclosingPosition.asInstanceOf[scala.reflect.internal.util.Position]
)
println(s"allImplicits=${search.allImplicits}")
q""
}
然后
foo[GetItem[List, Double, Int] { type Out = List[Double] }]
产生警告
App.this.GetItem.ifRefIsInt is not a valid implicit value for App.GetItem[List,Double,Int]{type Out = List[Double]} because:
hasMatchingSymbol reported error: polymorphic expression cannot be instantiated to expected type;
found : [A[_], T]App.GetItem[A,T,Int]{type Out = A[T]}
required: App.GetItem[List,Double,Int]{type Out = List[Double]}
scalac: allImplicits=List()
即A
、T
未推断。