Para complementar las otras respuestas, aquí hay algunos ejemplos que muestran por qué se obtiene el "tipo de parámetro faltante" en algunos casos cuando se usa '_' como parámetro de marcador de posición.
La inferencia de tipo de Scala considera el tipo 'esperado' de una expresión en función de su contexto. Si no hay contexto, no puede inferir el tipo de los parámetros. Observe en el mensaje de error que la primera y la segunda instancia de _
se reemplazan con los identificadores generados por el compilador x$1
y 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))
_ + _
^
Adición de una adscripción tipo a toda la expresión proporciona el contexto suficiente para ayudar al inferencer:
scala> (_ + _) : ((Int, Int) => Int)
res3: (Int, Int) => Int = <function2>
Alternativamente, se puede añadir una indicación de tipo de cada parámetro marcador de posición:
scala> (_: Int) + (_: Int)
res4: (Int, Int) => Int = <function2>
En la llamada de función a continuación con los argumentos de tipo provistos, el contexto no es ambiguo y se deduce el tipo de función.
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
Sin embargo, si nos preguntamos el compilador para inferir los parámetros de tipo, si falla:
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, _ + _)
^
Podemos evitarlo, sin embargo, por ganarse las listas de parámetros. Aquí, los argumentos a la primera lista de parámetros (1, 1)
, indican que el parámetro de tipo A
debe ser Int
. Entonces sabe que el tipo del argumento f
debe ser (Int, Int) => ?)
, y el tipo de retorno R
se infiere como Int
, el resultado de la suma entera. Verá el mismo enfoque utilizado en Traversable.flatMap
en la biblioteca estándar.
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 para reforzar esto, el guion bajo se usa para muchos _different_ propósitos en Scala. Como David explicó, cada uso en tu ejemplo tiene un significado diferente. También hay otros significados: el guión bajo, en Scala, es un buen ejemplo de problemas que surgen de la sobrecarga del operador. Si bien tuve problemas al principio, puedo decir honestamente que nunca he pensado en alguna forma de mejorarlo. –