Что означает "двойной стрелочный тип" без значения LHS в аргументе функции

У меня возникли проблемы с интерпретацией типа double-rightarrow Type, указанного как аргумент функции без LHS (слева), например. () => Int от () до Int, но что означает только => Int? например см. первый аргумент метода foo ниже, каков тип f? Это (Int, () => Int) => Int?

Для определения bar, где y передается по имени, я интерпретировал его как функцию без аргумента, которая создаст Int, который выглядит эквивалентно определению baz.

Я мог бы попытаться объяснить, что f в foo принимает второй аргумент как вызов по имени и не от () => Int, но это противоречит тому факту, что определения bar и baz идентичны в javap. Что мне не хватает?

object ParamTest {
  def foo(f: (Int, => Int) => Int, x: Int) : Int = 10
  def bar(x: Int, y: => Int) : Int = 20
  def baz(x: Int, f: () => Int) : Int = 30
  def qux(f: (Int, () => Int) => Int, x: Int) : Int = 40
}

Для тестирования я скомпилировал вышеуказанный класс с помощью scalac ParamTest.scala

javap ParamTest дает мне:

public final class ParamTest {
  public static int qux(scala.Function2<java.lang.Object, scala.Function0<java.lang.Object>, java.lang.Object>, int);
  public static int baz(int, scala.Function0<java.lang.Object>);
  public static int bar(int, scala.Function0<java.lang.Object>);
  public static int foo(scala.Function2<java.lang.Object, scala.Function0<java.lang.Object>, java.lang.Object>, int);
}

Это означает, что foo и qux имеют одну и ту же сигнатуру метода. Другими словами, я мог бы интерпретировать => Int как () => Int, но foo(baz,100) дает мне ошибку несоответствия типа

scala> import ParamTest._
import ParamTest._

scala> foo(bar,100)
res0: Int = 10

scala> foo(baz,100)
<console>:11: error: type mismatch;
 found   : (Int, () => Int) => Int
 required: (Int, => Int) => Int
              foo(baz,100)
                  ^

EDIT: это не то же самое, что этот вопрос. Я не задаю практических различий между call-by-name: => Type и () => Type. То, что мне больше интересно знать, - это внутренности. Как scala различает два, когда javap или декомпиляция cfr дает мне идентичные определения для foo и qux; и для bar и baz.

Ответ 1

Как вы обнаружили, () => A и => A - это не одно и то же.

Вызов по имени (т.е. => A) просто означает: "задержать оценку этого аргумента метода". Другими словами, ленивая оценка.

def f(x: Int, y: => Int) = ???

f(3+5, 2+4)

В этом примере добавление 3 + 5 выполняется на сайте вызова, а значение x равно 8. Добавление 2 + 4, с другой стороны, не выполняется до тех пор, пока y не будет указана внутри тело метода f(). Если эта ссылка находится в ветки if...else..., которая не выполняется, добавление никогда не выполняется.

Это довольно бессмысленно для простых оценок, таких как добавление Int, но становится более значимым, если аргумент является дорогостоящей оценкой, если он представляет собой блок кода с побочными эффектами.

Итак, в ответе на ваш вопрос значение f: (Int, => Int) => Int: "f принимает два аргумента и создает Int, аргументы равны 2 Int s, 2-й из которых оценивается лениво."