2013-06-04 15 views
5

Ich versuche, ein besseres Verständnis für das folgende Verhalten zu erhalten:Scala Typ Grenzen & Varianz

scala> class C[-A, +B <: A] 
<console>:7: error: contravariant type A occurs in covariant position 
        in type >: Nothing <: A of type B 
     class C[-A, +B <: A] 
        ^

jedoch folgende Arbeiten:

scala> class C[-A, +B <% A] 
defined class C 

ich sehen kann, dass es Fragen aus dem sein könnte Varianz der begrenzenden und beschränkten Variablen ist entgegengesetzt, obwohl ich nicht klar bin, was das spezifische Problem ist. Ich bin noch weniger klar darüber, warum die Änderung des Typs, der an eine Ansicht gebunden ist, die Dinge in Ordnung bringt. In Ermangelung anwendbarer impliziter Umrechnungen würde ich erwarten, dass die beiden Definitionen weitgehend denselben Effekt haben. Wenn überhaupt, würde ich erwarten, dass eine Sichtweise mehr Möglichkeiten für Unfug bietet.

Für ein bisschen Hintergrund I-Klassen definieren, die in gewisser Weise wie Funktionen sind, und ich wollte so etwas wie

CompositeFunc[-A, +B <: C, -C, +D] (f1 : BaseFunc[A, B], f2 : BaseFunc[C, D]) 
    extends BaseFunc[A, D] 

Diskutierbar

CompositeFunc[-A, +B <% C, -C, +D] (f1 : BaseFunc[A, B], f2 : BaseFunc[C, D]) 
    extends BaseFunc[A, D] 

ist eigentlich bevorzugt tun, aber ich würde immer noch mag es besser zu verstehen, was hier vor sich geht.

+0

Intriguing ... I 1 Stunde lang die Suche nach einem Beispiel, bei dem Typ Sicherheit bricht mit dem gebundenen Typ. Keine gefunden :( – gzm0

+0

Auch wenn es ein Beispiel gab, das mit dem Typ gebunden war, ist es schwer zu sehen, wie das Ersetzen in einer Ansichtsgrenze es beheben würde. –

+0

Ja, ich stimme etwas zu. Aber der grundlegende Unterschied ist, dass die Ansicht gebunden ist konvertiert immer nach den Typen, mit denen die Klasse erstellt wurde, während dies bei dem gebundenen Typ nicht unbedingt der Fall ist (sagt zumindest meine Intuition ...) – gzm0

Antwort

4

Zuerst wird die einfache:

class C[-A, +B <% A] 

Dies entspricht

class C[-A, +B](implicit view: B => A) 

Da view nicht öffentlich zurückgegeben, es ist nicht in der Lage, die die Varianz von A oder B einschränken würde. Z.B.

class C[-A, +B](val view: B => A) // error: B in contravariant position in view 

Mit anderen Worten, ist C[-A, +B <% A] nicht anders als C[-A, +B] in Bezug auf die Zwänge, wird die Ansicht Argument nichts ändern.


Die obere Grenze Fall C[-A, +B <: A] Ich bin mir nicht ganz sicher. Die Scala Language Specification in §4.5 states

Die Varianzposition der Untergrenze einer Typdeklaration oder eines Typparameters ist das Gegenteil der Varianzposition der Typdeklaration oder des Parameters.

Die Varianz von B scheint nicht beteiligt zu sein, aber in der Regel die obere Schranke muss covariant sein:

trait C[-A, B <: A] // contravariant type A occurs in covariant position 

Dieses Problem irgendwie produzieren müssen? Aber ich konnte mir kein Beispiel vorstellen, das beweist, dass diese Konstruktion in einem bestimmten Fall nicht tragfähig ist ....


Wie für die zusammengesetzte Funktion, warum nicht nur

class Composite[-A, B, +C](g: A => B, h: B => C) extends (A => C) { 
    def apply(a: A) = h(g(a)) 
} 

EDIT: Zum Beispiel:

import collection.LinearSeq 

def compose[A](g: Traversable[A] => IndexedSeq[A], h: Traversable[A] => LinearSeq[A]) = 
    new Composite(g, h) 
+0

Interessant, danke, ich habe nicht daran gedacht, 'Merkmal C 'zu versuchen [-A, B <: A] '. Ich dachte nur, es müssten die entgegengesetzten Varianzen sein. –

+0

Ja, sie komponieren, genau wegen der Varianz von' Function1' –

+0

Klasse 'CompositeFunc [-A, B, + C]' würde es dir nicht erlauben 'f: BaseFunc (Traversable [A], IndexedSeq [A])' mit 'g: BaseFunc (Traversable [A], LinearSeq [A])' zu komponieren, obwohl ihre Kompositionen in beiden Ordnungen Sinn ergeben. –