【发布时间】:2015-08-15 04:35:30
【问题描述】:
给定一个类型类,其中应根据返回类型执行实例选择:
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
为什么 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]
^
当使用 implicitly 函数时根据返回类型找到一个隐式没有问题(我们在这里将其重新定义为 i 以说明它与 mzero)
def i[A](implicit a : A) : A = a
scala> i : Monoid[List[Int]]
res18: Monoid[List[Int]] = Monoid(List())
错误消息中的Monoid[A],而不是Monoid[List[Int]],令人费解。
我假设许多 scalaz 贡献者都熟悉这个问题,因为它似乎限制了 scala 中类型类的便利性。
编辑:我正在考虑在不放弃类型推断的情况下使其正常工作。否则,我想了解为什么这是不可能的。如果这个限制被记录为 Scala 问题,我找不到它。
【问题讨论】:
-
Scala 在涉及隐式时使用预期返回类型来指导类型参数推断的能力的限制令人难以置信,所以每个人都只写
mzero[List[Int]]。 -
作为一些解决方法,您可以通过将
mzero重新定义为def mzero[A](implicit m: Monoid[_<:A]) : A = m.m0来摆脱困境。正如 Travis Brown 所说,我个人会选择mzero[List[Int]]。 -
令人印象深刻和令人惊讶。谢谢!有什么解释吗?这似乎是放松类型并获得更少的匹配!
-
抱歉,不,我无法解释这种行为。只是经验告诉我尝试使
Monoid协变,这确实使代码编译。由于您可能无法使其成为协变的(假设Monoid的完整定义会在逆变位置出现A),下一个最好的方法是尝试通过使用存在类型单独在mzero上模拟它,给def mzero[A](implicit m: Monoid[_<:A])。我肯定有兴趣亲自解释这种奇怪的情况。
标签: scala type-inference implicit return-type scalaz