Это производит анонимную функцию, как Вы ожидали бы (f, функция с тремя аргументами):
f(_, _, _)
То, что я не понимаю, - то, почему это не компилирует, вместо этого давая "недостающую ошибку" типа параметра:
f(_, _, 27)
Вместо этого я должен указать типы символов нижнего подчеркивания явно. Разве Scala не должен мочь вывести их, учитывая, что это знает, каковы типы параметра функционального f?
Ссылки ниже относятся к Спецификация языка Scala
Рассмотрим следующий метод:
def foo(a: Int, b: Int) = 0
Eta Expansion может преобразовать это в значение типа (Инт, Инт) => Инт
. Это расширение вызывается, если:
a) _
используется вместо списка аргументов (значение метода (§6.7))
val f = foo _
b) список аргументов опущен, а ожидаемый тип выражения является типом функции (§6.25.2):
val f: (Int, Int) => Int = foo
c) каждый из аргументов имеет вид _
( особый случай 'Синтаксиса заполнителя для анонимных функций' (§6.23 ))
val f = foo(_, _)
Выражение foo (_, 1)
не подходит для расширения Eta; он просто расширяется до (a) => foo (a, 1)
(§6.23). Вывод обычного типа не пытается выяснить, что a: Int
.
Если вы думаете о частичном применении, я подумал, что это возможно только с списками с несколькими параметрами (тогда как у вас есть только один):
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
Ваш пример интересен, поскольку я совершенно не знал о синтаксис, который вы описываете, и похоже, что вы можете иметь частичное приложение с одним списком параметров:
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
Таким образом, компилятор может четко определить тип 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,_)
^
Хммм, странно! Кажется, я не могу выполнить частичное приложение с одним списком параметров. Но тогда, если я объявлю тип второго параметра, я могу иметь частичное применение!
scala> val anon2 = plus2(20,_: Int)
anon2: (Int) => Int = <function1>
scala> anon2(24)
res2: Int = 44
РЕДАКТИРОВАТЬ - я бы заметил одну вещь: кажется, что следующие два сокращения эквивалентны, и в этом случае немного более очевидно, что это не «частичное приложение», а больше похоже на «указатель на функцию»
val anon1 = plus2(_,_)
val anon2 = plus2 _
Мне кажется, что это один из тех пограничных случаев, возникающих при преобразовании кода, поскольку в этом случае создается анонимная функция, которая направляет вызов исходному методу. Тип задается для аргумента внешней анонимной функции. На самом деле, вы можете указать любой подтип, например
val f = foo(_: Nothing, 1)
даже это будет компилироваться