2011-10-29 2 views
6
scala> implicit def transitive[A, B, C](implicit f: A => B, g: B => C): A => C = f andThen g 
transitive: [A, B, C](implicit f: A => B, implicit g: B => C)A => C 

scala> class Foo; class Bar; class Baz { def lol = println("lol") } 
defined class Foo 
defined class Bar 
defined class Baz 

scala> implicit def foo2Bar(f: Foo) = new Bar 
foo2Bar: (f: Foo)Bar 

scala> implicit def bar2Baz(f: Bar) = new Baz 
bar2Baz: (f: Bar)Baz 

scala> implicitly[Foo => Baz] 
<console>:14: error: diverging implicit expansion for type Foo => Baz 
starting with method transitive in object $iw 
       implicitly[Foo => Baz] 

Comme il ressort du code ci-dessus, j'essaie d'écrire une méthode qui, une fois importée dans la portée, rendra les conversions implicites transitives. Je m'attendais à ce que ce code fonctionne, mais ce n'est pas étonnant. Que signifie le message d'erreur ci-dessus et comment puis-je faire fonctionner ce code?Message d'erreur curieux concernant les implicites

Répondre

4

Mise à jour: Comme il est indiqué dans les commentaires, cette approche ne compile pas sur 2,8, et tout implicitly[Foo => Baz] fonctionne correctement, (new Foo).lol ne fonctionne pas.


Cela fonctionne très bien si vous renommez votre transitive-conforms à l'ombre de la méthode Predef:

implicit def conforms[A, B, C](implicit f: A => B, g: B => C): A => C = f andThen g 

Voir this answer pour plus de détails.


Comme une note de côté: à partir de la REPL avec -Xlog-implicits est un moyen pratique pour obtenir des messages d'erreur plus d'information dans des situations comme celle-ci. Dans ce cas, il n'y a pas beaucoup d'aide dans un premier temps:

scala> implicitly[Foo => Baz] 
scala.this.Predef.conforms is not a valid implicit value for Foo => Baz because: 
type mismatch; 
found : <:<[Foo,Foo] 
required: Foo => Baz 
<console>:14: error: diverging implicit expansion for type Foo => Baz 
starting with method transitive in object $iw 
       implicitly[Foo => Baz] 
         ^
scala.this.Predef.conforms is not a valid implicit value for Foo => Baz because: 
type mismatch; 
found : <:<[Foo,Foo] 
required: Foo => Baz 
transitive is not a valid implicit value for Unit => Foo => Baz because: 
not enough arguments for method transitive: (implicit f: A => B, implicit g: B => C)A => C. 
Unspecified value parameter g. 
transitive is not a valid implicit value for => Unit => Foo => Baz because: 
not enough arguments for method transitive: (implicit f: A => B, implicit g: B => C)A => C. 
Unspecified value parameter g. 

Mais si nous réécrivons temporairement foo2Bar et bar2Baz être fonctions, nous obtenons un message d'erreur qui met en évidence l'ambiguïté:

implicit val foo2Bar = (_: Foo) => new Bar 
implicit val bar2Baz = (_: Bar) => new Baz 

scala> implicitly[Foo => Baz] 
transitive is not a valid implicit value for Foo => Baz because: 
ambiguous implicit values: 
both method conforms in object Predef of type [A]=> <:<[A,A] 
and value foo2Bar in object $iw of type => Foo => Bar 
match expected type Foo => B 

Maintenant, il est clair que nous avons juste besoin d'ombre conforms.

+0

Merci Travis, mais cela ne fonctionne toujours pas pour moi après avoir renommé comme vous l'avez suggéré. http://ideone.com/KV0aY – missingfaktor

+0

@missingfaktor: Cela fonctionne pour moi dans 2.9.1. Je vais jeter un oeil à 2.8. –

+0

Je l'ai testé sur 2.9.1. L'expression 'implicitly [Foo => Baz]' fonctionne, mais '(new Foo) .lol' ne fonctionne pas. – missingfaktor