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

Come dovrebbe essere ovvio dal codice precedente, sto provando a scrivere un metodo che, quando importato in ambito, renderà transitive le conversioni implicite. Mi aspettavo che questo codice funzionasse, ma sorprendentemente no. Che cosa significa il messaggio di errore sopra riportato e come posso far funzionare questo codice?Messaggio di errore curioso relativo agli impliciti

risposta

4

Aggiornamento: Come notato nei commenti, questo approccio non compilare il 2,8, e mentre implicitly[Foo => Baz] funziona correttamente, (new Foo).lol non lo fa.


Questo funziona bene se si rinomina il tuo transitive-conforms ombreggiare il metodo in Predef:

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

Vedere this answer per maggiori dettagli.


Come nota a margine: l'avvio del REPL con -Xlog-implicits è un modo pratico per ottenere messaggi di errore più informativo in situazioni come questa. In questo caso non è di molto aiuto in un primo momento:

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. 

Ma se riscriviamo temporaneamente foo2Bar e bar2Baz essere funzioni, otteniamo un messaggio di errore che mette in evidenza l'ambiguità:

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 

Ora è il chiaro che abbiamo solo bisogno di ombra conforms.

+0

Grazie a Travis, ma ancora non funziona per me dopo la ridenominazione come mi hai suggerito. http://ideone.com/KV0aY – missingfaktor

+0

@missingfaktor: Funziona per me in 2.9.1. Daremo un'occhiata al 2.8. –

+0

L'ho provato su 2.9.1. L'espressione 'implicitamente [Foo => Baz]' funziona, ma '(new Foo) .lol' no. – missingfaktor

Problemi correlati