Функции высшего порядка

Функция высшего порядка — это функция, которая работает с другими функциями, и именно здесь Scala раскрывается.

«Передайте поведение как аргумент — и одна функция заменит десяток почти одинаковых.»

Функция высшего порядка (higher-order function) — это функция, которая либо принимает функцию параметром, либо возвращает функцию. Это позволяет вынести «изменяемую часть» алгоритма наружу.

// Принимает функцию преобразования
def transform(x: Int, f: Int => Int): Int = f(x)

println(transform(5, _ * 2))    // 10
println(transform(5, _ + 100))  // 105

Возврат функции

Функция может и вернуть функцию. Это удобно, когда нужно создать «настроенную» функцию.

def multiplier(factor: Int): Int => Int =
  (x: Int) => x * factor

val triple = multiplier(3)
val tenX = multiplier(10)
println(triple(4))   // 12
println(tenX(4))     // 40

Здесь multiplier возвращает новую функцию, которая «помнит» переданный factor. Это называется замыкание (closure).

Зачем это на практике

Почти все методы коллекций — map, filter, sortBy — это функции высшего порядка. Вы передаёте им поведение, а они применяют его к каждому элементу.

val nums = List(1, 2, 3, 4)
val doubled = nums.map(x => x * 2)   // List(2, 4, 6, 8)
val evens = nums.filter(x => x % 2 == 0)  // List(2, 4)

Та же идея на Python ▶

# Функции высшего порядка на Python
def transform(x, f):
    return f(x)

def multiplier(factor):
    return lambda x: x * factor   # замыкание помнит factor

print(transform(5, lambda v: v * 2))   # 10
triple = multiplier(3)
print(triple(4))                       # 12

nums = [1, 2, 3, 4]
print(list(map(lambda x: x * 2, nums)))          # [2, 4, 6, 8]
print(list(filter(lambda x: x % 2 == 0, nums)))  # [2, 4]
обычная функция:  данные -> [логика] -> результат

функция высшего порядка:
  данные + ФУНКЦИЯ -> [применяет переданное поведение] -> результат

Как работает под капотом (JVM)

Замыкание — это объект, который захватывает значения из окружающей области. Когда multiplier(3) возвращает лямбду, компилятор создаёт объект Function1, в поле которого сохранён factor = 3. Поэтому возвращённая функция «помнит» контекст даже после того, как multiplier завершилась. JVM хранит этот объект в куче, пока на него есть ссылки.

Частые ошибки

  • Захватывать var в замыкании. Если захваченная переменная меняется, поведение функции тоже «плавает». Захватывайте val.
  • Слишком абстрактные сигнатуры. Не превращайте простой код в башню из функций, если в этом нет нужды.
  • Забывать, что функция возвращает функцию. Следите за типом возврата A => B.

Best practices

  • Используйте функции высшего порядка, чтобы избегать дублирования: общий каркас + разное поведение.
  • Захватывайте только неизменяемые значения — это делает замыкания предсказуемыми.
  • Опирайтесь на встроенные map/filter вместо ручных циклов.

Абстракция поведения меняет архитектуру

Функции высшего порядка — это не просто удобный приём, а целый способ проектирования. Раньше, чтобы изменить поведение алгоритма, приходилось писать новую версию или городить флаги и условия. С функциями высшего порядка изменяемая часть выносится наружу как параметр-функция, а каркас остаётся одним. Так появляется множество стандартных «каркасов» — map, filter, sortBy — в которые вы просто вставляете нужное поведение.

Замыкания добавляют к этому мощь конфигурации. Функция, которая возвращает функцию, по сути создаёт «настроенный инструмент»: multiplier(3) рождает умножитель на три, помнящий свою настройку. Это позволяет строить семейства похожих функций из одного определения, не дублируя код. Освоив этот приём, вы заметите, как много повторяющейся логики можно свернуть в одну параметризованную фабрику.

На практике функции высшего порядка особенно ценны при работе с коллекциями, которым посвящён отдельный раздел. Каждый раз, передавая поведение в map, filter или sortBy, вы пользуетесь именно этим механизмом. Поэтому уверенное владение функциями-аргументами — это ключ ко всему функциональному арсеналу Scala, а не отдельный академический навык.

Итоги. Функции высшего порядка принимают и возвращают функции, позволяя выносить поведение наружу и строить замыкания. Это сердце функционального стиля. Дальше — параметры по умолчанию и именованные аргументы.

Проверьте себя
1. Что такое функция высшего порядка?
AФункция с большим количеством параметров
BФункция, которая принимает или возвращает другую функцию
CФункция, объявленная вне класса
DОчень быстрая функция
2. Что «запоминает» замыкание, возвращённое из multiplier(3)?
AНичего
BЗахваченное значение factor = 3
CТолько своё имя
DАдрес в памяти JVM