2015-08-19 16 views
8

Perché questo non viene compilato?Limitazione dell'inferenza del tipo bizzare - parametri di tipo multiplo

trait Lol[A, SA] { 
    def flatMap[B, SB](f: A => Lol[B, SB]): Lol[B, SB] = ??? 
} 

val p1: Lol[Int, String] = ??? 
val p2: Lol[Double, Nothing] = ??? 

val p5 = p1.flatMap(_ => p2) 

Risultato:

found : Int => Lol[Double,Nothing] 
required: Int => Lol[Double,SB] 
    val p5 = p1.flatMap(_ => p2) 
         ^ 

le cose iniziano a compilare se: (? WTF)

  • tipo params di flatMap invocazione sono espliciti
  • SA è covariant
  • alcuni altro tipo di Nothing siamo noi ed in p2 (ad es. Null)
  • SB non si verifica il tipo cambio di flatMap o avviene in posizione covariante di quel tipo di ritorno (ad esempio tipo di ritorno è Option[SB])

Le soluzioni precedenti non sono comunque accettabile per me.

+1

Perché l'annotazione della varianza non è un'opzione per te? Di solito è una buona idea usare la varianza laddove possibile. L'uso di 'Nothing' la maggior parte delle volte ha senso solo in base alla varianza. –

+0

@ 0__ 'SA' semplicemente non può essere covariante data l'API completa (non mostrata qui). Comunque - hai ragione sul 'Nothing' - se' SA' non è covariante, probabilmente posso creare il mio tipo speciale invece di usare 'Nothing' – ghik

+1

Tuttavia, questo errore è ancora ridicolmente bizzarro e puzza di bug. – ghik

risposta

2

Il commento di @ retronym su SI-9453 spiega il comportamento che si sta verificando. Ecco una soluzione di sorta ...

Siamo in grado di sintetizzare un tipo equivalente a Nothing che non causerà la macchina per scrivere per ritrarre la soluzione di inferenza,

type ReallyNothing = Nothing { type T = Unit } 

es. Nothing con una raffinatezza fittizia. Ora con l'esempio della domanda,

scala> :paste 
// Entering paste mode (ctrl-D to finish) 

trait Lol[A, SA] { 
    def flatMap[B, SB](f: A => Lol[B, SB]): Lol[B, SB] = ??? 
} 

val p1: Lol[Int, String] = ??? 
val p2: Lol[Double, ReallyNothing] = ??? 

val p5 = p1.flatMap(_ => p2) 

// Exiting paste mode, now interpreting. 

scala.NotImplementedError: an implementation is missing 
    at scala.Predef$.$qmark$qmark$qmark(Predef.scala:225) 
    ... 37 elided 
2

Al fine di comprendere meglio il problema, può essere semplificata come:

class Lol[A] 
def foo[B](f: Lol[B]) = f 
foo(new Lol[Nothing]) 

che vi dà il seguente errore di compilazione:

error: type mismatch; 
found : Lol[Nothing] 
required: Lol[B] 
Note: Nothing <: B, but class Lol is invariant in type A. 
You may wish to define A as +A instead. (SLS 4.5) 

Una possibile soluzione è quella di aggiornare il frammento di genere :

def foo[B <: Lol[_]](f: B) = f 

Torna al codice originale:

trait Lol[A, SA] { 
    def flatMap[B <: Lol[_,_]](f: A => B): B = ??? 
} 
Problemi correlati