2013-06-04 16 views
5

Sto cercando di ottenere una migliore comprensione del seguente comportamento:tipo Scala limiti e varianza

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] 
        ^

Tuttavia le seguenti opere:

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

posso vedere che ci potrebbero essere problemi dalla la varianza delle variabili delimitate e delimitate è opposta, sebbene non sia chiaro su quale sia il problema specifico. Sono ancora meno chiaro sul perché cambiare il tipo associato a una vista associata rende le cose ok. In assenza di conversioni implicite applicabili, mi aspetto che le due definizioni abbiano in gran parte lo stesso effetto. Se mai, mi aspetterei che una vista sia destinata a offrire maggiori opportunità di malizia.

Per un po 'di background che definisce le classi che sono in qualche modo come funzioni, e volevo fare qualcosa di simile

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

Probabilmente

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

in realtà è preferibile, ma avrei ancora piace capire meglio cosa sta succedendo qui.

+0

Intrigante ... ho speso 1 ora alla ricerca di un esempio in cui il tipo interruzioni di sicurezza con il tipo vincolato. Nessuna trovata :( – gzm0

+0

Anche se c'era un esempio non corretto con il tipo rilegato, è difficile vedere come la sostituzione in una vista vincolata lo risolvesse. –

+0

Sì, sono d'accordo, ma la differenza fondamentale è che la vista è vincolata si converte sempre in base ai tipi con cui è stata creata la classe, mentre questo non è necessariamente il caso con il tipo associato (dice la mia intuizione almeno ...) – gzm0

risposta

4

Innanzitutto il facile:

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

Ciò equivale a

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

Poiché view non è pubblicamente restituito, non è in una posizione che la varianza di A o B. Per esempio.

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

In altre parole, C[-A, +B <% A] non è diverso da C[-A, +B] in termini di vincoli, l'argomento vista non cambia nulla.


La custodia con rilegatura superiore C[-A, +B <: A] Non ne sono sicuro. La Specifica della lingua di Scala in §4.5 afferma

La posizione di variazione del limite inferiore di una dichiarazione di tipo o di un parametro di tipo è l'opposto della posizione di scostamento della dichiarazione o del parametro di tipo.

La varianza di B non sembra essere coinvolto, ma generalmente il limite superiore deve essere covariante:

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

Questo deve in qualche modo produrre un problema? Ma non sono riuscito a trovare un esempio che dimostrasse come questa costruzione non sia corretta in un caso particolare ....


Per quanto riguarda la funzione composta, perché non basta

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

EDIT: Per esempio:

import collection.LinearSeq 

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

Interessante, grazie. Non pensavo di provare 'tratto C [-A, B <: A] '. Ho solo pensato che dovevano essere le varianze opposte –

+0

Sì, si compongono, esattamente a causa della varianza di' Function1' –

+0

classe 'CompositeFunc [-A, B, + C]' non ti permetterebbe di comporre 'f: BaseFunc (Traversable [A], IndexedSeq [A])' con 'g: BaseFunc (Traversable [A], LinearSeq [A])' anche se le loro composizioni hanno perfettamente senso in entrambi gli ordini. –