Анонимная функция
В компьютерном программировании анонимная функция ( функциональный литерал , лямбда-абстракция , лямбда-функция , лямбда-выражение или блок ) — это определение функции , не привязанное к идентификатору . Анонимные функции часто представляют собой аргументы, передаваемые функциям более высокого порядка или используемые для создания результата функции более высокого порядка, которая должна возвращать функцию. [1] Если функция используется только один раз или ограниченное количество раз, анонимная функция может быть синтаксически проще, чем использование именованной функции. Анонимные функции повсеместно встречаются в языках функционального программирования и других языках с первоклассными функциями ту же роль , где они выполняют для типа функции , что и литералы для других типов данных .
Анонимные функции берут свое начало в работе Алонзо Чёрча , когда он изобрел лямбда-исчисление , в котором все функции анонимны, в 1936 году, до появления электронных компьютеров. [2] В некоторых языках программирования анонимные функции вводятся с помощью ключевого слова лямбда , а анонимные функции часто называют лямбда-выражениями или лямбда-абстракциями. Анонимные функции были особенностью языков программирования со времен Лиспа в 1958 году, и все большее число современных языков программирования поддерживают анонимные функции.
Имена
[ редактировать ]Названия «лямбда-абстракция», «лямбда-функция» и «лямбда-выражение» относятся к обозначениям абстракции функции в лямбда-исчислении, где обычная функция f ( x ) = M будет записана (λ x . M ) , и где M — это выражение, которое использует x . Сравните с синтаксисом Python lambda x: M
.
Название «стрелочная функция» относится к математическому « сопоставлению » символа x ↦ M . Сравните с синтаксисом JavaScript x => M
. [3]
Использование
[ редактировать ]Анонимные функции могут использоваться для хранения функций, которым не нужно давать имя, и, возможно, для краткосрочного использования. Некоторые известные примеры включают замыкания и каррирование .
Использование анонимных функций — это вопрос стиля. Их использование никогда не является единственным способом решения проблемы; вместо этого каждая анонимная функция может быть определена как именованная функция и вызываться по имени. Анонимные функции часто предоставляют более краткие обозначения, чем определения именованных функций. В языках, которые не допускают определения именованных функций в локальных областях, анонимные функции могут обеспечивать инкапсуляцию через локализованную область, однако код в теле такой анонимной функции не может быть повторно использован или поддаваться отдельному тестированию. Короткие/простые анонимные функции, используемые в выражениях, может быть легче читать и понимать, чем отдельно определенные именованные функции, хотя без описательного имени их может быть сложнее понять.
В некоторых языках программирования анонимные функции обычно реализуются для очень специфических целей, таких как привязка событий к обратным вызовам или создание экземпляра функции для определенных значений, что может быть более эффективным на динамическом языке программирования , более читабельным и менее подверженным ошибкам, чем вызов функции. именованная функция.
Следующие примеры написаны на Python 3.
Сортировка
[ редактировать ]При попытке сортировки нестандартным способом может оказаться проще сохранить логику сортировки в виде анонимной функции вместо создания именованной функции. Большинство языков предоставляют общую функцию сортировки, реализующую алгоритм сортировки произвольных объектов. Эта функция обычно принимает произвольную функцию, которая определяет, как сравнивать, равны ли два элемента или один из них больше или меньше другого.
Рассмотрим этот код Python, сортирующий список строк по длине строки:
>>> a = ['house', 'car', 'bike']
>>> a.sort(key=lambda x: len(x))
>>> a
['car', 'bike', 'house']
Анонимной функцией в этом примере является лямбда-выражение:
lambda x: len(x)
Анонимная функция принимает один аргумент: x
и возвращает длину своего аргумента, который затем используется sort()
метод как критерий сортировки.
Основной синтаксис лямбда-функции в Python:
lambda arg1, arg2, arg3, ...: <operation on the arguments returning a value>
Выражение, возвращаемое лямбда-функцией, можно присвоить переменной и использовать в коде в нескольких местах.
>>> add = lambda a: a + a
>>> add(20)
40
Другим примером может быть сортировка элементов в списке по имени их класса (в Python все имеет класс):
>>> a = [10, 'number', 11.2]
>>> a.sort(key=lambda x: x.__class__.__name__)
>>> a
[11.2, 10, 'number']
Обратите внимание, что 11.2
имеет имя класса " float
", 10
имеет имя класса " int
", и 'number'
имеет имя класса " str
". Отсортированный порядок: " float
", " int
", затем " str
".
Замыкания
[ редактировать ]Замыкания — это функции, вычисляемые в среде, содержащей связанные переменные . В следующем примере переменная «порог» привязывается к анонимной функции, которая сравнивает входные данные с порогом.
def comp(threshold):
return lambda x: x < threshold
Это можно использовать как своего рода генератор функций сравнения:
>>> func_a = comp(10)
>>> func_b = comp(20)
>>> print(func_a(5), func_a(8), func_a(13), func_a(21))
True True False False
>>> print(func_b(5), func_b(8), func_b(13), func_b(21))
True True True False
Было бы непрактично создавать функцию для каждой возможной функции сравнения, и может быть слишком неудобно сохранять пороговое значение для дальнейшего использования. Независимо от причины использования замыкания, анонимная функция — это сущность, содержащая функциональность, выполняющую сравнение.
каррирование
[ редактировать ]Каррирование — это процесс изменения функции, при котором вместо нескольких входных данных она принимает один входной сигнал и возвращает функцию, которая принимает второй входной сигнал, и так далее. В этом примере функция, выполняющая деление на любое целое число, преобразуется в функцию, выполняющую деление на заданное целое число.
>>> def divide(x, y):
... return x / y
>>> def divisor(d):
... return lambda x: divide(x, d)
>>> half = divisor(2)
>>> third = divisor(3)
>>> print(half(32), third(32))
16.0 10.666666666666666
>>> print(half(40), third(40))
20.0 13.333333333333334
Хотя использование анонимных функций, возможно, не является обычным явлением при каррировании, его все же можно использовать. В приведенном выше примере функция divisor генерирует функции с указанным делителем. Функции half и Third каррируют функцию деления с фиксированным делителем.
Функция делителя также формирует замыкание, связывая переменную d
.
Функции высшего порядка
[ редактировать ]Функция высшего порядка — это функция, которая принимает функцию в качестве аргумента или возвращает ее в качестве результата. Обычно это используется для настройки поведения обобщенно определенной функции, часто это конструкция цикла или схема рекурсии. Анонимные функции — удобный способ указать аргументы таких функций. Следующие примеры относятся к Python 3.
Карта
[ редактировать ]Функция карты выполняет вызов функции для каждого элемента списка. В следующем примере возводится в квадрат каждый элемент массива с помощью анонимной функции.
>>> a = [1, 2, 3, 4, 5, 6]
>>> list(map(lambda x: x*x, a))
[1, 4, 9, 16, 25, 36]
Анонимная функция принимает аргумент и умножает его на себя (возводит в квадрат). Вышеуказанная форма не одобряется создателями языка, которые утверждают, что форма, представленная ниже, имеет то же значение и больше соответствует философии языка:
>>> a = [1, 2, 3, 4, 5, 6]
>>> [x*x for x in a]
[1, 4, 9, 16, 25, 36]
Фильтр
[ редактировать ]Функция фильтра возвращает все элементы из списка, которые оценивают True при передаче определенной функции.
>>> a = [1, 2, 3, 4, 5, 6]
>>> list(filter(lambda x: x % 2 == 0, a))
[2, 4, 6]
Анонимная функция проверяет, является ли переданный ей аргумент четным. Как и в случае с картой, более подходящей считается форма ниже:
>>> a = [1, 2, 3, 4, 5, 6]
>>> [x for x in a if x % 2 == 0]
[2, 4, 6]
Складывать
[ редактировать ]Функция сгиба выполняется по всем элементам структуры (для списков обычно слева направо, «свертывание влево», называемое reduce
в Python), накапливая значение по ходу дела. Это можно использовать для объединения всех элементов структуры в одно значение, например:
>>> from functools import reduce
>>> a = [1, 2, 3, 4, 5]
>>> reduce(lambda x,y: x*y, a)
120
Это выполняет
Анонимная функция здесь — это умножение двух аргументов.
Результат свертки не обязательно должен быть одним значением. Вместо этого и карту, и фильтр можно создать с помощью сгиба. В карте накапливаемое значение представляет собой новый список, содержащий результаты применения функции к каждому элементу исходного списка. В фильтре накапливаемое значение представляет собой новый список, содержащий только те элементы, которые соответствуют заданному условию.
Список языков
[ редактировать ]Ниже приводится список языков программирования , которые поддерживают безымянные анонимные функции полностью или частично в каком-либо варианте или не поддерживают вообще.
В этой таблице показаны некоторые общие тенденции. Во-первых, все языки, которые не поддерживают анонимные функции ( C , Pascal , Object Pascal ), являются статически типизированными языками. Однако статически типизированные языки могут поддерживать анонимные функции. Например, языки ML статически типизированы и в основном включают анонимные функции, а Delphi , диалект Object Pascal , был расширен для поддержки анонимных функций, как и C++ (по стандарту C++11 ). Во-вторых, языки, которые рассматривают функции как функции первого класса ( Dylan , Haskell , JavaScript , Lisp , ML , Perl , Python , Ruby , Scheme ), обычно имеют поддержку анонимных функций, поэтому функции можно определять и передавать так же легко, как и другие данные. типы.
Язык | Поддерживать | Примечания |
---|---|---|
ActionScript | ||
Есть | Функции выражения являются частью Ada2012, доступа к подпрограмме. [4] | |
АЛГОЛ 68 | ||
АПЛ | Dyalog, ngn и dzaima APL полностью поддерживают как dfns, так и неявные функции. GNU APL имеет довольно ограниченную поддержку dfns. | |
Языки ассемблера | ||
АХК | Поскольку анонимные функции AutoHotkey V2 поддерживаются с синтаксисом, аналогичным JavaScript. | |
Баш | Создана библиотека для поддержки анонимных функций в Bash. [5] | |
С | Поддержка предоставляется в Clang , а также в библиотеке компилятора LLVM . Поддержка GCC предоставляется для реализации макроса, которая обеспечивает возможность использования. Более подробную информацию смотрите ниже. | |
С# | [6] | |
С++ | По C++11 стандарту | |
CFML | Начиная с Райло 4, [7] КолдФьюжн 10 [8] | |
Кложур | [9] | |
КОБОЛ | Micro Focus поддерживает лямбда-выражения, которые называются анонимными делегатами/методами. Нестандартный диалект Managed COBOL [10] | |
Завиток | ||
Д | [11] | |
Дарт | [12] | |
Дельфи | [13] | |
Дилан | [14] | |
Эйфелева | ||
Вяз | [15] | |
Эликсир | [16] | |
Эрланг | [17] | |
Ф# | [18] | |
Эксель | Функция листа Excel, бета-версия 2021 г. [19] | |
Фактор | «Цитаты» подтверждают это [20] | |
Фортран | ||
Фринк | [21] | |
Идти | [22] | |
Гоша | [23] | |
классный | [24] | |
Хаскелл | [25] | |
Смешанный | [26] | |
Ява | Поддерживается в Java 8 . см. в разделе «Ограничения Java» Подробности ниже. | |
JavaScript | [27] | |
Юлия | [28] | |
Котлин | [29] | |
Лисп | ||
Логток | ||
Два | [30] | |
Свинка | ||
Клен | [31] | |
МАТЛАБ | [32] | |
Максима | [33] | |
Nim | [34] | |
OCaml | [35] | |
Октава | [36] | |
Объектный Паскаль | Delphi, диалект Object Pascal, изначально поддерживает анонимные функции (формально анонимные методы ) начиная с Delphi 2009. Диалект Oxygene Object Pascal также поддерживает их. | |
Objective-C (Mac OS X 10.6+) | Называемые блоки ; Помимо Objective-C, блоки также можно использовать на C и C++ при программировании на платформе Apple. | |
OpenSCAD | Поддержка Function Literal была представлена в версии 2021.01. [37] | |
Паскаль | ||
Перл | [38] | |
PHP | Начиная с PHP 5.3.0 поддерживаются настоящие анонимные функции. [39] Раньше поддерживались только частично анонимные функции, которые работали очень похоже на реализацию C#. | |
ПЛ/Я | ||
Питон | Python поддерживает анонимные функции через синтаксис лямбда. [40] который поддерживает только выражения, а не операторы. | |
Р | ||
Ракетка | [41] | |
Раку | [42] | |
Рекс | ||
РПГ | ||
Руби | Анонимные функции Ruby, унаследованные от Smalltalk , называются блоками . [43] | |
Ржавчина | [44] | |
Скала | [45] | |
Схема | ||
Смолток | Анонимные функции Smalltalk называются блоками . | |
Стандартный ML | [46] | |
Быстрый | Анонимные функции Swift называются замыканиями. [47] | |
Машинопись | [48] | |
Ткл | [49] | |
Налить | [49] | |
Visual Basic .NET v9 | [50] | |
Visual Prolog v 7.2 | [51] | |
Вольфрам Язык | [52] | |
Зиг | [53] |
Примеры
[ редактировать ]Этот раздел содержит инструкции, советы и инструкции . ( декабрь 2018 г. ) |
Многие языки поддерживают анонимные функции или что-то подобное.
АПЛ
[ редактировать ]Лишь некоторые диалекты поддерживают анонимные функции, например dfns , в неявном стиле или их комбинацию.
f←{⍵×⍵} As a dfn
f 1 2 3
1 4 9
g←⊢×⊢ As a tacit 3-train (fork)
g 1 2 3
1 4 9
h←×⍨ As a derived tacit function
h 1 2 3
1 4 9
C (нестандартное расширение)
[ редактировать ]Анонимная функция не поддерживается стандартным языком программирования C, но поддерживается некоторыми диалектами C, такими как GCC. [54] и Кланг .
GCC
[ редактировать ]Коллекция компиляторов GNU (GCC) поддерживает анонимные функции, смешанные с вложенными функциями и выражениями операторов. Он имеет форму:
( { return_type anonymous_functions_name (parameters) { function_body } anonymous_functions_name; } )
Следующий пример работает только с GCC. Из-за того, как макросы расширяются, l_body
не может содержать запятых вне круглых скобок; GCC рассматривает запятую как разделитель между аргументами макроса.
Аргумент l_ret_type
можно удалить, если __typeof__
доступен; в примере ниже, используя __typeof__
в массиве вернется testtype *
, который при необходимости можно разыменовать для получения фактического значения.
#include <stdio.h>
//* this is the definition of the anonymous function */
#define lambda(l_ret_type, l_arguments, l_body) \
({ \
l_ret_type l_anonymous_functions_name l_arguments \
l_body \
&l_anonymous_functions_name; \
})
#define forEachInArray(fe_arrType, fe_arr, fe_fn_body) \
{ \
int i=0; \
for(;i<sizeof(fe_arr)/sizeof(fe_arrType);i++) { fe_arr[i] = fe_fn_body(&fe_arr[i]); } \
}
typedef struct
{
int a;
int b;
} testtype;
void printout(const testtype * array)
{
int i;
for ( i = 0; i < 3; ++ i )
printf("%d %d\n", array[i].a, array[i].b);
printf("\n");
}
int main(void)
{
testtype array[] = { {0,1}, {2,3}, {4,5} };
printout(array);
/* the anonymous function is given as function for the foreach */
forEachInArray(testtype, array,
lambda (testtype, (void *item),
{
int temp = (*( testtype *) item).a;
(*( testtype *) item).a = (*( testtype *) item).b;
(*( testtype *) item).b = temp;
return (*( testtype *) item);
}));
printout(array);
return 0;
}
Clang (C, C++, Objective-C, Objective-C++)
[ редактировать ]Clang поддерживает анонимные функции, называемые блоками . [55] которые имеют вид:
^return_type ( parameters ) { function_body }
Тип вышеперечисленных блоков: return_type (^)(parameters)
.
Используя вышеупомянутое расширение блоков и Grand Central Dispatch (libdispatch), код мог бы выглядеть проще:
#include <stdio.h>
#include <dispatch/dispatch.h>
int main(void) {
void (^count_loop)() = ^{
for (int i = 0; i < 100; i++)
printf("%d\n", i);
printf("ah ah ah\n");
};
/* Pass as a parameter to another function */
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), count_loop);
/* Invoke directly */
count_loop();
return 0;
}
Код с блоками должен быть скомпилирован с помощью -fblocks
и связан с -lBlocksRuntime
С++ (начиная с С++11)
[ редактировать ]C++11 поддерживает анонимные функции (технически функциональные объекты ), называемые лямбда-выражениями . [56] которые имеют вид:
[ captures ] ( params ) specs requires (optional) { body }
где " specs
"имеет форму" specifiers exception attr trailing-return-type
в таком порядке; каждый из этих компонентов является необязательным». Если он отсутствует, тип возвращаемого значения выводится из return
операторы, как если бы это была функция с объявленным типом возвращаемого значения auto
.
Это пример лямбда-выражения:
[](int x, int y) { return x + y; }
C++11 также поддерживает замыкания , называемые здесь захватами. Захваты определяются в квадратных скобках [
и ]
в объявлении лямбда-выражения. Механизм позволяет захватывать эти переменные по значению или по ссылке. Следующая таблица демонстрирует это:
[] // No captures, the lambda is implicitly convertible to a function pointer.
[x, &y] // x is captured by value and y is captured by reference.
[&] // Any external variable is implicitly captured by reference if used
[=] // Any external variable is implicitly captured by value if used.
[&, x] // x is captured by value. Other variables will be captured by reference.
[=, &z] // z is captured by reference. Other variables will be captured by value.
Переменные, захватываемые по значению, по умолчанию являются постоянными. Добавление mutable
после того, как список параметров делает их непостоянными.
C++14 и более новые версии поддерживают init-capture, например:
std::unique_ptr<int> ptr = std::make_unique<int>(42);
[ptr]{ /* ... */ }; // copy assignment is deleted for a unique pointer
[ptr = std::move(ptr)]{ /* ... */ }; // ok
auto counter = [i = 0]() mutable { return i++; }; // mutable is required to modify 'i'
counter(); // 0
counter(); // 1
counter(); // 2
Следующие два примера демонстрируют использование лямбда-выражения:
std::vector<int> some_list{ 1, 2, 3, 4, 5 };
int total = 0;
std::for_each(begin(some_list), end(some_list),
[&total](int x) { total += x; });
// Note that std::accumulate would be a way better alternative here...
При этом вычисляется общее количество всех элементов в списке. Переменная total
сохраняется как часть закрытия лямбда-функции. Поскольку это ссылка на переменную стека total
, он может изменить свое значение.
std::vector<int> some_list{ 1, 2, 3, 4, 5 };
int total = 0;
int value = 5;
std::for_each(begin(some_list), end(some_list),
[&total, value, this](int x) { total += x * value * this->some_func(); });
Это вызовет total
храниться как ссылка, но value
будет сохранен как копия.
Захват this
особенный. Его можно захватить только по значению, а не по ссылке. Однако в C++17 текущий объект можно захватить по значению (обозначаемому *this
), или может быть получено по ссылке (обозначается this
). this
может быть захвачен только в том случае, если ближайшая охватывающая функция является нестатической функцией-членом. Лямбда будет иметь тот же доступ, что и член, создавший ее, с точки зрения защищенных/частных членов.
Если this
фиксируется явно или неявно, затем также проверяется область видимости вложенных членов класса. Доступ к членам this
не требует явного использования this->
синтаксис.
Конкретная внутренняя реализация может различаться, но ожидается, что лямбда-функция, которая захватывает все по ссылке, будет хранить фактический указатель стека функции, в которой она создана, а не отдельные ссылки на переменные стека. Однако, поскольку большинство лямбда-функций небольшие по размеру и локальны, они, скорее всего, являются кандидатами на встраивание и, следовательно, не требуют дополнительного хранилища для ссылок.
Если объект замыкания, содержащий ссылки на локальные переменные, вызывается после самой внутренней области блока его создания, поведение не определено .
Лямбда-функции — это функциональные объекты типа, зависящего от реализации; имя этого типа доступно только компилятору. Если пользователь желает использовать лямбда-функцию в качестве параметра, тип параметра должен быть типом шаблона, или он должен создать std::function
или аналогичный объект для захвата значения лямбда. Использование auto
Ключевое слово может помочь сохранить лямбда-функцию,
auto my_lambda_func = [&](int x) { /*...*/ };
auto my_onheap_lambda_func = new auto([=](int x) { /*...*/ });
Вот пример хранения анонимных функций в переменных, векторах и массивах; и передавая их как именованные параметры:
#include <functional>
#include <iostream>
#include <vector>
double eval(std::function<double(double)> f, double x = 2.0) {
return f(x);
}
int main() {
std::function<double(double)> f0 = [](double x) { return 1; };
auto f1 = [](double x) { return x; };
decltype(f0) fa[3] = {f0, f1, [](double x) { return x * x; }};
std::vector<decltype(f0)> fv = {f0, f1};
fv.push_back([](double x) { return x * x; });
for (size_t i = 0; i < fv.size(); i++) {
std::cout << fv[i](2.0) << std::endl;
}
for (size_t i = 0; i < 3; i++) {
std::cout << fa[i](2.0) << std::endl;
}
for (auto& f : fv) {
std::cout << f(2.0) << std::endl;
}
for (auto& f : fa) {
std::cout << f(2.0) << std::endl;
}
std::cout << eval(f0) << std::endl;
std::cout << eval(f1) << std::endl;
std::cout << eval([](double x) { return x * x; }) << std::endl;
}
Лямбда-выражение с пустой спецификацией захвата ( []
) можно неявно преобразовать в указатель на функцию того же типа, что и лямбда-выражение. Итак, это законно:
auto a_lambda_func = [](int x) -> void { /*...*/ };
void (* func_ptr)(int) = a_lambda_func;
func_ptr(4); //calls the lambda.
Начиная с C++17 , можно объявить лямбду. constexpr
, а поскольку C++20 , consteval
с обычной семантикой. Эти спецификаторы идут после списка параметров, например mutable
. Начиная с C++23 , лямбда также может быть static
если у него нет захватов. static
и mutable
спецификаторы не могут быть объединены.
Кроме того, начиная с C++23, лямбда-выражение может быть рекурсивным посредством явного this
в качестве первого параметра:
auto fibonacci = [](this auto self, int n) { return n <= 1 ? n : self(n - 1) + self(n - 2); };
fibonacci(7); // 13
В дополнение к этому, C++23 изменил синтаксис так, что круглые скобки можно было опустить в случае лямбды, которая не принимает аргументов, даже если лямбда имеет спецификатор. Также сделано так, что последовательность спецификаторов атрибутов, которая появляется перед списком параметров, лямбда-спецификаторами или спецификатором noException (один из них должен быть), применяется к оператору вызова функции или шаблону оператора типа замыкания. В противном случае это относится к типу оператора вызова функции или шаблону оператора. Ранее такая последовательность всегда применялась к типу оператора вызова функции или шаблону оператора типа замыкания, создавая, например, [[noreturn]]
атрибут невозможно использовать с лямбдами.
Библиотека Boost также предоставляет собственный синтаксис для лямбда-функций, используя следующий синтаксис: [57]
for_each(a.begin(), a.end(), std::cout << _1 << ' ');
Начиная с C++14 , параметры функции лямбды могут быть объявлены с помощью auto
. Полученная лямбда называется общей лямбдой и, по сути, представляет собой анонимный шаблон функции, поскольку правила вывода типа автоматических параметров являются правилами вывода аргументов шаблона. Начиная с C++20 , параметры шаблона также могут быть объявлены явно с помощью следующего синтаксиса:
[ captures ] < tparams > requires (optional) ( params ) specs requires (optional) { body }
С#
[ редактировать ]В C# поддержка анонимных функций расширилась благодаря различным версиям компилятора языка. Язык v3.0, выпущенный в ноябре 2007 года вместе с .NET Framework v3.5, имеет полную поддержку анонимных функций. [58] : 7–8 [59] : 26 В C# они называются лямбда-выражениями , следуя исходной версии анонимных функций — лямбда-исчислению . [60] [58] : 7–8, 91 [59] : 91
// the first int is the x' type // the second int is the return type // <see href="http://msdn.microsoft.com/en-us/library/bb549151.aspx" />Func<int,int> foo = x => x * x;
Console.WriteLine(foo(7));
Хотя функция анонимна, ее нельзя присвоить неявно типизированной переменной, поскольку синтаксис лямбда может использоваться для обозначения анонимной функции или дерева выражений, и компилятор не может автоматически определить выбор. [58] : 101–103 Например, это не работает:
// will NOT compile!
var foo = (int x) => x * x;
Однако лямбда-выражение может участвовать в выводе типа и может использоваться в качестве аргумента метода , например, для использования анонимных функций с возможностью Map, доступной с помощью System.Collections.Generic.List
(в ConvertAll()
метод):
// Initialize the list:
var values = new List<int>() { 7, 13, 4, 9, 3 };
// Map the anonymous function over all elements in the list, return the new list
var foo = values.ConvertAll(d => d * d) ;
// the result of the foo variable is of type System.Collections.Generic.List<Int32>
Предыдущие версии C# имели более ограниченную поддержку анонимных функций. C# v1.0, представленный в феврале 2002 года вместе с .NET Framework v1.0, обеспечивал частичную поддержку анонимных функций за счет использования делегатов . [58] : 6 В C# они называются лямбда-выражениями , следуя исходной версии анонимных функций — лямбда-исчислению . [58] : 91 Эта конструкция чем-то похожа на делегаты PHP. В C# 1.0 делегаты подобны указателям на функции, которые ссылаются на явно названный метод внутри класса. (Но в отличие от PHP, имя не требуется во время использования делегата.) C# v2.0, выпущенный в ноябре 2005 года вместе с .NET Framework v2.0, представил концепцию анонимных методов как способа написания безымянных встроенных операторов. блоки, которые могут быть выполнены при вызове делегата. [58] : 6–7 C# 3.0 продолжает поддерживать эти конструкции, но также поддерживает конструкцию лямбда-выражения.
Этот пример компилируется в C# 3.0 и демонстрирует три формы:
public class TestDriver
{
delegate int SquareDelegate(int d);
static int Square(int d)
{
return d * d;
}
static void Main(string[] args)
{
// C# 1.0: Original delegate syntax needed
// initializing with a named method.
SquareDelegate A = new SquareDelegate(Square);
System.Console.WriteLine(A(3));
// C# 2.0: A delegate can be initialized with
// inline code, called an "anonymous method". This
// method takes an int as an input parameter.
SquareDelegate B = delegate(int d) { return d * d; };
System.Console.WriteLine(B(5));
// C# 3.0. A delegate can be initialized with
// a lambda expression. The lambda takes an int, and returns an int.
// The type of x is inferred by the compiler.
SquareDelegate C = x => x * x;
System.Console.WriteLine(C(7));
// C# 3.0. A delegate that accepts one input and
// returns one output can also be implicitly declared with the Func<> type.
System.Func<int,int> D = x => x * x;
System.Console.WriteLine(D(9));
}
}
В случае версии C# 2.0 компилятор C# берет блок кода анонимной функции и создает статическую закрытую функцию. Внутри функция, конечно, получает сгенерированное имя; это сгенерированное имя основано на имени метода, в котором объявлен делегат. Но это имя не раскрывается коду приложения, кроме как с помощью отражения . [58] : 103 В случае версии C# 3.0 применяется тот же механизм.
Язык разметки ColdFusion (CFML)
[ редактировать ]Используя функция ключевое слово:
fn = function(){
// statements
};
Или используя функцию стрелки:
fn = () => {
// statements
};
fn = () => singleExpression // singleExpression is implicitly returned. There is no need for the braces or the return keyword
fn = singleParam => { // if the arrow function has only one parameter, there's no need for parentheses
// statements
}
fn = (x, y) => { // if the arrow function has zero or multiple parameters, one needs to use parentheses
// statements
}
CFML поддерживает любые операторы в определении функции, а не просто выражения.
CFML поддерживает рекурсивные анонимные функции:
factorial = function(n){
return n > 1 ? n * factorial(n-1) : 1;
};
Анонимные функции CFML реализуют замыкание.
Д
[ редактировать ]D использует встроенные делегаты для реализации анонимных функций. Полный синтаксис встроенного делегата:
return_type delegate(arguments){/*body*/}
Если однозначно, тип возвращаемого значения и ключевое слово делегат можно опустить.
(x){return x*x;}
delegate (x){return x*x;} // if more verbosity is needed
(int x){return x*x;} // if parameter type cannot be inferred
delegate (int x){return x*x;} // ditto
delegate double(int x){return x*x;} // if return type must be forced manually
Начиная с версии 2.0, D размещает замыкания в куче, если только компилятор не докажет, что в этом нет необходимости; тот scope
Ключевое слово можно использовать для принудительного выделения стека.
Начиная с версии 2.058 можно использовать сокращенную запись:
x => x*x;
(int x) => x*x;
(x,y) => x*y;
(int x, int y) => x*y;
Анонимную функцию можно присвоить переменной и использовать следующим образом:
auto sqr = (double x){return x*x;};
double y = sqr(4);
Дарт
[ редактировать ]Dart поддерживает анонимные функции. [12]
var sqr = (x) => x * x;
print(sqr(5));
или
print(((x) => x * x)(5));
Дельфи
[ редактировать ]Delphi представила анонимные функции в версии 2009.
program demo;
type
TSimpleProcedure = reference to procedure;
TSimpleFunction = reference to function(const x: string): Integer;
var
x1: TSimpleProcedure;
y1: TSimpleFunction;
begin
x1 := procedure
begin
Writeln('Hello World');
end;
x1; //invoke anonymous method just defined
y1 := function(const x: string): Integer
begin
Result := Length(x);
end;
Writeln(y1('bar'));
end.
PascalABC.NET
[ редактировать ]PascalABC.NET поддерживает анонимные функции, используя синтаксис лямбда.
begin
var n := 10000000;
var pp := (1..n)
.Select(x -> (Random, Random))
.Where(p -> Sqr(p[0]) + Sqr(p[1]) < 1)
.Count / n * 4;
Print(pp);
end.
Эликсир
[ редактировать ]Эликсир использует замыкание fn
для анонимных функций. [16]
sum = fn(a, b) -> a + b end
sum.(4, 3)
#=> 7
square = fn(x) -> x * x end
Enum.map [1, 2, 3, 4], square
#=> [1, 4, 9, 16]
Эрланг
[ редактировать ]Erlang использует синтаксис анонимных функций, аналогичный синтаксису именованных функций. [17]
% Anonymous function bound to the Square variable
Square = fun(X) -> X * X end.
% Named function with the same functionality
square(X) -> X * X.
Идти
[ редактировать ]Go поддерживает анонимные функции. [22]
foo := func(x int) int {
return x * x
}
fmt.Println(foo(10))
Хаскелл
[ редактировать ]Haskell использует краткий синтаксис для анонимных функций (лямбда-выражений). Обратная косая черта должна напоминать λ.
\x -> x * x
Лямбда-выражения полностью интегрированы с механизмом вывода типов и поддерживают весь синтаксис и функции «обычных» функций (за исключением использования нескольких определений для сопоставления с образцом, поскольку список аргументов указывается только один раз).
map (\x -> x * x) [1..5] -- returns [1, 4, 9, 16, 25]
Все следующие эквивалентны:
f x y = x + y
f x = \y -> x + y
f = \x y -> x + y
Смешанный
[ редактировать ]В Haxe анонимные функции называются лямбда и используют синтаксис function(argument-list) expression;
.
var f = function(x) return x*x;
f(8); // 64
(function(x,y) return x+y)(5,6); // 11
Ява
[ редактировать ]Java поддерживает анонимные функции, называемые Lambda Expressions , начиная с JDK 8 . [61]
Лямбда-выражение состоит из разделенного запятыми списка формальных параметров, заключенных в круглые скобки, токена со стрелкой ( ->
) и тело. Типы данных параметров всегда можно опустить, как и круглые скобки, если параметр только один. Тело может состоять из одного оператора или блока операторов. [62]
// with no parameter
() -> System.out.println("Hello, world.")
// with one parameter (this example is an identity function).
a -> a
// with one expression
(a, b) -> a + b
// with explicit type information
(long id, String name) -> "id: " + id + ", name:" + name
// with a code block
(a, b) -> { return a + b; }
// with multiple statements in the lambda body. It needs a code block.
// This example also includes two nested lambda expressions (the first one is also a closure).
(id, defaultPrice) -> {
Optional<Product> product = productList.stream().filter(p -> p.getId() == id).findFirst();
return product.map(p -> p.getPrice()).orElse(defaultPrice);
}
Лямбда-выражения преобразуются в «функциональные интерфейсы» (определяемые как интерфейсы, которые содержат только один абстрактный метод в дополнение к одному или нескольким методам по умолчанию или статическим методам). [62] как в следующем примере:
public class Calculator {
interface IntegerMath {
int operation(int a, int b);
default IntegerMath swap() {
return (a, b) -> operation(b, a);
}
}
private static int apply(int a, int b, IntegerMath op) {
return op.operation(a, b);
}
public static void main(String... args) {
IntegerMath addition = (a, b) -> a + b;
IntegerMath subtraction = (a, b) -> a - b;
System.out.println("40 + 2 = " + apply(40, 2, addition));
System.out.println("20 - 10 = " + apply(20, 10, subtraction));
System.out.println("10 - 20 = " + apply(20, 10, subtraction.swap()));
}
}
В этом примере функциональный интерфейс под названием IntegerMath
объявлено. Лямбда-выражения, реализующие IntegerMath
передаются в apply()
метод, который будет выполнен. Методы по умолчанию, такие как swap
определить методы для функций.
В Java 8 появился еще один механизм, названный ссылкой на метод (метод ::
оператор) для создания лямбда-выражения для существующего метода. Ссылка на метод не указывает количество или типы аргументов, поскольку они извлекаются из абстрактного метода функционального интерфейса.
IntBinaryOperator sum = Integer::sum;
В приведенном выше примере функциональный интерфейс IntBinaryOperator
объявляет абстрактный метод int applyAsInt(int, int)
, поэтому компилятор ищет метод int sum(int, int)
в классе java.lang.Integer
.
Отличия от анонимных классов
[ редактировать ]Анонимные классы лямбда-совместимых интерфейсов похожи, но не совсем эквивалентны лямбда-выражениям.
Для иллюстрации на следующем примере: anonymousClass
и lambdaExpression
оба являются экземплярами IntegerMath
которые добавляют два параметра:
IntegerMath anonymousClass = new IntegerMath() {
@Override
public int operation(int a, int b) {
return a + b;
}
};
IntegerMath lambdaExpression = (a, b) -> a + b;
Основное отличие здесь заключается в том, что лямбда-выражению не обязательно нужно выделять новый экземпляр для IntegerMath
и может возвращать один и тот же экземпляр каждый раз при запуске этого кода. [63]
Кроме того, по крайней мере, в реализации OpenJDK лямбды компилируются в вызывать динамические инструкции, в которых тело лямбда-выражения вставлено как статический метод в окружающий класс, [64] вместо того, чтобы полностью создавать новый файл класса.
Ограничения Java
[ редактировать ]Лямбды Java 8 имеют следующие ограничения:
- Лямбды могут генерировать проверенные исключения, но такие лямбды не будут работать с интерфейсами, используемыми API коллекции.
- Переменные, находящиеся в области, в которой объявлена лямбда, могут быть доступны внутри лямбды только в том случае, если они фактически являются окончательными, т. е. если переменная не мутируется внутри или за пределами области лямбда.
JavaScript
[ редактировать ]JavaScript / ECMAScript поддерживает анонимные функции.
alert((function(x){
return x * x;
})(10));
ES6 поддерживает синтаксис «стрелочной функции», где символ => отделяет список параметров анонимной функции от тела:
alert((x => x * x)(10));
Эта конструкция часто используется в Букмарклетах . Например, чтобы изменить заголовок текущего документа (видимый в строке заголовка его окна ) на его URL-адрес , может показаться, что работает следующий букмарклет.
document.title=location.href;
Однако, поскольку оператор присваивания возвращает значение (сам URL-адрес), многие браузеры фактически создают новую страницу для отображения этого значения.
Вместо этого можно использовать анонимную функцию, которая не возвращает значение:
(function(){document.title=location.href;})();
Оператор функции в первой (внешней) паре круглых скобок объявляет анонимную функцию, которая затем выполняется при использовании с последней парой круглых скобок. Это почти эквивалентно следующему, которое заполняет среду f
в отличие от анонимной функции.
var f = function(){document.title=location.href;}; f();
Используйте void() , чтобы избежать появления новых страниц для произвольных анонимных функций:
void(function(){return document.title=location.href;}());
или просто:
void(document.title=location.href);
В JavaScript есть синтаксические тонкости определения, вызова и оценки анонимных функций. Эти подсознательные нюансы являются прямым следствием оценки выражений в скобках. Это иллюстрируют следующие конструкции, которые называются выражением немедленно вызываемой функции :
(function(){ ... }())
и
(function(){ ... })()
Представляя " function(){ ... }
" к f
, форма конструкций
скобка внутри скобки (f())
и скобка применяется к скобке (f)()
.
Обратите внимание на общую синтаксическую двусмысленность выражения в скобках, аргументов функции в скобках и круглых скобок вокруг формальных параметров в определении функции. В частности, JavaScript определяет ,
(запятая) в контексте выражения в скобках. То, что синтаксические формы выражения и аргументов функции совпадают (без учета синтаксиса формальных параметров функции) – не простое совпадение! Если f
не идентифицируется в приведенных выше конструкциях, они становятся (())
и ()()
. Первый не дает синтаксического намека на какую-либо резидентную функцию, но второй ДОЛЖЕН оценить первую скобку как функцию, чтобы быть законным JavaScript. (Кроме того: например, ()
может быть ([],{},42,"abc",function(){}), если выражение оценивается как функция.)
Кроме того, функция является экземпляром объекта (аналогично объекты являются экземплярами функции), а скобки для обозначения литерала объекта: {}
для кода со скобками используются при таком определении функции (в отличие от использования new Function(...)
). В очень широком, нестрогом смысле (особенно учитывая, что глобальные привязки скомпрометированы), произвольная последовательность операторов JavaScript в фигурных скобках, {stuff}
, можно считать фиксированной точкой
(function(){( function(){( ... {( function(){stuff}() )} ... )}() )}() )
Правильнее, но с оговорками,
( function(){stuff}() ) ~=
A_Fixed_Point_of(
function(){ return function(){ return ... { return function(){stuff}() } ... }() }()
)
Обратите внимание на значение анонимной функции в следующих фрагментах JavaScript:
function(){ ... }()
без окружения()
это вообще не законно(f=function(){ ... })
не «забывает»f
глобально непохожий(function f(){ ... })
- производительности Метрики для анализа пространственной и временной сложности вызовов функций, стека вызовов и т. д. в интерпретатора механизме JavaScript легко реализуются с помощью этих последних анонимных функциональных конструкций. Из последствий результатов можно сделать вывод о некоторых деталях рекурсивной и итеративной реализации движка, особенно о хвостовой рекурсии .
Юлия
[ редактировать ]В Julia анонимные функции определяются с использованием синтаксиса (arguments)->(expression)
,
julia> f = x -> x*x; f(8)
64
julia> ((x,y)->x+y)(5,6)
11
Котлин
[ редактировать ]Котлин поддерживает анонимные функции с синтаксисом {arguments -> expression}
,
val sum = { x: Int, y: Int -> x + y }
sum(5,6) // returns 11
val even = { x: Int -> x%2==0}
even(4) // returns true
Лисп
[ редактировать ]Lisp и Scheme поддерживают анонимные функции с использованием конструкции «лямбда», которая является ссылкой на лямбда-исчисление . Clojure поддерживает анонимные функции со специальной формой «fn» и синтаксисом чтения #().
(lambda (arg) (* arg arg))
Общий Лисп
[ редактировать ]В Common Lisp есть концепция лямбда-выражений. Лямбда-выражение записывается в виде списка с символом «лямбда» в качестве первого элемента. Затем список содержит список аргументов, документацию или объявления и тело функции. Лямбда-выражения можно использовать внутри лямбда-форм и со специальным оператором «функция».
(function (lambda (arg) (do-something arg)))
«функция» может быть сокращена до #'. Кроме того, существует лямбда- макрос , который расширяется до функциональной формы:
; using sharp quote
#'(lambda (arg) (do-something arg))
; using the lambda macro:
(lambda (arg) (do-something arg))
Одним из типичных применений анонимных функций в Common Lisp является передача их функциям более высокого порядка, таким как Mapcar , который применяет функцию к каждому элементу списка и возвращает список результатов.
(mapcar #'(lambda (x) (* x x))
'(1 2 3 4))
; -> (1 4 9 16)
Лямбда -форма в Common Lisp позволяет лямбда-выражение записать при вызове функции:
((lambda (x y)
(+ (sqrt x) (sqrt y)))
10.0
12.0)
Анонимным функциям в Common Lisp позднее можно будет дать глобальные имена:
(setf (symbol-function 'sqr)
(lambda (x) (* x x)))
; which allows us to call it using the name SQR:
(sqr 10.0)
Схема
[ редактировать ]Scheme Именованные функции — это просто синтаксический сахар для анонимных функций, привязанных к именам:
(define (somename arg)
(do-something arg))
расширяется (и эквивалентно) до
(define somename
(lambda (arg)
(do-something arg)))
Кложур
[ редактировать ]Clojure поддерживает анонимные функции через специальную форму «fn»:
(fn [x] (+ x 3))
Существует также синтаксис чтения для определения лямбды:
#(+ % %2%3) ; Defines an anonymous function that takes three arguments and sums them.
Как и Scheme, «именованные функции» Clojure — это просто синтаксический сахар для лямбда-выражений, привязанных к именам:
(defn func [arg] (+ 3 arg))
расширяется до:
(def func (fn [arg] (+ 3 arg)))
Два
[ редактировать ]В Lua (как и в Scheme) все функции анонимны. в Именованная функция Lua — это просто переменная, содержащая ссылку на объект функции. [65]
Таким образом, в Луа
function foo(x) return 2*x end
это просто синтаксический сахар для
foo = function(x) return 2*x end
Пример использования анонимных функций для сортировки в обратном порядке:
table.sort(network, function(a,b)
return a.name > b.name
end)
Язык Wolfram, Mathematica
[ редактировать ]Wolfram Language — это язык программирования Mathematica . Анонимные функции важны при программировании последних. Есть несколько способов их создания. Ниже приведены несколько анонимных функций, которые увеличивают число. Первый является наиболее распространенным. #1
относится к первому аргументу и &
отмечает конец анонимной функции.
#1+1&
Function[x,x+1]
x \[Function] x+1
Так, например:
f:= #1^2&;f[8]
64
#1+#2&[5,6]
11
Кроме того, в Mathematica есть добавленная конструкция для создания рекурсивных анонимных функций. Символ «#0» относится ко всей функции. Следующая функция вычисляет факториал входных данных:
If[#1 == 1, 1, #1 * #0[#1-1]]&
Например, 6-факториал будет выглядеть так:
If[#1 == 1, 1, #1 * #0[#1-1]]&[6]
720
МАТЛАБ, Октава
[ редактировать ]Анонимные функции в MATLAB или Octave определяются с использованием синтаксиса @(argument-list)expression
. Любые переменные, которые не найдены в списке аргументов, наследуются из окружающей области и фиксируются по значению.
>> f = @(x)x*x; f(8)
ans = 64
>> (@(x,y)x+y)(5,6) % Only works in Octave
ans = 11
Максима
[ редактировать ]В Maxima анонимные функции определяются с использованием синтаксиса lambda(argument-list,expression)
,
f: lambda([x],x*x); f(8);
64
lambda([x,y],x+y)(5,6);
11
МЛ
[ редактировать ]Различные диалекты ML поддерживают анонимные функции.
OCaml
[ редактировать ]Анонимные функции в OCaml — это функции без объявленного имени. Вот пример анонимной функции, которая умножает свои входные данные на два:
fun x -> x*2
В этом примере fun — это ключевое слово, указывающее, что функция является анонимной. Мы передаем аргумент x и ->, чтобы отделить аргумент от тела. [66]
Ф#
[ редактировать ]F# поддерживает анонимные функции, [18] следующее:
(fun x -> x * x) 20 // 400
Стандартный ML
[ редактировать ]Стандартное машинное обучение поддерживает следующие анонимные функции:
fn arg => arg * arg
Nim
[ редактировать ]Nim поддерживает многострочные анонимные функции с несколькими выражениями. [34]
var anon = proc (var1, var2: int): int = var1 + var2
assert anon(1, 2) == 3
Многострочный пример:
var anon = func (x: int): bool =
if x > 0:
result = true
else:
result = false
assert anon(9)
Анонимные функции могут передаваться в качестве входных параметров других функций:
var cities = @["Frankfurt", "Tokyo", "New York"]
cities.sort(
proc (x, y: string): int = cmp(x.len, y.len)
)
Анонимная функция — это, по сути, функция без имени.
Перл
[ редактировать ]Перл 5
[ редактировать ]Perl 5 поддерживает анонимные функции, [38] следующее:
(sub { print "I got called\n" })->(); # 1. fully anonymous, called as created
my $squarer = sub { my $x = shift; $x * $x }; # 2. assigned to a variable
sub curry {
my ($sub, @args) = @_;
return sub { $sub->(@args, @_) }; # 3. as a return value of another function
}
# example of currying in Perl programming
sub sum { my $tot = 0; $tot += $_ for @_; $tot } # returns the sum of its arguments
my $curried = curry \&sum, 5, 7, 9;
print $curried->(1,2,3), "\n"; # prints 27 ( = 5 + 7 + 9 + 1 + 2 + 3 )
Другие конструкции принимают в качестве аргументов голые блоки , которые выполняют функцию, аналогичную лямбда-функциям с одним параметром, но не имеют того же соглашения о передаче параметров, что и функции — @_ не установлен.
my @squares = map { $_ * $_ } 1..10; # map and grep don't use the 'sub' keyword
my @square2 = map $_ * $_, 1..10; # braces unneeded for one expression
my @bad_example = map { print for @_ } 1..10; # values not passed like normal Perl function
PHP
[ редактировать ]До версии 4.0.1 в PHP не было поддержки анонимных функций. [67]
PHP с 4.0.1 по 5.3
[ редактировать ]PHP 4.0.1 представил create_function
это была первоначальная поддержка анонимных функций. Этот вызов функции создает новую функцию со случайным именем и возвращает ее имя (в виде строки).
$foo = create_function('$x', 'return $x*$x;');
$bar = create_function("\$x", "return \$x*\$x;");
echo $foo(10);
Список аргументов и тело функции должны быть заключены в одинарные кавычки или знаки доллара должны быть экранированы.
В противном случае PHP предполагает " $x
" означает переменную $x
и заменит его в строку (несмотря на то, что он, возможно, не существует) вместо того, чтобы оставить " $x
"в строке.
Для функций с кавычками или функций со многими переменными может оказаться довольно утомительно проверять, соответствует ли тело предполагаемой функции тому, что интерпретирует PHP.
Каждый вызов create_function
создает новую функцию, которая существует для остальной части программы и не может быть удалена сборщиком мусора , необратимо используя память в программе. Если это используется для создания анонимных функций много раз, например, в цикле, это может вызвать такие проблемы, как раздувание памяти.
PHP 5.3
[ редактировать ]В PHP 5.3 добавлен новый класс под названием Closure
и волшебный метод __invoke()
это делает экземпляр класса вызываемым. [68]
$x = 3;
$func = function($z) { return $z * 2; };
echo $func($x); // prints 6
В этом примере $func
является примером Closure
и echo $func($x)
эквивалентно echo $func->__invoke($x)
.
PHP 5.3 имитирует анонимные функции, но не поддерживает настоящие анонимные функции, поскольку функции PHP по-прежнему не являются объектами первого класса.
PHP 5.3 поддерживает замыкания, но переменные должны быть явно указаны как таковые:
$x = 3;
$func = function() use(&$x) { $x *= 2; };
$func();
echo $x; // prints 6
Переменная $x
связан ссылкой, поэтому вызов $func
изменяет его, и изменения видны вне функции.
PHP 7.4
[ редактировать ]Функции стрелок были представлены в PHP 7.4.
$x = 3;
$func = fn($z) => $z * 2;
echo $func($x); // prints 6
Диалекты Пролога
[ редактировать ]Логток
[ редактировать ]Logtalk использует следующий синтаксис для анонимных предикатов (лямбда-выражений):
{FreeVar1, FreeVar2, ...}/[LambdaParameter1, LambdaParameter2, ...]>>Goal
Простой пример без свободных переменных и с использованием предиката сопоставления списка:
| ?- meta::map([X,Y]>>(Y is 2*X), [1,2,3], Ys).
Ys = [2,4,6]
yes
Также поддерживается каррирование. Приведенный выше пример можно записать так:
| ?- meta::map([X]>>([Y]>>(Y is 2*X)), [1,2,3], Ys).
Ys = [2,4,6]
yes
Визуальный Пролог
[ редактировать ]Анонимные функции (в общем анонимные предикаты ) были введены в Visual Prolog в версии 7.2. [69] Анонимные предикаты могут захватывать значения из контекста. Если он создан в члене объекта, он также может получить доступ к состоянию объекта (путем захвата This
).
mkAdder
возвращает анонимную функцию, которая захватила аргумент X
в закрытии. Возвращаемая функция — это функция, которая добавляет X
на его аргумент:
clauses
mkAdder(X) = { (Y) = X+Y }.
Питон
[ редактировать ]Python поддерживает простые анонимные функции через лямбда-форму. [40] Исполняемое тело лямбды должно быть выражением и не может быть инструкцией, что является ограничением, ограничивающим ее полезность. Значение, возвращаемое лямбда-выражением, является значением содержащегося выражения. Лямбда-формы можно использовать везде, где можно использовать обычные функции. Однако эти ограничения делают его очень ограниченной версией обычной функции. Вот пример:
>>> foo = lambda x: x * x
>>> foo(10)
100
В целом, соглашение Python поощряет использование именованных функций, определенных в той же области, что и анонимные функции в других языках. Это приемлемо, поскольку локально определенные функции реализуют всю мощь замыканий и почти так же эффективны, как использование лямбда-выражений в Python. В этом примере можно сказать, что встроенная степенная функция была каррирована :
>>> def make_pow(n):
... def fixed_exponent_pow(x):
... return pow(x, n)
... return fixed_exponent_pow
...
>>> sqr = make_pow(2)
>>> sqr(10)
100
>>> cub = make_pow(3)
>>> cub(10)
1000
Р
[ редактировать ]В R анонимные функции определяются с использованием синтаксиса function(argument-list)expression
, который имеет сокращение начиная с версии 4.1.0 \
, аналог Хаскеля.
> f <- function(x)x*x; f(8)
[1] 64
> (function(x,y)x+y)(5,6)
[1] 11
> # Since R 4.1.0
> (\(x,y) x+y)(5, 6)
[1] 11
Раку
[ редактировать ]В Raku все блоки (даже связанные с if, while и т.п.) являются анонимными функциями. Блок, который не используется в качестве значения r, выполняется немедленно.
- полностью анонимный, называется как созданный
{ say "I got called" };
- присвоено переменной
my $squarer1 = -> $x { $x * $x }; # 2a. pointy block my $squarer2 = { $^x * $^x }; # 2b. twigil my $squarer3 = { my $x = shift @_; $x * $x }; # 2c. Perl 5 style
- карри
sub add ($m, $n) { $m + $n } my $seven = add(3, 4); my $add_one = &add.assuming(m => 1); my $eight = $add_one($seven);
- Объект WhatWordCode
my $w = * - 1; # WhateverCode object my $b = { $_ - 1 }; # same functionality, but as Callable block
Руби
[ редактировать ]Ruby поддерживает анонимные функции, используя синтаксическую структуру, называемую блоком . В Ruby существует два типа данных для блоков. Proc
s ведут себя аналогично замыканиям , тогда как lambda
s ведут себя более похоже на анонимную функцию. [43] При передаче методу блок в некоторых случаях преобразуется в Proc.
# Example 1:
# Purely anonymous functions using blocks.
ex = [16.2, 24.1, 48.3, 32.4, 8.5]
=> [16.2, 24.1, 48.3, 32.4, 8.5]
ex.sort_by { |x| x - x.to_i } # Sort by fractional part, ignoring integer part.
=> [24.1, 16.2, 48.3, 32.4, 8.5]
# Example 2:
# First-class functions as an explicit object of Proc -
ex = Proc.new { puts "Hello, world!" }
=> #<Proc:0x007ff4598705a0@(irb):7>
ex.call
Hello, world!
=> nil
# Example 3:
# Function that returns lambda function object with parameters
def multiple_of?(n)
lambda{|x| x % n == 0}
end
=> nil
multiple_four = multiple_of?(4)
=> #<Proc:0x007ff458b45f88@(irb):12 (lambda)>
multiple_four.call(16)
=> true
multiple_four[15]
=> false
Ржавчина
[ редактировать ]В Rust анонимные функции называются замыканиями. [70] Они определяются с использованием следующего синтаксиса:
|<parameter-name>: <type>| -> <return-type> { <body> };
Например:
let f = |x: i32| -> i32 { x * 2 };
Однако с помощью вывода типа компилятор может определить тип каждого параметра и тип возвращаемого значения, поэтому приведенную выше форму можно записать как:
let f = |x| { x * 2 };
При замыканиях с одним выражением (т. е. телом с одной строкой) и неявным возвращаемым типом фигурные скобки можно опустить:
let f = |x| x * 2;
Замыкания без входного параметра записываются так:
let f = || println!("Hello, world!");
Замыкания могут передаваться в качестве входных параметров функций, которые ожидают указатель на функцию:
// A function which takes a function pointer as an argument and calls it with
// the value `5`.
fn apply(f: fn(i32) -> i32) -> i32 {
// No semicolon, to indicate an implicit return
f(5)
}
fn main() {
// Defining the closure
let f = |x| x * 2;
println!("{}", apply(f)); // 10
println!("{}", f(5)); // 10
}
Однако для описания того, как фиксируются значения в теле замыкания, могут потребоваться сложные правила. Они реализуются с помощью Fn
, FnMut
, и FnOnce
функции: [71]
Fn
: замыкание фиксируется по ссылке (&T
). Они используются для функций, которые все еще можно вызывать, если у них есть только ссылочный доступ (с&
) к окружающей среде.FnMut
: замыкание фиксируется по изменяемой ссылке (&mut T
). Они используются для функций, которые можно вызывать, если у них есть доступ к изменяемым ссылкам (с&mut
) к окружающей среде.FnOnce
: замыкание захватывает по значению (T
). Они используются для функций, которые вызываются только один раз.
Благодаря этим особенностям компилятор будет захватывать переменные наименее ограничительным образом. [71] Они помогают управлять тем, как значения перемещаются между областями действия, что очень важно, поскольку Rust следует конструкции жизненного цикла, чтобы гарантировать, что значения «заимствованы» и перемещены предсказуемым и явным образом. [72]
Ниже показано, как можно передать замыкание в качестве входного параметра, используя метод Fn
черта:
// A function that takes a value of type F (which is defined as
// a generic type that implements the `Fn` trait, e.g. a closure)
// and calls it with the value `5`.
fn apply_by_ref<F>(f: F) -> i32
where F: Fn(i32) -> i32
{
f(5)
}
fn main() {
let f = |x| {
println!("I got the value: {}", x);
x * 2
};
// Applies the function before printing its return value
println!("5 * 2 = {}", apply_by_ref(f));
}
// ~~ Program output ~~
// I got the value: 5
// 5 * 2 = 10
Предыдущее определение функции также можно для удобства сократить следующим образом:
fn apply_by_ref(f: impl Fn(i32) -> i32) -> i32 {
f(5)
}
Скала
[ редактировать ]В Scala анонимные функции используют следующий синтаксис: [73]
(x: Int, y: Int) => x + y
В определенных контекстах, например, когда анонимная функция является параметром, передаваемым другой функции, компилятор может определить типы параметров анонимной функции, и они могут быть опущены в синтаксисе. В таких контекстах также можно использовать сокращение анонимных функций, используя символ подчеркивания для введения безымянных параметров.
val list = List(1, 2, 3, 4)
list.reduceLeft( (x, y) => x + y )
// Here, the compiler can infer that the types of x and y are both Int.
// Thus, it needs no type annotations on the parameters of the anonymous function.
list.reduceLeft( _ + _ )
// Each underscore stands for a new unnamed parameter in the anonymous function.
// This results in an even shorter equivalent to the anonymous function above.
Смолток
[ редактировать ]В Smalltalk анонимные функции называются блоками и вызываются (вызываются) путем отправки им сообщения «значение». Если необходимо передать несколько аргументов, необходимо использовать сообщение «value:...value:» с соответствующим количеством аргументов-значений.
Например, в GNU Smalltalk
st> f:=[:x|x*x]. f value: 8 .
64
st> [:x :y|x+y] value: 5 value: 6 .
11
Блоки Smalltalk технически являются замыканиями, что позволяет им выйти за рамки своей определяющей области и по-прежнему ссылаться на объявленные в них переменные.
st> f := [:a|[:n|a+n]] value: 100 .
a BlockClosure
"returns the inner block, which adds 100 (captured in "a" variable) to its argument."
st> f value: 1 .
101
st> f value: 2 .
102
Быстрый
[ редактировать ]В Swift анонимные функции называются замыканиями. [47] Синтаксис имеет следующую форму:
{ (parameters) -> returnType in
statement
}
Например:
{ (s1: String, s2: String) -> Bool in
return s1 > s2
}
Для краткости и выразительности типы параметров и тип возвращаемого значения можно опустить, если их можно вывести:
{ s1, s2 in return s1 > s2 }
Аналогичным образом, Swift также поддерживает неявные операторы возврата для замыканий с одним оператором:
{ s1, s2 in s1 > s2 }
Наконец, имена параметров также можно опустить; если они опущены, ссылки на параметры используются с использованием сокращенных имен аргументов, состоящих из символа $, за которым следует их позиция (например, $0, $1, $2 и т. д.):
{ $0 > $1 }
Ткл
[ редактировать ]В Tcl применение анонимной функции возведения в квадрат к 2 выглядит следующим образом: [74]
apply {x {expr {$x*$x}}} 2
# returns 4
В этом примере участвуют два кандидата на роль функции в Tcl. Самый общий вариант обычно называется префиксом команды , и если переменная f содержит такую функцию, то способ выполнения приложения функции f ( x ) будет следующим:
{*}$f $x
где {*}
— префикс расширения (новый в Tcl 8.5). Префикс команды в приведенном выше примере:
применять {x {expr {$x*$x}}}
Имена команд могут быть привязаны к префиксам команд с помощью interp alias
команда. Префиксы команд поддерживают каррирование . Префиксы команд очень распространены в API Tcl .
Другой кандидат на роль «функции» в Tcl обычно называется лямбда и выглядит как {x {expr {$x*$x}}}
часть приведенного выше примера. Это часть, которая кэширует скомпилированную форму анонимной функции, но ее можно вызвать только путем передачи в функцию. apply
команда. Лямбды не поддерживают каррирование, если только они не объединены с apply
для формирования префикса команды. Лямбды редко встречаются в API Tcl.
Налить
[ редактировать ]В Vala анонимные функции поддерживаются как лямбда-выражения. [75]
delegate int IntOp (int x, int y);
void main () {
IntOp foo = (x, y) => x * y;
stdout.printf("%d\n", foo(10,5));
}
Визуальный Бейсик .NET
[ редактировать ]Visual Basic .NET 2008 представил анонимные функции через лямбда-форму. В сочетании с неявной типизацией VB обеспечивает экономичный синтаксис для анонимных функций. Как и в Python, в VB.NET анонимные функции должны быть определены в одной строке; они не могут быть составными утверждениями. Более того, анонимная функция в VB.NET должна действительно быть функцией VB.NET. Function
- он должен возвращать значение.
Dim foo = Function(x) x * x
Console.WriteLine(foo(10))
В Visual Basic.NET 2010 добавлена поддержка многострочных лямбда-выражений и анонимных функций без возвращаемого значения. Например, функция для использования в потоке.
Dim t As New System.Threading.Thread(Sub ()
For n As Integer = 0 To 10 'Count to 10
Console.WriteLine(n) 'Print each number
Next
End Sub
)
t.Start()
См. также
[ редактировать ]Ссылки
[ редактировать ]- ^ «Функции высшего порядка» . Learnyouahaskell.com . Проверено 3 декабря 2014 г.
- ^ Фернандес, Марибель (2009), Модели вычислений: введение в теорию вычислимости , Темы бакалавриата по информатике, Springer Science & Business Media, стр. 33, ISBN 9781848824348 ,
Лямбда-исчисление ... было введено Алонзо Чёрчем в 1930-х годах как точное обозначение теории анонимных функций.
- ^ «Выражения стрелочных функций — JavaScript» . МДН . Проверено 21 августа 2019 г.
- ^ «Типы доступа» . www.adaic.org . Проверено 27 июня 2024 г.
- ^ «Баш лямбда» . Гитхаб . 08.03.2019.
- ^ БиллВагнер. «Лямбда-выражения — справочник по C#» . docs.microsoft.com . Проверено 24 ноября 2020 г.
- ^ «Поддержка закрытия» . Архивировано из оригинала 6 января 2014 г. Проверено 5 января 2014 г.
- ^ «Что нового в ColdFusion 10» . Архивировано из оригинала 6 января 2014 г. Проверено 5 января 2014 г.
- ^ «Clojure — функции высшего порядка» . Clojure.org . Проверено 14 января 2022 г.
- ^ «Управляемый справочник COBOL» . Документация Микро Фокус . Микро Фокус . Архивировано из оригинала 25 февраля 2014 года . Проверено 25 февраля 2014 г.
- ^ «Функции — язык программирования D» . dlang.org . Проверено 14 января 2022 г.
- ^ Jump up to: а б «Экскурсия по языку дартс» . dart.dev . Проверено 24 ноября 2020 г.
- ^ «Анонимные методы в Delphi — RAD Studio» . docwiki.embarcadero.com . Проверено 24 ноября 2020 г.
- ^ «Функции — Программирование Дилана» . opendylan.org . Проверено 14 января 2022 г.
- ^ «документы/синтаксис» . elm-lang.org . Проверено 14 января 2022 г.
- ^ Jump up to: а б «Синтаксис Эрланга/Эликсира: ускоренный курс» . эликсир-lang.github.com . Проверено 24 ноября 2020 г.
- ^ Jump up to: а б «Эрланг -- Забавы» . erlang.org . Проверено 24 ноября 2020 г.
- ^ Jump up to: а б Картермп. «Лямбда-выражения: забавное ключевое слово — F#» . docs.microsoft.com . Проверено 24 ноября 2020 г.
- ^ «LAMBDA: совершенная функция листов Excel» . microsoft.com . 25 января 2021 г. Проверено 30 марта 2021 г.
- ^ «Котировки – Факторная документация» . Проверено 26 декабря 2015 г.
Цитата — это анонимная функция (значение, обозначающее фрагмент кода), которую можно использовать в качестве значения и вызывать с помощью фундаментальных комбинаторов.
- ^ «Фринк» . frinklang.org . Проверено 24 ноября 2020 г.
- ^ Jump up to: а б «Анонимные функции в GoLang» . Документы GoLang . 9 января 2020 г. Проверено 24 ноября 2020 г.
- ^ «Документация Госу» (PDF) . Проверено 4 марта 2013 г.
- ^ «Отличная документация» . Архивировано из оригинала 22 мая 2012 года . Проверено 29 мая 2012 г.
- ^ «Анонимная функция — HaskellWiki» . wiki.haskell.org . Проверено 14 января 2022 г.
- ^ «Лямбда» . Haxe — Кроссплатформенный набор инструментов . Проверено 14 января 2022 г.
- ^ «Функции — JavaScript | MDN» . http://developer.mozilla.org . Проверено 14 января 2022 г.
- ^ «Функции · Язык Джулии» . docs.julialang.org . Проверено 24 ноября 2020 г.
- ^ «Функции высшего порядка и лямбда-выражения — язык программирования Kotlin» . Котлин . Проверено 24 ноября 2020 г.
- ^ «Программирование на Lua: 6» . www.lua.org . Проверено 24 ноября 2020 г.
- ^ «Программирование на Maple: 1.6: Анонимные функции и выражения — Центр приложений» . www.maplesoft.com . Проверено 24 ноября 2020 г.
- ^ «Анонимные функции — MATLAB и Simulink» . www.mathworks.com . Проверено 14 января 2022 г.
- ^ «Руководство Maxima 5.17.1: 39. Определение функций» . maths.cnam.fr . Проверено 24 ноября 2020 г.
- ^ Jump up to: а б «Руководство Нима» . nim-lang.github.io .
- ^ «Примеры кода — OCaml» . ocaml.org . Проверено 24 ноября 2020 г.
- ^ «GNU Octave: анонимные функции» . Octave.org . Проверено 24 ноября 2020 г.
- ^ «Функциональные литералы» . Руководство пользователя OpenSCAD . Викикниги . Проверено 22 февраля 2021 г.
- ^ Jump up to: а б «perlsub — Подпрограммы Perl — Браузер Perldoc» . perldoc.perl.org . Проверено 24 ноября 2020 г.
- ^ «PHP: Анонимные функции — Руководство» . www.php.net . Проверено 24 ноября 2020 г.
- ^ Jump up to: а б «6. Выражения — документация Python 3.9.0» . docs.python.org . Проверено 24 ноября 2020 г.
- ^ «4.4 Функции: лямбда» . docs.racket-lang.org . Проверено 24 ноября 2020 г.
- ^ «Функции» . docs.raku.org . Проверено 14 января 2022 г.
- ^ Jump up to: а б Сосински, Роберт (21 декабря 2008 г.). «Понимание блоков Ruby, процедур и лямбд» . Реактивный.ИО. Архивировано из оригинала 31 мая 2014 г. Проверено 30 мая 2014 г.
- ^ «Замыкания: анонимные функции, которые могут захватывать свое окружение — язык программирования Rust» . doc.rust-lang.org . Проверено 14 января 2022 г.
- ^ «Анонимные функции» . Документация Скала . Проверено 14 января 2022 г.
- ^ «Декламация 3: Функции высшего порядка» . www.cs.cornell.edu . Проверено 14 января 2022 г.
- ^ Jump up to: а б «Замыкания — язык программирования Swift (Swift 5.5)» . docs.swift.org .
- ^ «Документация — повседневные типы» . www.typescriptlang.org . Проверено 14 января 2022 г.
- ^ Jump up to: а б «Проекты/Вала/Руководство — GNOME Wiki!» . Wiki.gnome.org . Проверено 24 ноября 2020 г.
- ^ Кэтлин Доллард (15 сентября 2021 г.). «Лямбда-выражения — Visual Basic» . docs.microsoft.com . Проверено 14 января 2022 г.
- ^ «Справочник по языку/Термины/Анонимные предикаты — wiki.visual-prolog.com» . wiki.visual-prolog.com . Проверено 14 января 2022 г.
- ^ «Чистая анонимная функция: элементарное введение в язык Wolfram» . www.wolfram.com . Проверено 14 января 2022 г.
- ^ «Лямбды, замыкания и все, что между ними · Проблема № 1048 · зигланг/зиг» . Гитхаб . Проверено 21 августа 2023 г.
- ^ «Выражения операторов (с использованием коллекции компиляторов GNU (GCC))» . gcc.gnu.org . Проверено 12 января 2022 г.
- ^ «Спецификация языка для блоков — документация Clang 13» . clang.llvm.org . Проверено 14 января 2022 г.
- ^ «Лямбда-выражения (начиная с C++11) — cppreference.com» . ru.cppreference.com . Проверено 14 января 2022 г.
- ^ Ярви, Яакко; Пауэлл, Гэри (nd). «Глава 16. Boost.Lambda» . Документация по повышению . Способствовать росту . Проверено 22 декабря 2014 г.
- ^ Jump up to: а б с д и ж г Скит, Джон (23 марта 2019 г.). C# в глубине . Мэннинг. ISBN 978-1617294532 .
- ^ Jump up to: а б Альбахари, Джозеф (2022). C# 10 в двух словах О'Рейли. ISBN 978-1-098-12195-2 .
- ^ «Спецификация языка C# 5.0» . Центр загрузки Microsoft .
- ^ «Что нового в JDK 8» .
- ^ Jump up to: а б Учебные пособия по Java: лямбда-выражения , docs.oracle.com
- ^ «Глава 15. Выражения» . docs.oracle.com .
- ^ "jdk/LambdaMethod.java" . Гитхаб .
- ^ «Программирование на Lua — еще о функциях» . Архивировано из оригинала 14 мая 2008 года . Проверено 25 апреля 2008 г.
- ^ «2.7. Анонимные функции · GitBook» . www.cs.cornell.edu .
- ^ http://php.net/create_function в верхней части страницы это указано как «(PHP 4 >= 4.0.1, PHP 5)»
- ^ «PHP: rfc:closures» . wiki.php.net .
- ^ «Анонимные предикаты» . в справочнике по языку Visual Prolog
- ^ «Замыкания — пример ржавчины» . doc.rust-lang.org .
- ^ Jump up to: а б «В качестве входных параметров — пример Rust» . doc.rust-lang.org .
- ^ «Время жизни — ржавчина на примере» . doc.rust-lang.org .
- ^ «Синтаксис анонимной функции — документация Scala» . Архивировано из оригинала 23 июля 2013 г. Проверено 31 декабря 2010 г.
- ^ применить страницу руководства , получено 6 сентября 2012 г.
- ^ Справочное руководство Vala , получено 9 июня 2021 г.
Внешние ссылки
[ редактировать ]- Анонимные методы – когда их следует использовать? (блог об анонимной функции в Delphi)
- Компиляция лямбда-выражений: Scala против Java 8
- Анонимные функции PHP Анонимные функции PHP
- Лямбда-функции на разных языках программирования
- Функции в Go