基于返回类型推断的意外隐式解析

Pat*_*ont 51 scala type-inference return-type implicit scalaz

给定一个类型类,其中应根据返回类型执行实例选择:

case class Monoid[A](m0: A) // We only care about the zero here
implicit def s[T] : Monoid[Set[T]] = Monoid(Set.empty[T])
implicit def l[T] : Monoid[List[T]] = Monoid(List.empty[T])
def mzero[A](implicit m: Monoid[A]) : A = m.m0
Run Code Online (Sandbox Code Playgroud)

为什么Scala(2.11.6)无法解析正确的实例:

scala> mzero : List[Int]
<console>:24: error: ambiguous implicit values:
 both method s of type [T]=> Monoid[Set[T]]
 and method l of type [T]=> Monoid[List[T]]
 match expected type Monoid[A]
              mzero : List[Int]
              ^
Run Code Online (Sandbox Code Playgroud)

当它有没有问题,使用时发现基于返回类型的隐式函数(我们在这里重新定义它为来说明它是多么相似mzero)

def i[A](implicit a : A) : A = a
scala> i : Monoid[List[Int]]
res18: Monoid[List[Int]] = Monoid(List())
Run Code Online (Sandbox Code Playgroud)

Monoid[A]不是Monoid[List[Int]]在错误消息中令人费解.

我会假设许多scalaz贡献者熟悉这个问题,因为它似乎限制了scala中类型类的便利性.

编辑:我正在考虑让这个工作没有放弃类型推断.否则我想明白为什么那是不可能的.如果将此限制记录为Scala问题,我找不到它.

use*_*559 1

1)重写代码后如下:

case class Monoid[A](m0: A) // We only care about the zero here
implicit def s[T] : Monoid[Set[T]] = Monoid(Set.empty[T])
implicit def l[T] : Monoid[List[T]] = Monoid(List.empty[T])
def mzero[A]()(implicit m: Monoid[A]) : A = m.m0

val zero = mzero[List[Int]]()
val zero2: List[Int] = mzero()
Run Code Online (Sandbox Code Playgroud)

然后就清楚为什么会这样了。

2)在您必须设置 mzero 之后,def mzero[A]()(implicit m: Monoid[_ <: A]) : A = m.m0您启用了附加类型推断来解析存在类型。编译器从所需的返回类型中获取实际类型。如果你愿意的话你可以检查一下def mzero[A <: B, B]()(implicit m: Monoid[A]) : A = m.m0

3)当然,所有这些行为只是编译器的微妙之处,我认为这种部分情况并不需要深入理解。