Использование _ в scala лямбда-функциях

Может кто-нибудь объяснить мне, почему я могу сделать:

a.mapValues(_.size)

вместо

a.mapValues(x => x.size)

но я не могу сделать

a.groupBy(_)

вместо

a.groupBy(x => x)

Ответ 1

Это не легко увидеть здесь:

a.groupBy(_)

Но легче видеть это примерно так:

a.mkString("<", _, ">")

Я частично применяю метод/функцию. Я применяю его к некоторым параметрам (первый и последний) и оставляя второй параметр непримененным, поэтому я получаю новую функцию следующим образом:

x => a.mkString("<", x, ">")

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

a.mapValues(_.size)
a.mapValues(x => x.size)

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

a.groupBy _

Ответ 2

Когда вы пишете a.groupBy(_), компилятор понимает его как анонимную функцию:

x => a.groupBy(x)

Согласно Scala Спецификации §6.23, замещающий знак подчеркивания в выражении заменяется анонимным параметром. Итак:

  • _ + 1 расширяется до x => x + 1
  • f(_) расширяется до x => f(x)
  • _ не размножается сам по себе (заполнитель не является частью какого-либо выражения).

Выражение x => a.groupBy(x) будет путать компилятор, потому что он не может вывести тип x. Если a - некоторая коллекция элементов типа E, то компилятор ожидает, что x будет функцией типа (E) => K, но тип K не может быть выведен...