2011-08-19 10 views
9

vedere questo esempio:Perché scala non può inferire il tipo in un metodo parziale?

def hello(a:String, b:String) = println(a + ":" + b) 
val m1 = hello("aaa", _) 
m1("bbb") 

Non può essere compilato, che ho bisogno di aggiungere il tipo al metodo parziale:

val m1 = hello("aaa", _: String) 

Perché Scala non si conosce il secondo parametro del metodo hello è String?

risposta

15

L'inferenza di tipo Scala è basata sul flusso. I metodi e le funzioni richiedono tipi di parametri espliciti, che vengono utilizzati per inferire altri tipi. I tipi di parametro non possono essere dedotti dal metodo o dal corpo della funzione. A volte, tuttavia, i tipi di parametro sono noti dal contesto esterno e quindi non devono essere etichettati. Due esempi,

val f: String => Unit = hello("aaa", _) 
val s = Seq(1,2).map(_+1) // Seq[Int].map expects a function of Int argument type 

Qui di seguito è una citazione da Martin Odersky sulle limitazioni di inferenza dei tipi di Scala, rispetto, per esempio, ML e Haskell. Le sfide includono sovraccarico di Scala, selezione dei record, e sottotipi, come pure la necessità di mantenere le cose semplici,

Il motivo Scala non ha Hindley/Milner inferenza dei tipi è che è molto difficile da combinare con caratteristiche tali come sovraccarico (la variante ad-hoc , non classi di tipi), selezione record e sottotipizzazione. Non sto dicendo impossibile: esiste un numero di estensioni che incorpora queste funzioni; ; in effetti sono stato io stesso un po 'di loro . Sto solo dicendo che è molto difficile farlo funzionare bene nella pratica , dove è necessario avere espressioni di tipo piccolo e buoni messaggi di errore . Nemmeno uno dei casi è chiuso: molti ricercatori sono che lavorano sul superamento dei limiti (si veda ad esempio il numero MLF di Remy). Ma al momento è un compromesso di tipo migliore inferenza vs supporto migliore per queste funzionalità. Puoi fare il tradeoff entrambi i modi . Il fatto che volessimo integrare con Java ha scalzato le scale in favore di sottotipizzazione e lontano da Hindley/Milner.

Fonte: commento al post Universal Type Inference is a Bad Thing.

3

Potrebbe essere perché esiste una potenziale ambiguità con questa definizione poiché hello potrebbe essere sovraccaricato.

// inside some class context 
def hello(a:String, b:String) = println(a + ":" + b) 
def hello(a:String, b:Int) = println(a + ":" + b.toString) 
val m1 = hello("aaa", _) // which one to choose? 

Si consideri che non è solo voi che può fare val m1 = hello("aaa", _). Potrebbe esserci un utente della tua classe, facendo val my_hello = (new C).hello("aaa", _). E poi si interrompe la compatibilità del codice sorgente aggiungendo un sovraccarico al metodo hello della stringa originale, perché improvvisamente non è più chiaro cosa dovrebbe essere fatto.

Non sono sicuro che questa sia l'unica ragione, ma si può certamente vederlo come una misura di sicurezza.

+0

ma nel mio codice, c'è solo un metodo 'ciao'. Vuoi dire, la classe può essere estesa, e la sottoclasse può sovrascrivere il metodo 'ciao' e rompere il codice? – Freewind

+0

Devo ammettere, non sono sicuro se questo sia effettivamente possibile con la sottoclasse. Ma anche senza di esso, penso che sia un po 'più coerente richiedere sempre l'annotazione del tipo. Altrimenti tutto il codice senza un'annotazione di tipo che si interromperebbe improvvisamente, se si è scelto di aggiungere un sovraccarico. – Debilski

+0

Sono curioso di sapere perché, in quel caso, 'm1' non è solo polimorfo sul tipo del suo argomento. –

4

Per dirla in parole semplici, Scala utilizza i tipi di parametri per cercare il metodo appropriato, non il tipo di metodo per dedurre il tipo dei parametri.

Per fare quello che vuoi, dovrebbe cercare tutte le chiamate possibili a hello con due parametri, il primo di essi String - che potrebbe includere conversioni implicite - e quindi, se viene trovata una singola opzione più specifica , usalo per dedurre il tipo di quel secondo parametro. Dovrebbe fare questo in aggiunta a a tutto ciò che fa già, rallentando ancora di più quello che è già una compilazione piuttosto lenta. Non impossibile, ma non lo fa.

Problemi correlati