0Pricing
Scala for Backend Engineering & Functional Programming · Урок

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

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

«Функции высшего порядка и каррирование» — бесплатный урок Scala for Backend Engineering & Functional Programming на CoddyKit. Это урок 2 из 3. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Scala for Backend Engineering & Functional Programming, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Scala for Backend Engineering & Functional Programming содержит 3 уроков всего.

Раскрываем возможности функций высшего порядка

Добро пожаловать на урок 2! В функциональном программировании функции обладают большой мощью. Они предназначены не только для вычисления значений: с ними можно обращаться как с любыми другими данными.

Это означает, что функции можно передавать другим функциям в качестве аргументов и даже возвращать из них в качестве результатов. Когда функция делает это, её называют функцией высшего порядка (HOF).

  • HOF принимают одну или несколько функций в качестве аргументов.
  • HOF возвращают функцию в качестве результата.
  • Или делают и то и другое!

HOF в действии: `map`

Одной из самых распространённых HOF в Scala является map. Она преобразует каждый элемент коллекции, применяя к нему заданную функцию, и возвращает новую коллекцию.

Попробуйте выполнить этот простой пример:

object Main {
  def main(args: Array[String]): Unit = {
    val numbers = List(1, 2, 3)
    val doubledNumbers = numbers.map(x => x * 2)
    println(s"Original: $numbers")
    println(s"Doubled: $doubledNumbers")
  }
}

HOF в действии: `filter`

Ещё одна полезная HOF — filter. Она выбирает из коллекции элементы, соответствующие заданному условию (функции, возвращающей логическое значение), и создаёт новую коллекцию.

Вот как с помощью filter можно найти чётные числа:

object Main {
  def main(args: Array[String]): Unit = {
    val allNumbers = List(1, 2, 3, 4, 5, 6)
    val evenNumbers = allNumbers.filter(x => x % 2 == 0)
    println(s"All: $allNumbers")
    println(s"Even: $evenNumbers")
  }
}

Определение собственной HOF

Вы не ограничены встроенными HOF! Вы можете определять собственные функции, принимающие другие функции в качестве параметров. Синтаксис типа функции: (InputType => ReturnType).

В этом примере определяется функция applyOperation, которая принимает значение типа Int и другую функцию op (принимающую значение типа Int и возвращающую значение типа Int).

object Main {
  // A HOF that applies an operation to a number
  def applyOperation(x: Int, op: Int => Int): Int = {
    op(x)
  }

  def main(args: Array[String]): Unit = {
    val result = applyOperation(10, _ * 3) // Pass an anonymous function
    println(s"Result of 10 * 3: $result")

    val anotherResult = applyOperation(7, _ + 5)
    println(s"Result of 7 + 5: $anotherResult")
  }
}

Анонимные функции и сокращённая запись

При передаче функций в HOF часто используют анонимные функции (их также называют лямбда-функциями). Scala предлагает краткие способы их записи.

  • x => x * 2: полная запись анонимной функции.
  • _ * 2: сокращённая запись анонимной функции с одним параметром.

Оба варианта распространены и делают код короче и понятнее.

object Main {
  def main(args: Array[String]): Unit = {
    val numbers = List(10, 20, 30)

    // Using full anonymous function syntax
    val dividedByTwo = numbers.map(x => x / 2)
    println(s"Divided by two: $dividedByTwo")

    // Using shorthand `_` syntax
    val plusOne = numbers.map(_ + 1)
    println(s"Plus one: $plusOne")
  }
}

Знакомство с каррированием

Каррирование — это приём, который преобразует функцию с несколькими аргументами в последовательность функций, каждая из которых принимает один аргумент.

Название происходит от имени логика Хаскелла Карри. В Scala функции с несколькими списками параметров автоматически каррируются.

Вместо f(arg1, arg2) записывают f(arg1)(arg2).

Пример каррирования: списки параметров

Рассмотрим каррирование в действии. Обратите внимание, что add принимает аргументы в двух отдельных списках параметров.

Это позволяет частично применить функцию, создав новые функции с заранее заданными некоторыми аргументами.

object Main {
  // A curried function with two parameter lists
  def add(a: Int)(b: Int): Int = {
    a + b
  }

  def main(args: Array[String]): Unit = {
    // Call the function normally
    println(s"5 + 3 = ${add(5)(3)}")

    // Partially apply the first argument
    val addFive = add(5)_ // `_` tells Scala to treat it as a partially applied function
    println(s"5 + 10 = ${addFive(10)}")
    println(s"5 + 20 = ${addFive(20)}")
  }
}

Преимущества каррирования

Зачем использовать каррирование? В функциональном программировании оно даёт несколько преимуществ:

  • Частичное применение: создание специализированных версий функции с заранее заданными некоторыми аргументами. Это повышает повторное использование кода.
  • Композиция функций: каррированные функции часто проще объединять с другими функциями.
  • Вывод типов: иногда помогает механизму вывода типов Scala, особенно при работе со сложными обобщёнными типами.

Каррирование для пользовательских регистраторов

Представьте, что вы хотите создать разные функции регистрации для разных уровней (например, INFO и ERROR), используя при этом одну и ту же основную логику. Каррирование идеально подходит для этого!

Можно определить общую функцию log, а затем частично применить её для создания конкретных регистраторов.

object Main {
  def log(level: String)(message: String): Unit = {
    println(s"[$level] $message")
  }

  def main(args: Array[String]): Unit = {
    // Create specialized loggers using partial application
    val infoLogger = log("INFO")_
    val errorLogger = log("ERROR")_

    infoLogger("User logged in successfully.")
    errorLogger("Failed to connect to database!")
  }
}

Быстрая проверка: HOF и каррирование

Рассмотрите следующий фрагмент кода Scala:

def calculate(x: Int)(y: Int, op: (Int, Int) => Int): Int = {
  op(x, y)
}

val add = (a: Int, b: Int) => a + b
val multiply = (a: Int, b: Int) => a * b

val result1 = calculate(10)(5, add)
val result2 = calculate(2)(3, multiply)

Каковы значения result1 и result2?

Повторение: HOF и каррирование

Отличная работа! Вы изучили две мощные концепции функционального программирования:

  • Функции высшего порядка (HOF): функции, которые могут принимать другие функции в качестве аргументов или возвращать их в качестве результатов. Они позволяют писать гибкий и повторно используемый код, например с помощью map и filter.
  • Каррирование: приём преобразования функции с несколькими аргументами в последовательность функций, каждая из которых принимает один аргумент. Оно особенно полезно для частичного применения и создания специализированных функций.

Эти концепции лежат в основе выразительного и модульного кода на Scala!

Часто задаваемые вопросы

Урок «Функции высшего порядка и каррирование» бесплатный?

Да — полный текст урока «Функции высшего порядка и каррирование» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Scala for Backend Engineering & Functional Programming, подпишись на CoddyKit PRO. Курс Scala for Backend Engineering & Functional Programming содержит 3 уроков всего.

Чему я научусь в уроке «Функции высшего порядка и каррирование»?

Изучите расширенные функциональные концепции, такие как функции высшего порядка и каррирование, чтобы создавать гибкий и повторно используемый код. Ты практикуешь Scala for Backend Engineering & Functional Programming с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать Scala for Backend Engineering & Functional Programming?

Предыдущий опыт не требуется. Scala for Backend Engineering & Functional Programming на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 2 из 3.

Сколько времени занимает урок «Функции высшего порядка и каррирование»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке Scala for Backend Engineering & Functional Programming?

Да. Каждый урок Scala for Backend Engineering & Functional Programming включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Функции как значения первого класса
  2. Функции высшего порядка и каррирование
  3. Неизменяемость и побочные эффекты
← Назад к Scala for Backend Engineering & Functional Programming