2013-04-17 3 views
7

ScalaのOrderingの形質が反則でない理由はありますか?動機付けの例が続きます。スカラ:規則の逆順を注文する

注文したインサートを実行したいとします。私はタイプAのスーパータイプを受け入れるOrderingを持って、署名ここ

def insert[A, B >: A](list: List[A], item: A)(implicit ord: Ordering[B]): List[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) 
} 

私は私の挿入機能はタイプList[CodeTree]List[Leaf]またはList[Fork]で作業したいと思います。しかし、Orderingは反則ではないので、caseごとに暗黙的にOrderingsを定義する必要があります。

私は予想通り

trait MyOrdering[-A] { 
    def compare(a: A, b: A): Int 
} 

すべての作品を定義した場合。

私の目標を達成する他の方法はありますか?

EDIT:

私の現在のソリューションは、List[CodeTree]を扱うときに正常に動作

def insert[A](list: List[A], item: A)(implicit ord: Ordering[A]): List[A] 

として、インサートを定義することです。私はまた、(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]インスタンスに対して暗黙のファクトリ関数を定義しています。 、これらの方法は反変であることから、それを防ぐため、現在のAPIで

+2

最も具体的な注文を見つけることができないタイプ推論に関連する技術的な問題のようです。詳細はhttp://scala-programming-language.1934581.n4.nabble.com/Contravariant-Ordering-T-java-util-Comparator-and-uncheckedVariance-td1955224.htmlを参照してください。 – Impredicative

+1

@Impredicative厄介な回避策で投稿を編集しました。 –

答えて

4

詳細な回答のもう少しは、上記のコメントにリンクされ「Scalaの言語」に関するスレッドから引き出されました。

Orderingが反変ではない理由は、暗黙の解決に使用される特異性の概念に合っていないということです。暗黙の解決は、パラメータの最も「特定の」タイプを選択しようとし、あるタイプがそのタイプのサブタイプである場合、他のタイプよりもより具体的であると考えます。これは共変の場合に意味があります。私はむしろ、古いリストのリストよりも、文字列のリストに暗黙的に固有のものを持っています。

trait Ord[-A] 
A <: B 
Ord[B] <: Ord[A] 

そしてそれが利用可能な場合、Ordering[Any]として「最も具体的な」順序を選択します:反変のケースでは、しかし、それは間違ったことを選択したいと考えています。

big discussionは「特異性」の変化を続けているように見えますが、scala-languageグループの反例のあるパラメータに関して定義されています。

+0

ああ、私は問題を見る。私はScalaの2日目がよりスムーズになることを願っていました! –

2

/** Return `x` if `x` >= `y`, otherwise `y`. */ 
    def max(x: T, y: T): T = if (gteq(x, y)) x else y 

    /** Return `x` if `x` <= `y`, otherwise `y`. */ 
    def min(x: T, y: T): T = if (lteq(x, y)) x else y 
+0

しかし 'max'と' min'は 'T'のサブタイプに対してパラメトリングすることで修正できます。 – Impredicative

+0

True - 最も具体的な引数解決が最も正確な答えになります。 – axel22

関連する問題