Что такое лямбда и почему она может быть полезна?

Что такое лямбда и почему она может быть полезна?
Что такое лямбда и почему она может быть полезна? - supaslim @ Unsplash

До сих пор я слышал о :

  • Лямбда-исчисление
  • Лямбда-программирование
  • Лямбда-выражения
  • Лямбда-функции

Которые все, похоже, связаны с функциональным программированием...

Очевидно, это будет интегрировано в C++1x, так что теперь я могу лучше понять это:

http://en.wikipedia.org/wiki/C%2B%2B0x#Lambda_functions_and_expressions

Кто-нибудь может кратко описать, что такое ламбда и указать, где она может быть полезна?

  • Лямбда-исчисление

Лямбда-исчисление — это модель вычислений, изобретенная Алонзо Чёрчем в 30-х годах. Синтаксис и семантика большинства функциональных языков программирования прямо или косвенно основаны на лямбда-исчислении.

Лямбда-исчисление в своей самой базовой форме имеет две операции: абстракцию (создание (анонимной) функции) и применение (применение функции). Абстракция выполняется с помощью оператора λ, что и дало название лямбда-исчислению.

  • Лямбда-выражения
  • Лямбда-функции

Анонимные функции часто называют «лямбда-функциями», «лямбда-функциями» или «лямбда-выражениями», потому что, как я сказал выше, λ был символом для создания анонимных функций в лямбда-исчислении (а слово lambda используется для создания анонимных функций во многих языки на основе lisp по той же причине).

  • Лямбда-программирование

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


Еще немного информации о лямбда-выражениях в C++0x, их мотивации и том, как они соотносятся с указателями на функции (многое из этого, вероятно, является повторением того, что вы уже знаете, но я надеюсь, что это поможет объяснить мотивацию лямбда-выражений и их отличия). из указателей функций):

Указатели функций, которые уже существовали в C, весьма полезны, например, для передать функцию сравнения функции сортировки. Однако есть пределы их полезности:

Например, если вы хотите отсортировать вектор векторов по i-му элементу каждого вектора (где i — параметр времени выполнения), вы не сможете решить эту задачу с помощью указателя на функцию. Функция, которая сравнивает два вектора по их i-му элементу, должна принимать три аргумента (i и два вектора), но для функции сортировки потребуется функция, принимающая два аргумента. Что нам нужно, так это каким-то образом передать аргумент i функции, прежде чем передать его функции сортировки, но мы не можем сделать это с помощью простых функций C.

Чтобы решить эту проблему, C++ ввел понятие «объекты-функции» или «функторы». Функтор — это, по сути, объект, у которого есть метод operator(). Теперь мы можем определить класс CompareByIthElement, который принимает аргумент i в качестве аргумента конструктора, а затем принимает два сравниваемых вектора в качестве аргументов метода operator(). Чтобы отсортировать вектор векторов по i-му элементу, теперь мы можем создать объект CompareByIthElement с i в качестве аргумента, а затем передать этот объект в функцию сортировки.

Поскольку объекты-функции — это просто объекты, а не функции с технической точки зрения (даже если они должны вести себя как они), вы не можете сделать так, чтобы указатель функции указывал на объект-функцию (конечно, вы можете иметь указатель на объект-функцию, но это не так). будет иметь тип, подобный CompareByIthElement*, и, следовательно, не будет указателем на функцию).

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

Теперь к лямбдам:

Определение целого класса для сравнения по i-му элементу немного многословно, если вы собираетесь использовать его только один раз для сортировки вектора. Даже в том случае, когда вам нужен только указатель на функцию, определение именованной функции неоптимально, если она используется только один раз, потому что а) она загрязняет пространство имен и б) функция обычно будет очень маленькой и на самом деле не будет хорошая причина абстрагировать логику в свою собственную функцию (кроме того, что вы не можете иметь указатели на функции без определения функции).

Поэтому, чтобы исправить это, были введены лямбда-выражения. Lambdas — это объекты функций, а не указатели на функции. Если вы используете лямбда-литерал, такой как [x1, x2](y1,y2){bla}, генерируется код, который в основном делает следующее:

  1. Определите класс, который имеет две переменные-члены (x1 и x2) и operator() с аргументами (y1 и y2) и телом bla.
  2. Создайте экземпляр класса, задав для переменных-членов x1 и x2 значения переменных x1 и x2, находящихся в настоящее время в области видимости.

Таким образом, лямбда-выражения ведут себя как функциональные объекты, за исключением того, что вы не можете получить доступ к классу, сгенерированному для реализации лямбда-выражения, каким-либо иным способом, кроме использования лямбда-выражения. Следовательно, любая функция, которая принимает функторы в качестве аргументов (в основном это означает любую не-C функцию в стандартной библиотеке), будет принимать лямбда-выражения, но любая функция, принимающая только указатели функций, не будет.


LetsCodeIt, 28 мая 2023 г., 12:32