Per completare le altre risposte, ecco alcuni esempi che mostrano il motivo per cui si ottiene il "tipo di parametro mancante" in alcuni casi quando si utilizza '_' come parametro segnaposto.
L'inferenza del tipo di Scala considera il tipo 'previsto' di un'espressione in base al suo contesto. Se non esiste un contesto, non può inferire il tipo di parametri. Si noti nel messaggio di errore la prima e la seconda istanza di _
vengono sostituite con gli identificatori del compilatore x$1
e x$2
.
scala> _ + _
<console>:5: error: missing parameter type for expanded function ((x$1, x$2) => x$1.$plus(x$2))
_ + _
^
<console>:5: error: missing parameter type for expanded function ((x$1: <error>, x$2) => x$1.$plus(x$2))
_ + _
^
Aggiunta di un tipo di attribuzione per l'intera espressione fornisce abbastanza contesto per aiutare l'inferencer:
scala> (_ + _) : ((Int, Int) => Int)
res3: (Int, Int) => Int = <function2>
In alternativa, è possibile aggiungere un tipo di attribuzione ad ogni parametro segnaposto:
scala> (_: Int) + (_: Int)
res4: (Int, Int) => Int = <function2>
Nella chiamata di funzione sottostante con gli argomenti di tipo forniti, il contesto non è ambiguo e il tipo di funzione viene dedotto.
scala> def bar[A, R](a1: A, a2: A, f: (A, A) => R) = f(a1, a2)
bar: [A,R](a1: A,a2: A,f: (A, A) => R)R
scala> bar[Int, Int](1, 1, _ + _)
res5: Int = 2
Tuttavia, se chiediamo il compilatore di dedurre i parametri di tipo, se fallisce:
scala> bar(1, 1, _ + _)
<console>:7: error: missing parameter type for expanded function ((x$1, x$2) => x$1.$plus(x$2))
bar(1, 1, _ + _)
^
<console>:7: error: missing parameter type for expanded function ((x$1: <error>, x$2) => x$1.$plus(x$2))
bar(1, 1, _ + _)
^
possiamo farne a meno, però, dai currying le liste di parametri. Qui, gli argomenti del primo elenco di parametri (1, 1)
indicano che il parametro di tipo A
deve essere Int
. Quindi sa che il tipo dell'argomento f
deve essere (Int, Int) => ?)
e il tipo di ritorno R
viene dedotto come Int
, il risultato dell'aggiunta di un intero. Vedrete lo stesso approccio utilizzato in Traversable.flatMap
nella libreria standard.
scala> def foo[A, R](a1: A, a2: A)(f: (A, A) => R) = f(a1, a2)
foo: [A,R](a1: A,a2: A)(f: (A, A) => R)R
scala> foo[Int, Int](1, 1) { _ + _ }
res1: Int = 2
scala> foo(1, 1) { _ + _ }
res0: Int = 2
@Scoobie Solo per rinforzarlo, il carattere di sottolineatura viene utilizzato per molti scopi _differenti in Scala. Come ha spiegato David, ogni uso nel tuo esempio ha in realtà un significato diverso. Ci sono anche altri significati - sottolineatura, in Scala, è un buon esempio di problemi derivanti dal sovraccarico dell'operatore. Inizialmente ho avuto dei problemi, posso onestamente dire che non ho mai pensato ad un modo per migliorarlo. –