Ordering
Scala的特征不是逆变的有什么原因吗?下面是一个鼓舞人心的例子。
假设我要执行有序插入。我可能有一个带有签名的功能
def insert[A, B >: A](list: List[A], item: A)(implicit ord: Ordering[B]): List[A]
在这里,我有一个Ordering
接受超类型的 type A
。我想这在您处理case classes
. 例如:
abstract class CodeTree
case class Fork(left: CodeTree, right: CodeTree, chars: List[Char], weight: Int) extends CodeTree
case class Leaf(char: Char, weight: Int) extends CodeTree
def weight(tree: CodeTree): Int
def chars(tree: CodeTree): List[Char]
implicit object CodeTreeOrdering extends Ordering[CodeTree] {
def compare(a: CodeTree, b: CodeTree): Int = weight(a) compare weight(b)
}
我希望我的 insert 函数可以与typesList[CodeTree]
或. 但是,由于不是逆变的,我需要为每个.List[Leaf]
List[Fork]
Ordering
Orderings
case
如果我定义
trait MyOrdering[-A] {
def compare(a: A, b: A): Int
}
一切都按预期工作。
还有其他方法可以实现我的目标吗?
编辑:
我目前的解决方案是将插入定义为
def insert[A](list: List[A], item: A)(implicit ord: Ordering[A]): List[A]
处理时效果很好List[CodeTree]
。我还定义(受 scalaz 库的启发):
trait Contravariant[F[_]] {
def contramap[A, B](r: F[A], f: B => A): F[B]
}
implicit object OrderingContravariant extends Contravariant[Ordering] {
def contramap[A, B](r: Ordering[A], f: B => A) = r.on(f)
}
implicit def orderingCodeTree[A <: CodeTree]: Ordering[A] =
implicitly[Contravariant[Ordering]].contramap(CodeTreeOrdering, identity)
我正在为Ordering[A <: CodeTree]
实例定义一个隐式工厂函数。