2013-03-04 14 views
5

Attualmente sto imparando Scala in questi giorni e oggi mi sono imbattuto in un problema che non riesco a capire.Problemi di inferenza del tipo Scala con funzione parametrica

Supponiamo di avere la seguente definizione di funzione parametrica:

def filter[T](source: List[T], predicate: T=>Boolean): List[T] = { 
    source match { 
     case Nil => Nil 
     case x::xs => if(predicate(x)) x::filter(xs, predicate) 
        else filter(xs, predicate) 
    } 
} 

Ora, questo funziona bene se invoco come segue:

filter(List(1,2,3,4,5,6), ((n:Int) => n % 2 == 0)) 

Ma se rimuovere il tag tipo, appare Scala non posso dedurre che il tipo di T sia Int.

filter(List(1,2,3,4,5,6), (n => n % 2 == 0)) 

Quindi, sono obbligato a fornire informazioni di tipo esplicito in questa chiamata.

Qualcuno sa perché Scala non è in grado di inferire il tipo di T in questa chiamata. L'elenco è evidentemente un elenco di Ints, non riesco a capire perché non possa dedurre che il tipo di n sia anche Int.

risposta

8

di Scala inferenza di tipo lavora per parametro lista, non per parametro, quindi non ha risolto T-Int per il momento si arriva al predicato nel secondo esempio. È possibile, tuttavia, ottenere quello che vuoi utilizzando due elenchi di parametri:

def filter[T](source: List[T])(predicate: T => Boolean): List[T] = 
    source match { 
    case Nil => Nil 
    case x :: xs => 
     if (predicate(x)) 
     x :: filter(xs)(predicate) 
     else 
     filter(xs)(predicate) 
    } 

Ora la seguente funzionano bene:

scala> filter(List(1, 2, 3, 4, 5, 6))((n => n % 2 == 0)) 
res0: List[Int] = List(2, 4, 6) 

Vedere la mia risposta here per qualche discussione supplementare.

+0

Inoltre, richiamare tali HOF è in realtà sintatticamente più naturale quando il 'predicato' è specificato in un elenco di parametri separato (e uno che ha un singolo parametro ed è più a destra, ad eccezione di qualsiasi elenco di parametri implicito). Questo perché non è necessario nidificare l'argomento della funzione all'interno dei parents dell'elenco dei parametri contenente 'source'. A causa della condizione "ha un singolo parametro" non è necessario racchiuderlo in parens, a parte i parens (o parentesi graffe) che useresti per racchiudere una funzione letterale. –

1

è necessario mettere il predicato in un altro gruppo di parametri per ottenere l'inferenza al lavoro:

def filter[T](source: List[T])(predicate: T=>Boolean): List[T] = { 
    source match { 
     case Nil => Nil 
     case x::xs => if(predicate(x)) x::filter(xs)(predicate) 
        else filter(xs)(predicate) 
    } 
} 

filter(List(1,2,3,4,5,6))(_ % 2 == 0) 

Purtroppo è una limitazione di scala.