11

我有这样的特点:

trait CanFold[-T, R] {
  def sum(acc: R, elem: T): R
  def zero: R
}

使用这样的功能:

def sum[A, B](list: Traversable[A])(implicit adder: CanFold[A, B]): B = 
  list.foldLeft(adder.zero)((acc,e) => adder.sum(acc, e))

目的是做这样的事情:

implicit def CanFoldSeqs[A] = new CanFold[Traversable[A], Traversable[A]] {
  def sum(x: Traversable[A], y: Traversable[A]) = x ++ y
  def zero = Traversable()
}

sum(List(1, 2, 3) :: List(4, 5) :: Nil)
//=> Traversable[Int] = List(1, 2, 3, 4, 5)

因此,对于环境已经知道如何折叠并且可以为 Ints、Strings 等定义的类型,它是一个类型类。

我的问题是我还希望有更具体的隐式优先,如下所示:

implicit def CanFoldSets[A] = new CanFold[Set[A], Set[A]] {
  def sum(x: Set[A], y: Set[A]) = x ++ y
  def zero = Set.empty[A]
}

sum(Set(1,2) :: Set(3,4) :: Nil)
//=> Set[Int] = Set(1, 2, 3, 4)

但是,该方法调用会产生冲突,因为存在歧义:

both method CanFoldSeqs in object ...
and method CanFoldSets in object ...
match expected type CanFold[Set[Int], B]

所以我想要的是让编译器在 Any 和我的类型之间搜索最具体的隐式。目的是为基类型提供默认实现,可以轻松地为更具体的子类型覆盖这些实现,而不会出现丑陋的阴影。

我可能在这里一厢情愿,但只能希望:-)

4

1 回答 1

15

在这种情况下,通常的方法利用了隐式按继承优先级的方式:

trait LowPriorityCanFoldInstances {
  implicit def CanFoldSeqs[A] = new CanFold[Traversable[A], Traversable[A]] {
    def sum(x: Traversable[A], y: Traversable[A]) = x ++ y
    def zero = Traversable()
  }
}

object CanFoldInstances extends LowPriorityCanFoldInstances {
  implicit def CanFoldSets[A] = new CanFold[Set[A], Set[A]] {
    def sum(x: Set[A], y: Set[A]) = x ++ y
    def zero = Set.empty[A]
  }
}

import CanFoldInstances._

现在该Set实例将在适用时使用,但 forTraversable在不适用时仍然可用。

于 2012-11-02T13:26:53.907 回答