tags:

views:

374

answers:

3

This produces an anonymous function as expected (f is a function with three arguments):

f(_, _, _)

What I don't understand is why this doesn't compile, instead giving a "missing parameter type" error:

f(_, _, 27)

I need to specify the types of the underscores explicitly. Shouldn't Scala be able to infer their types given that the parameter types of the function f are known?

+5  A: 

If you are thinking about partial application, I thought that this was only possible with multiple parameter lists (whereas you only have one):

def plus(x: Int)(y: Int) = x + y //x and y in different parameter lists

val plus10 = plus(10) _ //_ indicates partial application

println(plus10(2)) //prints 12

Your example is interesting though as I was completely unaware of the syntax you describe and it appears you can have partial application with a single parameter list:

scala> def plus2(x: Int, y: Int) = x + y
plus2: (x: Int,y: Int)Int

scala> val anon = plus2(_,_)
anon: (Int, Int) => Int = <function2>

scala> anon(3, 4)
res1: Int = 7

So the compiler can clearly infer the type Int!

scala> val anon2 = plus2(20,_)
<console>:5: error: missing parameter type for expanded function ((x$1) => plus2(20, x$1))
       val anon2 = plus2(20,_)
                            ^

Hmmm, strange! I don't seem to be able to do partial application with a single parameter list. But then if I declare the type of the second parameter, I can have partial application!

scala> val anon2 = plus2(20,_: Int)
anon2: (Int) => Int = <function1>

scala> anon2(24)
res2: Int = 44

EDIT - one thing I would observe is that it seems like the following two shortenings are equivalent, in which case it's a bit more obvious that this is not a "partial application" but more like a "function pointer"

val anon1 = plus2(_,_)
val anon2 = plus2 _
oxbow_lakes
`val f = foo(_, _)` expands to `val f = (a, b) => foo(a, b)`, it isn't precisely the same as partially applying a curried function.
retronym
But it *seems* to have the same effect, you must admit. And if the compiler can infer types with 2 `_` placeholders, why does it have trouble when there is only one?
oxbow_lakes
To answer that question, you could debug through Infer.scala in the compiler :) I agree, it seems like an unnecessary limitation, but scala's type inference is intentionally omitted from the spec to allow such wiggle room.
retronym
Partial application does not require curried methods, it is applicable to any method or function.
Randall Schulz
@Randall - indeed! I was not aware of this before this question came up
oxbow_lakes
+4  A: 

References below are to the Scala Language Specification

Consider the following method:

def foo(a: Int, b: Int) = 0

Eta Expansion can convert this to a value of type (Int, Int) => Int. This expansion is invoked if:

a) _ is used in place of the argument list (Method Value (§6.7))

val f = foo _

b) the argument list is omitted, and expected type of expression is a function type (§6.25.2):

val f: (Int, Int) => Int = foo

c) each of the arguments is _ (a special case of the 'Placeholder Syntax for Anonymous Functions' (§6.23))

val f = foo(_, _)   

The expression, foo(_, 1) doesn't qualify for Eta Expansion; it just expands to (a) => foo(a, 1) (§6.23). Regular type inference doesn't attempt to figure out that a: Int.

retronym
A: 

I feel this is one of those border cases arising from all the code conversion, since this involves the creation of an anonymous function which directs the call to the original method. The type is for the argument of the outer anonymous function. In-fact, you can specify any sub-type i.e

val f = foo(_: Nothing, 1) 

even this would compile

Nagaraj