2011-10-29 20 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] 

Jak wynika z powyższego kodu, próbuję napisać metodę, która po zaimportowaniu do zakresu spowoduje przechodzenie domyślne konwersji. Spodziewałem się, że ten kod zadziała, ale, co zaskakujące, nie działa. Co oznacza powyższy komunikat o błędzie i jak mogę sprawić, aby ten kod działał?Ciekawy komunikat o błędzie dotyczący implicitów

Odpowiedz

4

Aktualizacja: Jak zauważył w komentarzach, to podejście nie kompiluje się na 2,8, a jednocześnie implicitly[Foo => Baz] działa poprawnie, (new Foo).lol nie.


Działa to dobrze, jeśli zmienić nazwę transitive do conforms do cienia metodę w Predef:

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

Zobacz this answer więcej szczegółów.


Na marginesie: Uruchamianie rEPL z -Xlog-implicits jest wygodnym sposobem, aby uzyskać bardziej informacyjne komunikaty o błędach w tego typu sytuacjach. W tym przypadku to nie jest dużo pomocy najpierw:

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. 

Ale jeśli tymczasowo przepisać foo2Bar i bar2Baz się funkcje, otrzymamy komunikat o błędzie, który podkreśla dwuznaczność:

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 

teraz nadszedł jasne, że musimy po prostu ocalić conforms.

+0

Dzięki Travis, ale nadal nie działa dla mnie po zmianie nazwy zgodnie z sugestią. http://ideone.com/KV0aY – missingfaktor

+0

@missingfaktor: działa dla mnie w wersji 2.9.1. Przyjrzę się 2.8. –

+0

Przetestowałem to na 2.9.1. Wyrażenie 'implicite [Foo => Baz]' działa, ale '(new Foo) .lol' nie działa. – missingfaktor

Powiązane problemy