2011-12-12 4 views
4

Pourquoi la conversion implicite suivante ne fonctionne-t-elle pas même si l'appel explicite fonctionne?Pourquoi cette conversion implicite Scala échoue-t-elle lorsque la conversion explicite fonctionne?

scala> implicit def view[A, C](xs: C)(implicit ev: C <:< Iterable[A]) = new { def bar = 0 } 
view: [A, C](xs: C)(implicit ev: <:<[C,scala.collection.immutable.Iterable[A]])java.lang.Object{def bar: Int} 

scala> List(1) bar 
<console>:147: error: Cannot prove that List[Int] <:< scala.collection.immutable.Iterable[A]. 
       List(1) bar 
       ^

scala> view(List(1)) bar 
res37: Int = 0 
+0

J'ai mis votre code dans l'EDI scala eclipse et il l'a échoué sur trois points - la vue de la valeur n'est pas un membre de AnyRef (barre de def: Int) Note: vue implicite non applicable ici; identifiant attendu mais '[' trouvé; introuvable: erreur de type. –

Répondre

0

Je ne suis pas vraiment répondre à votre question (à savoir, je réponds à « comment puis-je faire ce travail », mais pas « pourquoi cela ne fonctionne pas »); de toute façon j'espère que cela aidera quelqu'un d'autre à faire quelques progrès vers une réponse. ... Dans le premier cas, le compilateur ne peut pas déduire correctement que A est un Int, étant donné que C est un List [Int]. Honnêtement, je suis plus surpris que le passage de la liste fonctionne explicitement, puisque la relation entre A et C est si indirecte (vous avez A et C, puisque C est un sous-type de Iterable [A] et puisque C est une liste [ Int], alors A doit être un Int, pas une inférence très directe ...).

Vous pouvez le faire fonctionner en étant plus explicite au sujet de la relation entre C et A, comme ceci:

scala> implicit def view[A, C[A]](xs: C[A])(implicit ev: C[A] <:< Iterable[A]) = 
     new { def bar = 0 } 
view: [A, C[A]](xs: C[A])(implicit ev: <:<[C[A],Iterable[A]])java.lang.Object{def bar: Int} 

scala> List(1) bar 
res0: Int = 0 

ou (étant donné que vous ne l'utilisez A):

scala> implicit def view[C](xs: C)(implicit ev: C <:< Iterable[_]) = 
     new { def bar = 0 } 

scala> List(1) bar 
res1: Int = 0 
+0

Cependant, cela contraint le type de xs à être un constructeur de type unaire appliqué; tous les autres types sont exclus. Voir une explication ici à http://suereth.blogspot.com/2011/06/generic-quicksort-in-scala.html. – Yang

+0

whoa, c'est un type-fu de ceinture noire là-bas! Je vois que ma "solution" est en train de casser la signature de type soigneusement construite de votre méthode, mais il me faudra du temps pour ingérer le reste du message que vous avez envoyé ... Cependant, FWIW, ma deuxième définition de la vue fonctionne toujours avec des constructeurs de type non unaires. Je l'ai testé avec la classe Foo (t: List [Int]) étend Iterable [Int] {def itérateur: Iterator [Int] = t.iterator} ', qui n'a pas de paramètres de type, et' (nouveau Foo (Liste (1))). Voir bar fonctionne. –

0

En termes simples, comme le suggère le message d'erreur, il ne peut en déduire A. Il n'y a aucune information que le compilateur peut utiliser pour déduire ce que doit être A, donc il doit supposer que cela peut être n'importe quoi.

Vous pourriez rétorquer qu'il peut déduire A de C <:< Iterable[A], mais qui transformerait le problème sur la tête: au lieu d'utiliser <:< pour vérifier les contraintes, il utiliserait les contraintes pour déduire le type de A! Cette logique n'est pas saine.

+0

Mais avec la plupart des prouveurs de type unification, l'information doit circuler dans les deux directions et être résolue au milieu. Considérons l'appel explicite, qui fonctionne et déduit 'A'. – Yang

Questions connexes