2015-10-28 3 views
3

J'ai réfléchi à un problème de conception dans une bibliothèque sur laquelle je travaille et j'ai réalisé que l'utilisation de types existentiels peut me permettre de modifier mon design de manière à simplifier de nombreuses parties de ma bibliothèque . Cependant, je n'arrive pas vraiment à le faire fonctionner.Type existentiel de Kind-Kinded

Il me semble que myBuilder est conforme au type MultiSignalBuilder[E, R] forSome { type E[+X] >: Element[X] }, où Element[X] est MultiSignalElement[X], mais le compilateur dit qu'il does't. Il semble devoir faire le fait que E est un type plus élevé. Pourquoi cela ne fonctionne-t-il pas, et y a-t-il un moyen de le réparer?

class MultiSignalElement[+T] { 
    } 

    abstract class MultiSignal[+T] { 
    type Element[+X] <: MultiSignalElement[X] 

    val element : Element[T] 

    def transform[R[+X] <: MultiSignal[X]](builder : MultiSignalBuilder[E, R] forSome { type E[+X] >: Element[X] }) : R[T] = 
     builder.buildNew(element) 
    } 

    abstract class MultiSignalBuilder[-E[+X] <: MultiSignalElement[X], +R[+X] <: MultiSignal[X]] { 
    def buildNew[T](element : E[T]) : R[T] 
    } 

    object myBuilder extends MultiSignalBuilder[MultiSignalElement, MultiSignal] { 
    def buildNew[T](e : MultiSignalElement[T]) = new MultiSignal[T]() { 
     type Element[+X] = MultiSignalElement[X] 

     val element = e 
    } 
    } 

    val multiSignal = new MultiSignal[Int] { 
    type Element[+X] = MultiSignalElement[X] 

    val element = new MultiSignalElement() 
    } 

    multiSignal.transform(myBuilder) //type error on this line 
    multiSignal.transform[MultiSignal](myBuilder) //type error on this line 
+0

En fait je ne pouvais toujours pas compiler une version existential-less avec scala 2.11.7 – Odomontois

+0

Pourriez-vous donner plus de détails sur la motivation derrière ce morceau de code? Qu'est-ce qu'il est censé accomplir exactement? Corriger les erreurs de compilation sans comprendre la signification du code est assez difficile ... –

+0

@Odomontois, Ouais, on dirait qu'il a compilé. Mais, en fait, les erreurs de compilation étaient juste préemptées par d'autres erreurs dans le projet dans d'autres fichiers. Donc, je l'ai enlevé. – Nimrand

Répondre

4

Procédons étape par étape.

D'abord, nous avons

def transform[R](builder : MultiSignalBuilder[E, R] forSome { type E[+X] >: Element[X] }) : Unit = { } 

ce qui équivaut à la déclaration: il existe

type E[+X] >: Element[X] 

Pour que nous pouvons définir

def transform[E[+X] >: Element[X], R[+_]](builder : MultiSignalBuilder[E, R]) : Unit = { } 

Ici nous avons une erreur

Error:(7, 18) covariant type X occurs in contravariant position in type [+X] >: MultiSignal.this.Element[X] of type E

C'est quelque chose. Vous attendez que votre mystérieux type covariant existentiel soit un supertype d'un autre type covariant. Je pense que c'est la première chose qui effraie le compilateur. Permet de relation de changement de sous-typage

def transform[E[+X] <: Element[X], R[+_]](builder : MultiSignalBuilder[E, R]) : Unit = { } 

Maintenant, nous avons

Error:(7, 56) type arguments [E,R] do not conform to class MultiSignalBuilder's type parameter bounds [-E[+X] <: MultiSignalElement[X],+R[+X] <: MultiSignal[X]]

Nous avons donc oublié d'exiger de sous-typage MultiSignal[X] de paramètre R.

Permet de changer

def transform[E[+X] <: Element[X], R[+X] <: MultiSignal[X]](builder : MultiSignalBuilder[E, R]) : Unit = { } 

maintenant

multiSignal.transform[MultiSignalElement,MultiSignal](myBuilder) 

est-il compilé correctement.

Enfin, nous pourrions revenir à la version existentielle

def transform[R[+X] <: MultiSignal[X]](builder : MultiSignalBuilder[E, R] forSome {type E[+X] <: Element[X]}) : Unit = { } 

Avec qui

multiSignal.transform[MultiSignal](myBuilder) 

est-il compilé correctement.

Malheureusement

multiSignal.transform(myBuilder) 

n'est pas encore compilé. Je pense qu'il y a trop de relations de type à résoudre pour le compilateur.

+1

Malheureusement, je ne peux pas utiliser E [+ X] <: Element [X], pour des raisons que vous ne pouviez pas connaître à cause des simplifications que j'ai faites. Voir ma question mise à jour avec le code mis à jour. Je vais jouer avec ça et voir ce que je peux faire, mais je vais devoir repenser cette approche. Merci pour l'aide. – Nimrand

+0

Je pense que je l'ai réparé. Il est descendu sur le fait que j'ai défini X est covariant dans E dans la définition de MultiSignalBuilder. Bien que cela soit généralement vrai, c'est une contrainte inutile. Une fois que j'ai enlevé cela, je pourrais également enlever la covariance de X sur E dans le paramètre de type de transformation, et il compile. Même l'inférence de type fonctionne correctement. – Nimrand