В программировании анонимная функция ( литерал функции , выражение или блок ) — это определение функции , не привязанное к идентификатору . Анонимные функции часто являются аргументами, передаваемыми функциям более высокого порядка или используемыми для построения результата функции более высокого порядка, которая должна возвращать функцию. [1] Если функция используется только один раз или ограниченное количество раз, анонимная функция может быть синтаксически легче, чем использование именованной функции. Анонимные функции повсеместно распространены в функциональных языках программирования и других языках с функциями первого класса , где они выполняют ту же роль для типа функции , что и литералы для других типов данных .
Анонимные функции берут свое начало в работе Алонзо Чёрча , когда он изобрел лямбда-исчисление , в котором все функции анонимны, в 1936 году, до появления электронных компьютеров. [2] В нескольких языках программирования анонимные функции вводятся с помощью ключевого слова lambda , а анонимные функции часто называют лямбдами или лямбда-абстракциями. Анонимные функции стали особенностью языков программирования со времен Lisp в 1958 году, и все большее число современных языков программирования поддерживают анонимные функции.
Названия «лямбда-абстракция», «лямбда-функция» и «лямбда-выражение» относятся к обозначению абстракции функции в лямбда-исчислении, где обычная функция f ( x ) = M будет записана как (λ x . M ) , и где M — это выражение, которое использует x . Сравните с синтаксисом Python .lambda x: M
Название «стрелочная функция» относится к математическому символу « отображается в », x ↦ M. Сравните с синтаксисом JavaScript . [3]x => M
Анонимные функции могут использоваться для включения функциональности, которая не нуждается в именовании, и, возможно, для краткосрочного использования. Некоторые известные примеры включают замыкания и каррирование .
Использование анонимных функций — это вопрос стиля. Их использование никогда не является единственным способом решения проблемы; каждая анонимная функция может быть определена как именованная функция и вызвана по имени. Анонимные функции часто предоставляют более краткую нотацию, чем определение именованных функций. В языках, которые не допускают определения именованных функций в локальных областях, анонимные функции могут обеспечивать инкапсуляцию через локализованную область, однако код в теле такой анонимной функции может быть не пригоден для повторного использования или не поддаваться отдельному тестированию. Короткие/простые анонимные функции, используемые в выражениях, могут быть более простыми для чтения и понимания, чем отдельно определенные именованные функции, хотя без описательного имени их может быть сложнее понять.
В некоторых языках программирования анонимные функции обычно реализуются для очень конкретных целей, таких как привязка событий к обратным вызовам или создание экземпляра функции для определенных значений, что может быть более эффективным в динамическом языке программирования , более читабельным и менее подверженным ошибкам, чем вызов именованной функции.
Следующие примеры написаны на Python 3.
При попытке сортировки нестандартным способом может быть проще включить логику сортировки в анонимную функцию вместо создания именованной функции. Большинство языков предоставляют универсальную функцию сортировки, которая реализует алгоритм сортировки , сортирующий произвольные объекты. Эта функция обычно принимает произвольную функцию, которая определяет, как сравнивать, равны ли два элемента или один больше или меньше другого.
Рассмотрим этот код Python, сортирующий список строк по длине строки:
>>> a = [ 'дом' , 'машина' , 'велосипед' ] >>> a . sort ( key = lambda x : len ( x )) >>> a [ 'машина' , 'велосипед' , 'дом' ]
Анонимная функция в этом примере — лямбда-выражение:
лямбда x : len ( x )
Анонимная функция принимает один аргумент x
и возвращает длину своего аргумента, которая затем используется методом sort()
в качестве критерия сортировки.
Базовый синтаксис лямбда-функции в Python:
лямбда arg1 , arg2 , arg3 , ... : < операция над аргументами , возвращающая значение >
Выражение, возвращаемое лямбда-функцией, можно присвоить переменной и использовать в коде в нескольких местах.
>>> добавить = лямбда а : а + а >>> добавить ( 20 ) 40
Другим примером может служить сортировка элементов в списке по названию их класса (в Python все имеет класс):
>>> a = [ 10 , 'число' , 11.2 ] >>> a . сортировка ( ключ = лямбда x : x . __класс__ . __имя__ ) >>> a [ 11.2 , 10 , 'число' ]
Обратите внимание, что 11.2
имеет имя класса " float
", 10
имеет имя класса " int
" и 'number'
имеет имя класса " str
". Порядок сортировки следующий: " float
", " int
", затем " str
".
Замыкания — это функции, вычисляемые в среде, содержащей связанные переменные . Следующий пример связывает переменную «порог» в анонимной функции, которая сравнивает входные данные с порогом.
def comp ( порог ): return лямбда x : x < порог
Это можно использовать как своего рода генератор функций сравнения:
>>> func_a = comp ( 10 ) >>> func_b = comp ( 20 )>>> print ( func_a ( 5 ), func_a ( 8 ), func_a ( 13 ), func_a ( 21 )) Истина Истина Ложь Ложь>>> print ( func_b ( 5 ), func_b ( 8 ), func_b ( 13 ), func_b ( 21 )) Истина Истина Истина Ложь
Было бы непрактично создавать функцию для каждой возможной функции сравнения и может быть слишком неудобно сохранять порог для дальнейшего использования. Независимо от причины, по которой используется замыкание, анонимная функция является сущностью, которая содержит функциональность, которая выполняет сравнение.
Каррирование — это процесс изменения функции таким образом, чтобы вместо приема нескольких входных данных она принимала один входной сигнал и возвращала функцию, которая принимает второй входной сигнал, и т. д. В этом примере функция, которая выполняет деление на любое целое число, преобразуется в функцию, которая выполняет деление на заданное целое число.
>>> def divide ( x , y ): ... return x / y>>> def divisor ( d ): ... return lambda x : delegate ( x , d )>>> половина = делитель ( 2 ) >>> треть = делитель ( 3 )>>> печать ( половина ( 32 ), треть ( 32 )) 16.0 10.666666666666666>>> печать ( половина ( 40 ), треть ( 40 )) 20.0 13.33333333333334
Хотя использование анонимных функций, возможно, не является обычным для каррирования, его все равно можно использовать. В приведенном выше примере функция divisor генерирует функции с указанным делителем. Функции half и third каррируют функцию divide с фиксированным делителем.
Функция делителя также образует замыкание, связывая переменную d
.
Функция высшего порядка — это функция, которая принимает функцию в качестве аргумента или возвращает ее в качестве результата. Обычно это используется для настройки поведения обобщенно определенной функции, часто циклической конструкции или схемы рекурсии. Анонимные функции — это удобный способ указать такие аргументы функции. Следующие примеры приведены на Python 3.
Функция map выполняет вызов функции для каждого элемента списка. Следующий пример возводит в квадрат каждый элемент массива с помощью анонимной функции.
>>> a = [ 1 , 2 , 3 , 4 , 5 , 6 ] >>> список ( карта ( лямбда x : x * x , a )) [ 1 , 4 , 9 , 16 , 25 , 36 ]
Анонимная функция принимает аргумент и умножает его на себя (возводит в квадрат). Вышеуказанная форма не приветствуется создателями языка, которые утверждают, что форма, представленная ниже, имеет то же значение и больше соответствует философии языка:
>>> а = [ 1 , 2 , 3 , 4 , 5 , 6 ] >>> [ x * x для x в а ] [ 1 , 4 , 9 , 16 , 25 , 36 ]
Функция фильтра возвращает все элементы из списка, которые при передаче определенной функции оцениваются как True.
>>> a = [ 1 , 2 , 3 , 4 , 5 , 6 ] >>> список ( фильтр ( лямбда x : x % 2 == 0 , a )) [ 2 , 4 , 6 ]
Анонимная функция проверяет, является ли переданный ей аргумент четным. Как и в случае с map, более подходящей считается следующая форма:
>>> a = [ 1 , 2 , 3 , 4 , 5 , 6 ] >>> [ x для x в a если x % 2 == 0 ] [ 2 , 4 , 6 ]
Функция fold проходит по всем элементам в структуре (для списков обычно слева направо, "left fold", называемый reduce
в Python), накапливая значение по мере его поступления. Это можно использовать для объединения всех элементов структуры в одно значение, например:
>>> из functools импортировать reduce >>> a = [ 1 , 2 , 3 , 4 , 5 ] >>> reduce ( лямбда x , y : x * y , a ) 120
Это выполняет
Анонимная функция здесь — это умножение двух аргументов.
Результатом свёртки не обязательно должно быть одно значение. Вместо этого и map, и filter могут быть созданы с помощью fold. В map накапливаемое значение — это новый список, содержащий результаты применения функции к каждому элементу исходного списка. В filter накапливаемое значение — это новый список, содержащий только те элементы, которые соответствуют заданному условию.
Ниже приведен список языков программирования , которые поддерживают неименованные анонимные функции полностью или частично в виде некоторого варианта, или не поддерживают вообще.
В этой таблице показаны некоторые общие тенденции. Во-первых, языки, которые не поддерживают анонимные функции ( C , Pascal , Object Pascal ), являются статически типизированными языками. Однако статически типизированные языки могут поддерживать анонимные функции. Например, языки ML являются статически типизированными и в своей основе включают анонимные функции, а Delphi , диалект Object Pascal , был расширен для поддержки анонимных функций, как и C++ (по стандарту C++11 ). Во-вторых, языки, которые рассматривают функции как функции первого класса ( Dylan , Haskell , JavaScript , Lisp , ML , Perl , Python , Ruby , Scheme ), как правило, поддерживают анонимные функции, поэтому функции можно определять и передавать так же легко, как и другие типы данных.
Лямбда-исчисление ... было введено Алонзо Чёрчем в 1930-х годах как точная запись для теории анонимных функций
Котировка — это анонимная функция (значение, обозначающее фрагмент кода), которая может использоваться как значение и вызываться с помощью основных комбинаторов.