В Scala, почему я не могу частично применить функцию, явно не указывая ее типы аргумента?

Это производит анонимную функцию, как Вы ожидали бы (f, функция с тремя аргументами):

f(_, _, _)

То, что я не понимаю, - то, почему это не компилирует, вместо этого давая "недостающую ошибку" типа параметра:

f(_, _, 27)

Вместо этого я должен указать типы символов нижнего подчеркивания явно. Разве Scala не должен мочь вывести их, учитывая, что это знает, каковы типы параметра функционального f?

35
задан vt. 23 October 2012 в 16:19
поделиться

3 ответа

Ссылки ниже относятся к Спецификация языка 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 .

19
ответ дан 27 November 2019 в 15:46
поделиться

Если вы думаете о частичном применении, я подумал, что это возможно только с списками с несколькими параметрами (тогда как у вас есть только один):

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 _
8
ответ дан 27 November 2019 в 15:46
поделиться

Мне кажется, что это один из тех пограничных случаев, возникающих при преобразовании кода, поскольку в этом случае создается анонимная функция, которая направляет вызов исходному методу. Тип задается для аргумента внешней анонимной функции. На самом деле, вы можете указать любой подтип, например

val f = foo(_: Nothing, 1) 

даже это будет компилироваться

-4
ответ дан 27 November 2019 в 15:46
поделиться
Другие вопросы по тегам:

Похожие вопросы: