统一类中的视图边界

时间:2013-06-25 14:07:58

标签: scala typeclass

我一直在努力寻找一种方法来处理以下情况,我希望找到一个统一类型参数的公共视图(或超类),这样我就可以访问一个比较苹果和苹果的类型类:

case class Foo[A](i:A) {
  def cmp[B:Ordering, C <% B](b:B)(implicit ev: A => B) = implicitly[Ordering[B]].lt(i,b)
}
// Foo(1).cmp(2.0) works
// Foo(1.0).cmp(2) complains about evidence of Double => Int

现在,这可以通过一个简单的函数来完成:

def cmp[A:Ordering](a1:A, a2:A) = implicitly[Ordering[A]].lt(a1,a2)
// cmp(Foo(1).a, 1.0)
// cmp(Foo(1.0).a, 1)

然而,我希望它作为Foo的方法存在。关于我可以做什么来强制它使用视图边界的任何想法?

1 个答案:

答案 0 :(得分:1)

您可以依赖类型类。有点沉重,但有效:

trait Cmp[A,B] {
  def cmp( a: A, b: B ): Boolean
}
trait LowPriorityCmpImplicits {
  implicit def cmp1[A,B]( implicit conv: A => B, ord: Ordering[B] ) = new Cmp[A, B]{ 
    def cmp( a: A, b: B ) = ord.lt(conv(a), b) 
  }
}
object Cmp extends LowPriorityCmpImplicits {
  implicit def cmp2[A,B]( implicit conv: B => A, ord: Ordering[A] ) = new Cmp[A, B]{ 
    def cmp( a: A, b: B ) = ord.lt(a, conv(b)) 
  }
}

case class Foo[A](i:A) {
  def cmp[B](b: B)(implicit cmp: Cmp[A,B]) = cmp.cmp( i, b )
}

LowPriorityCmpImplicits特征是为了避免两种类型相同时出现歧义(cmp2优先于cmp1) 测试:

scala> Foo(1).cmp(2.0)
res0: Boolean = true
scala> Foo(1.0).cmp(2)
res1: Boolean = true
scala> Foo(1).cmp(2)
res2: Boolean = true
scala> Foo(2).cmp(1.0)
res3: Boolean = false
scala> Foo(2.0).cmp(1)
res4: Boolean = false
scala> Foo(2).cmp(1)
res5: Boolean = false