为什么会发生这种隐含的歧义行为? [英] Why is this implicit ambiguity behaviour happening?

查看:80
本文介绍了为什么会发生这种隐含的歧义行为?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个类型类Search,如果我们有一个TypeClass1[A]TypeClass2[A]实例,则它有一个实例Search[A].优先考虑1实例.

I have a typeclass Search, which has an instance Search[A] if we have a TypeClass1[A] or a TypeClass2[A] instance. With preference given to the 1 instance.

以下编译:

trait TypeClass1[A]
trait TypeClass2[A]
trait Search[A]

object Search extends LPSearch {
  implicit def case1[A](implicit ev: TypeClass1[A]): Search[A] = null
}

trait LPSearch {
  implicit def case2[A](implicit ev: TypeClass2[A]): Search[A] = null
}

object Test {
  implicit val ev1: TypeClass1[Int] = null
  implicit val ev2: TypeClass2[Int] = null
  implicitly[Search[Int]]
}

这是我所期望的,隐式搜索找到case1,找到ev1,然后停止搜索.

This is as I would expect, the implicit search finds case1, finds ev1, and stops searching.

但是,如果我们将TypeClass2更改为具有更多结构,则隐式搜索将停止工作:

However, if we change TypeClass2 to have more structure, the implicit search stops working:

trait TypeClass1[A]
trait TypeClass2[M[_], A]
trait Search[A]

object Search extends LPSearch {
  // This is the same as before
  implicit def case1[A](implicit ev: TypeClass1[A]): Search[A] = null
}

trait LPSearch {
  implicit def case2[M[_], A](implicit ev: TypeClass2[M, A]): Search[M[A]] = null
}

object Test {
  implicit val ev1: TypeClass1[List[Int]] = null
  implicit val ev2: TypeClass2[List, Int] = null

  // Does not compile:
  implicitly[Search[List[Int]]]
}

在上面的示例中为什么最后一行没有编译?

Why does this last line not compile in the above example?

失败并显示ambiguous implicit values,表示case1case2都满足条件.

It fails with ambiguous implicit values, saying both case1 and case2 satisfy the condition.

在scala 2.12.8和2.13.0上观察到的行为

Behaviour observed on scala 2.12.8 and 2.13.0

推荐答案

Scala规范说:

如果有几个与隐式参数类型匹配的合格参数,则将使用静态重载解析规则选择一个最具体的参数.

If there are several eligible arguments which match the implicit parameter's type, a most specific one will be chosen using the rules of static overloading resolution.

https://www .scala-lang.org/files/archive/spec/2.13/07-implicits.html#implicit-parameters

替代项A在替代项B上的相对权重是一个从0到2的数字,定义为

The relative weight of an alternative A over an alternative B is a number from 0 to 2, defined as the sum of

    如果AB一样具体,则为
  • 1,否则为0,
  • 如果从定义B的类或对象派生的类或对象中定义了A,则为
  • 1,否则为0.
  • 1 if A is as specific as B, 0 otherwise, and
  • 1 if A is defined in a class or object which is derived from the class or object defining B, 0 otherwise.

https://www .scala-lang.org/files/archive/spec/2.13/06-expressions.html#overloading-resolution

  • case1是在一个对象中定义的,该对象是从定义case2的类(特征)得出的(),反之亦然.

  • case1 is defined in an object which is derived from the class (trait) defining case2 but not vice versa.

case2特定于 case1,反之亦然.

因此case1case2上的相对权重是1 + 0 = 1,而case2case1上的相对权重是0 + 1 = 1.所以这很模棱两可.

So relative weight of case1 over case2 is 1+0=1 and relative weight of case2 over case1 is 0+1=1. So it's ambiguity.

Error: ambiguous implicit values:
 both method case2 in trait LPSearch of type [M[_], A](implicit ev: App.TypeClass2[M,A])App.Search[M[A]]
 and method case1 in object Search of type [A](implicit ev: App.TypeClass1[A])App.Search[A]
 match expected type App.Search[List[Int]]
    implicitly[Search[List[Int]]]

在第二种情况下,没有意义使用低优先级特征,因为如果两个隐式对象都与预期类型匹配,则当在同一对象中定义它们时,优选使用case2.所以尝试

In the second case there is no sense to use low-priority trait since if both implicits match expected type, case2 is preferred when they are defined in the same object. So try

object Search {
  implicit def case1[A](implicit ev: TypeClass1[A]): Search[A] = null
  implicit def case2[M[_], A](implicit ev: TypeClass2[M, A]): Search[M[A]] = null
}

这篇关于为什么会发生这种隐含的歧义行为?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆