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)

つまり、これは、環境がすでに折り畳み方法を知っている型の型クラスであり、Int、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インスタンスが使用されますが、Traversableそうでない場合は引き続き使用できます。

于 2012-11-02T13:26:53.907 に答える