2016-02-27 17 views
8

Ho uno strano errore del compilatore su un implicito che è effettivamente presente ma non è stato trovato per un motivo. Quindi ho costruito un piccolo test che riproduce comportamenti misteriosi.In alcuni casi, gli impliciti di alto ordine vengono ignorati?

Tipo semplice utilizzato come target non ambiguo per le conversioni implicite.

def id[H <: Hide, C](x : C)(implicit ev : C => H#T) : H#T = ev(x) 
def drop[H <: Hide, C](x : C)(implicit ev : C => H#T) : Int = { 
    println(ev(x)) 
    1 
} 
def idSeq[H <: Hide, C](x : Seq[C])(implicit ev : Seq[C] => Seq[H#T]) : Seq[H#T] = ev(x) 
def dropSeq[H <: Hide, C](x : Seq[C])(implicit ev : Seq[C] => Seq[H#T]) : Int = { 
    println(ev(x)) 
    1 
} 

I metodi che si basano su conversioni implicite. È fondamentalmente una matrice 2x2. I metodi id restituiscono il tipo convertito e i metodi drop utilizzano la conversione internamente e restituiscono una costante. I metodi normali funzionano sul tipo esattamente convertito implicitamente e i metodi Seq funzionano su sequenze.

implicit def exString(x : String) : HideString.type#T = x 
implicit def highString[F[_]](x : F[String]) : F[HideString.type#T] = x 

Sopra conversioni implicite highString è definito con il tipo di ordine superiore.

val s1 = id("sdf") 
val s2 = drop("aero") 

val r1 = idSeq(Seq("a", "bc")) 
val r2 = dropSeq(Seq("i", "IO")) 

Cercando utilizzare effettivamente conversioni mi porta un errore:

ImplicitResolution.scala:98: error: No implicit view available from Seq[String] => Seq[test.implicits.HighReduction.Hide#T]. 
    val r2 = dropSeq(Seq("i", "IO")) 

che potrebbe essere riassunto nella seguente matrice:

|  | id | drop | 
|--------+------+------| 
| normal | pass | pass | 
| seq | pass | fail | 

se uso definito con precisione conversione implicita per dropSeq metodo si trova normalmente:

implicit def seqBool(x : Seq[Boolean]) : Seq[HideBool.type#T] = x 

val a1 = idSeq(Seq(true, false)) 
val a2 = dropSeq(Seq(false, true)) 

E inoltre, se a specificare in modo esplicito implicito argomento dropSeq ha cominciato a lavorare:

val r2i = dropSeq(Seq("i", "IO"))(highString[Seq] _) 

E questa è la cosa più strana. highString implicito soddisfa tutti i requisiti. Ed è dichiarato come implicit, quindi dovrebbe essere trovato dal compilatore. E in caso di idSeq è effettivamente trovato. Quindi, perché viene ignorato nel caso dropSeq?

risposta

1

Nel tuo caso l'unica differenza tra idSeq e dropSeq è il tipo di ritorno: hai colpito un caso d'angolo nel compilatore Scala che vale la pena segnalare alla comunità di Scala.

Detto questo, il vostro idSeq ha firma errata: H#X non significa che il tipo di X per la H tipo specificato, ma piuttosto X per qualsiasi istanza di H (non quella che è stata risolta dal compilatore, vedere Daniel Sobral spiegazione qui What does the `#` operator mean in Scala?)

Quello che probabilmente vuole fare è quello di stabilire una relazione tra H e il tipo di risultato, che è più facile se si introduce tipo alias per ottenere una firma più leggibile:

object Hide { 
    type HideAux[X] = Hide { type T = X} 
} 

Puoi quindi riscrivi il tuo codice come th è:

def idSeq[B,H <: HideAux[B], C](x : Seq[C])(implicit ev : Seq[C] => Seq[B]) : Seq[B] = ev(x) 
    def dropSeq[B,H <: HideAux[B], C](x : Seq[C])(implicit ev : Seq[C] => Seq[B]) : Int = { 
    println(ev(x)) 
    1 
    } 

Questo codice di compilazione, e notare anche che se si utilizza correttamente typeclasses generici e non avrete bisogno di due metodi diversi id e idSeq perché il comportamento dinamico sta per essere fornito da typeclass sé.

+2

Sarei più propenso a concederti la taglia se hai archiviato un problema per il "caso angolo nel compilatore Scala" che descrivi. Supponevo che si trattasse di un caso d'angolo, ma non hai ancora fornito informazioni sufficienti per sapere se questo comportamento è * previsto *, o se è davvero un bug nel compilatore. Sarebbe anche bello se ti liberassi di questo '}' ... – DaoWen

+0

Le tue due funzioni hanno la stessa firma ad eccezione del tipo restituito, ma tu usi l'inferenza di tipo per r1 e r2 (quindi il tipo di ritorno non può essere usato per la risoluzione implicita). Se è possibile risolvere l'implicito per r1 con le informazioni sul tipo disponibili, è possibile risolvere l'implicito per r2: dato che drop funziona e dropSeq no, è probabile che il problema sia con le proiezioni di tipo e tipo generici. – Edmondo1984

+0

L'uso di '-Xlog-implicits' restituisce alcuni errori interessanti. –

Problemi correlati