2013-03-15 3 views
4

En essayant de répondre à this question, je suis venu avec le code suivant:résolution Scala de plusieurs paramètres implicites

case class Monkey(bananas: Int) 
    case class Tree(rings: Int) 
    case class Duck(quacks: Seq[String]) 

    implicit class IntLike(val x : Int) extends AnyVal 

    implicit def monkey2Age(monkey: Monkey): IntLike = monkey.bananas/1000 
    implicit def tree2Age(tree: Tree): IntLike = tree.rings 
    implicit def duck2Age(duck: Duck): IntLike = duck.quacks.size/100000 

    def purchaseCandles[A <% IntLike]()(implicit age : A) = { 
     val asAge : IntLike = age 
     println(s"I'm going to buy $asAge candles!") 
    }    

    { 
     implicit val guest = Tree(50) 
     purchaseCandles() 
    } 

Notez que le IntLike est seulement là pour me convaincre ce n'était pas un problème axé sur Int.

Cela semble être une utilisation assez standard, si mauvaise, d'implicits, et je m'attendais à ce qu'il fonctionne bien. Cependant, sur l'appel purchaseCandles() REPL donne l'erreur suivante:

error: ambiguous implicit values: both value StringCanBuildFrom in object Predef of type => scala.collection.generic.CanBuildFrom[String,Char,String] and value guest of type Tree match expected type A

Je ne peux pas pour la vie de me voir comment cela est le cas. A est lié à avoir une vue liée à IntLike, un type que je viens d'inventer. Le REPL confirme qu'il n'y a pas de vue implicite disponible:

scala> implicitly[Tree => IntLike]

res14: Tree => IntLike = function1

mais

scala> implicitly[scala.collection.generic.CanBuildFrom[String, Char, String] => IntLike]

:18: error: No implicit view available from scala.collection.generic.CanBuildFrom[String,Char,String] => IntLike.

Alors, comment peut StringCanBuildFrom être d'un type approprié? Le compilateur est-il capable de résoudre les implicites dépendants multiples, et si non, pourquoi cette erreur est-elle affichée?

Répondre

1

Avant de tenter une réponse, voici d'abord le cas réduit. Notez que vous appelez purchaseCandles sans aucune allusion sur le type A qui je pense est à l'origine du problème.

object Foo 

def test[A <% Foo.type](implicit bar: A) {} 

test 

Erreur:

<console>:10: error: ambiguous implicit values: 
both value StringCanBuildFrom in object Predef of type => 
    scala.collection.generic.CanBuildFrom[String,Char,String] 
and method conforms in object Predef of type [A]=> <:<[A,A] 
match expected type A 
       test 
      ^

Le StringCanBuildFrom ressemble plus à un message d'erreur de confusion. Si vous vous concentrez sur conforms ici, la raison pour laquelle cela ne fonctionne pas pourrait devenir plus claire: Predef.conform stipule que chaque fois que vous demandez une conversion implicite A => A, cela est garanti au moyen de l'identité. C'est ainsi que si vous avez def foo[B <% A](b: B), vous pouvez toujours appeler foo avec une valeur de type A sans avoir besoin de définir une sorte de A => A.


Vous demandez la résolution de l'argument implicite d'un de type non spécifié avec une conversion de ce type non spécifié -IntLike. Je pense que cela dépasse la portée de l'algorithme de résolution implicite. Encore le message d'erreur est quelque peu étrange.

+0

Oui , être au-delà de la portée de la résolution implicite semble probable, mais le message est confus. Tout fonctionne si vous spécifiez explicitement le paramètre type: 'test [Foo.type]' dans votre exemple. – Impredicative

0

toujours pas d'explication pourquoi il ne-même si, comme on dit, je pense que c'est trop pour la résolution implicite en raison de la type- d'entrée non définie, mais vous pouvez le faire fonctionner comme ceci:

implicit def findIntLike[A <% IntLike](x: A): IntLike = x 
    def purchaseCandles()(implicit age: IntLike) = { 
     println(s"I'm going to buy $age candles!") 
    }    

    implicit val guest = Tree(50) 
    purchaseCandles() 
Questions connexes