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

Eta-расширение между методами и функциями с перегруженными методами в Scala

Я хотел бы понять, почему эта-расширение (§6.26.5) не работает для перегруженных методов. Например, если у меня есть два метода:

def d1(a: Int, b: Int) {}
def r[A, B](delegate: (A, B) ⇒ Unit) {}

Я могу это сделать:

r(d1)

Но при перегрузке r он больше не будет работать:

def r[A, B](delegate: (A, B) ⇒ Unit) {}
def r[A, B, C](delegate: (A, B, C) ⇒ Unit) {}

r(d1) // no longer compiles

и я должен явно преобразовать метод в частично прикладную функцию:

r(d1 _)

Есть ли способ выполнить следующее с явным преобразованием?

def r[A, B](delegate: (A, B) ⇒ Unit) {}
def r[A, B, C](delegate: (A, B, C) ⇒ Unit) {}

def d1(a: Int, b: Int) {}
def d2(a: Int, b: Int, c: Int) {}

r(d1) // only compiles with r(d1 _)
r(d2) // only compiles with r(d2 _)

Существует несколько схожий question, но это не полностью объяснено.

4b9b3361

Ответ 1

Неявный - это правильный термин, а раздел - 6.26.2 в спецификации, и это должен быть дублированный вопрос (или, как можно думать, это стабильное поведение).

Связанный вопрос также отвечает, что ожидаемый тип должен быть функцией.

Я выйду на конечность и скажу, что при перегрузке применимость подрывается, потому что нет ожидаемого типа (6.26.3, позор). Если не перегружено, применяется 6.26.2 (это расширение), потому что тип параметра определяет ожидаемый тип. При перегрузке аргумент arg специфически вводится без ожидаемого типа, поэтому 6.26.2 не применяется; поэтому не считается перегруженным вариантом d.

Из 6.26.3 Разрешение перегрузки

В противном случае пусть S 1,.,, S m - вектор типов, полученный вводя каждый аргумент с ожидаемым типом undefined.

Ниже приведены "неявные преобразования" (так называемые), когда вы называете метод без аргументов, как в r(d1). Здесь применяется параграф о расширении eta.

6.26.2 Преобразование метода

Следующие четыре неявных преобразования могут применяться к методам которые не применяются к списку аргументов.

Оценка. Безпараметрический метод m типа = > T всегда преобразуется для того, чтобы ввести T, оценивая выражение, к которому привязано m.

Неявное приложение. Если метод принимает только неявные параметры, неявные аргументы передаются по правилам § 7.2.

Расширение Eta. В противном случае, если метод не является конструктором, а ожидаемый тип pt - это тип функции (Ts) ⇒ T, eta-расширение (§6.26.5) выполняется по выражению e.

Пустое приложение. В противном случае, если e имеет тип метода() T, это неявно применяется к списку пустых аргументов, что дает e()

Подробнее о пояснительной проверке...

Следующий пример демонстрирует предпочтительность приложения для eta-расширения при наличии перегрузки. Когда eta-расширение не применяется, "пустое приложение" является последним неявным, чтобы попробовать в 6.26.2. Другими словами, при перегрузке (что на первый взгляд сбивает с толку и зла) естественно принимать f как f() по принципу равномерного доступа, но неестественно или странно принимать f как f _, если вы не уверены, что ожидается тип функции.

scala> object Bar {
     | def r(f: () => Int) = 1
     | def r(i: Int) = 2
     | }
defined module Bar

scala> def f() = 4
f: ()Int

scala> Bar.r(f)
res4: Int = 2

scala> Bar.r(f _)
res5: Int = 1

Кандидаты на перегрузочное разрешение предварительно экранируются "формой". Тест формы инкапсулирует интуицию в том, что eta-расширение никогда не используется, потому что аргументы печатаются без ожидаемого типа. В этом примере показано, что eta-расширение не используется, даже если это "единственный способ проверки типа для проверки типа".

scala> object Bar {
     | def bar(f: () => Int) = 1
     | def bar(is: Array[Int]) = 2
     | }
defined object Bar

scala> def m() = 7
m: ()Int

scala> m _
res0: () => Int = <function0>

scala> Bar.bar(m)
<console>:10: error: overloaded method value bar with alternatives:
  (is: Array[Int])Int <and>
  (f: () => Int)Int
 cannot be applied to (Int)
              Bar.bar(m)
                  ^

Любому, кто читает это, будет интересно узнать о связанной проблеме с этими двумя преобразованиями.