To complement the other answers, here are some examples showing why you get the "missing parameter type" in some cases when using '_' as a placeholder parameter.
Scala's type inference considers the 'expected' type of an expression based on its context. If there is no context, it cannot infer the type of the parameters. Notice in the error message the first and second instances of _
are replaced with the compiler generated identifiers x$1
and 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))
_ + _
^
Adding a type ascription to the entire expression provides enough context to help the inferencer:
scala> (_ + _) : ((Int, Int) => Int)
res3: (Int, Int) => Int = <function2>
Alternatively, you can add a type ascription to each parameter placeholder:
scala> (_: Int) + (_: Int)
res4: (Int, Int) => Int = <function2>
In the function call below with type arguments provided, the context is unambigous and the function type is inferred.
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
However, if we ask the compiler to infer the type parameters, if fails:
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, _ + _)
^
We can help it, though, by currying the parameter lists. Here, the arguments to the first parameter list (1, 1)
, tell the inference that the type parameter A
should be Int
. It then knows that the type of the argument f
must be (Int, Int) => ?)
, and the return type R
is inferred as Int
, the result of integer addition. You will see the same approach used in Traversable.flatMap
in the standard library.
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