Подтвердить что ты не робот

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

Это создает анонимную функцию, как и следовало ожидать (f - это функция с тремя аргументами):

f(_, _, _)

Я не понимаю, почему это не компилируется, вместо этого возникает ошибка "Отсутствующий тип параметра":

f(_, _, 27)

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

4b9b3361

Ответ 1

Ниже приведены ссылки Scala Спецификация языка

Рассмотрим следующий метод:

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

Eta Expansion может преобразовать это значение в значение типа (Int, Int) => Int. Это расширение вызывается, если:

a) _ используется вместо списка аргументов (значение метода (§6.7))

val f = foo _

b) список аргументов опущен, а ожидаемый тип выражения - это тип функции (§6.25.2):

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

c) каждый из аргументов _ (a специальный случай синтаксиса-заполнителя для анонимных функций (§6.23))

val f = foo(_, _)   

Выражение foo(_, 1) не относится к Eta Expansion; он просто расширяется до (a) => foo(a, 1) (§6.23). Регулярный вывод типа не пытается понять, что a: Int.

Ответ 2

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

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

EDIT - я бы заметил, что следующие два сокращения эквивалентны, и в этом случае немного более очевидно, что это не "частичное приложение", а скорее как "указатель функции"

val anon1 = plus2(_,_)
val anon2 = plus2 _

Ответ 3

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

scala> object Ashkan { def f(a:Int,b:Int) = a; def f(a:Int,b:String) = b; }
defined object Ashkan

scala> Ashkan.f(1,2)
res45: Int = 1

scala> Ashkan.f(1,"Ashkan")
res46: String = Ashkan

scala> val x= Ashkan.f _
<console>:11: error: ambiguous reference to overloaded definition,
both method f in object Ashkan of type (a: Int, b: String)String
and  method f in object Ashkan of type (a: Int, b: Int)Int
match expected type ?
       val x= Ashkan.f _
                     ^

scala> val x= Ashkan.f(_,_)
<console>:11: error: missing parameter type for expanded function ((x$1, x$2) => Ashkan.f(x$1, x$2))
       val x= Ashkan.f(_,_)
                       ^
<console>:11: error: missing parameter type for expanded function ((x$1: <error>, x$2) => Ashkan.f(x$1, x$2))
       val x= Ashkan.f(_,_)
                         ^

scala> val x= Ashkan.f(_,"Akbar")
<console>:11: error: missing parameter type for expanded function ((x$1) => Ashkan.f(x$1, "Akbar"))
       val x= Ashkan.f(_,"Akbar")
                       ^

scala> val x= Ashkan.f(1,_)
<console>:11: error: missing parameter type for expanded function ((x$1) => Ashkan.f(1, x$1))
       val x= Ashkan.f(1,_)
                         ^

scala> val x= Ashkan.f(1,_:String)
x: String => String = <function1>

Ответ 4

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

val f = foo(_: Nothing, 1) 

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