Jump to content

Анонимная функция

(Перенаправлено из функционального интерфейса )

В компьютерном программировании анонимная функция ( функциональный литерал , лямбда-абстракция , лямбда-функция , лямбда-выражение или блок ) — это определение функции , не привязанное к идентификатору . Анонимные функции часто представляют собой аргументы, передаваемые функциям более высокого порядка или используемые для создания результата функции более высокого порядка, которая должна возвращать функцию. [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]

Многие языки поддерживают анонимные функции или что-то подобное.

Только некоторые диалекты поддерживают анонимные функции, например , 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] и Кланг .

Коллекция компиляторов 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.ListConvertAll() метод):

// 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 поддерживает анонимные функции, используя синтаксис лямбда.

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 / 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 — это функции без объявленного имени. Вот пример анонимной функции, которая умножает свои входные данные на два:

fun x -> x*2

В этом примере fun — это ключевое слово, указывающее, что функция является анонимной. Мы передаем аргумент x и ->, чтобы отделить аргумент от тела. [66]

F# поддерживает анонимные функции, [18] следующее:

(fun x -> x * x) 20 // 400

Стандартный ML

[ редактировать ]

Стандартное машинное обучение поддерживает следующие анонимные функции:

fn  arg => arg * arg

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)
)

Анонимная функция — это, по сути, функция без имени.

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

До версии 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 добавлен новый класс под названием 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.

$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, выполняется немедленно.

  1. полностью анонимный, называется как созданный
    { say "I got called" };
    
  2. присвоено переменной
    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
    
  3. карри
    sub add ($m, $n) { $m + $n }
    my $seven   = add(3, 4);
    my $add_one = &add.assuming(m => 1);
    my $eight   = $add_one($seven);
    
  4. Объект WhatWordCode
    my $w = * - 1;       # WhateverCode object
    my $b = { $_ - 1 };  # same functionality, but as Callable block
    

Ruby поддерживает анонимные функции, используя синтаксическую структуру, называемую блоком . В Ruby существует два типа данных для блоков. Procs ведут себя аналогично замыканиям , тогда как lambdas ведут себя более похоже на анонимную функцию. [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()

См. также

[ редактировать ]
  1. ^ «Функции высшего порядка» . Learnyouahaskell.com . Проверено 3 декабря 2014 г.
  2. ^ Фернандес, Марибель (2009), Модели вычислений: введение в теорию вычислимости , Темы бакалавриата по информатике, Springer Science & Business Media, стр. 33, ISBN  9781848824348 , Лямбда-исчисление ... было введено Алонзо Чёрчем в 1930-х годах как точное обозначение теории анонимных функций.
  3. ^ «Выражения стрелочных функций — JavaScript» . МДН . Проверено 21 августа 2019 г.
  4. ^ «Типы доступа» . www.adaic.org . Проверено 27 июня 2024 г.
  5. ^ «Баш лямбда» . Гитхаб . 08.03.2019.
  6. ^ БиллВагнер. «Лямбда-выражения — справочник по C#» . docs.microsoft.com . Проверено 24 ноября 2020 г.
  7. ^ «Поддержка закрытия» . Архивировано из оригинала 6 января 2014 г. Проверено 5 января 2014 г.
  8. ^ «Что нового в ColdFusion 10» . Архивировано из оригинала 6 января 2014 г. Проверено 5 января 2014 г.
  9. ^ «Clojure — функции высшего порядка» . Clojure.org . Проверено 14 января 2022 г.
  10. ^ «Управляемый справочник COBOL» . Документация Микро Фокус . Микро Фокус . Архивировано из оригинала 25 февраля 2014 года . Проверено 25 февраля 2014 г.
  11. ^ «Функции — язык программирования D» . dlang.org . Проверено 14 января 2022 г.
  12. ^ Перейти обратно: а б «Экскурсия по языку дартс» . dart.dev . Проверено 24 ноября 2020 г.
  13. ^ «Анонимные методы в Delphi — RAD Studio» . docwiki.embarcadero.com . Проверено 24 ноября 2020 г.
  14. ^ «Функции — Программирование Дилана» . opendylan.org . Проверено 14 января 2022 г.
  15. ^ «документы/синтаксис» . elm-lang.org . Проверено 14 января 2022 г.
  16. ^ Перейти обратно: а б «Синтаксис Erlang/Elixir: ускоренный курс» . эликсир-lang.github.com . Проверено 24 ноября 2020 г.
  17. ^ Перейти обратно: а б «Эрланг -- Забавы» . erlang.org . Проверено 24 ноября 2020 г.
  18. ^ Перейти обратно: а б Картермп. «Лямбда-выражения: забавное ключевое слово — F#» . docs.microsoft.com . Проверено 24 ноября 2020 г.
  19. ^ «LAMBDA: совершенная функция листов Excel» . microsoft.com . 25 января 2021 г. Проверено 30 марта 2021 г.
  20. ^ «Котировки – Факторная документация» . Проверено 26 декабря 2015 г. Цитата — это анонимная функция (значение, обозначающее фрагмент кода), которую можно использовать в качестве значения и вызывать с помощью фундаментальных комбинаторов.
  21. ^ «Фринк» . frinklang.org . Проверено 24 ноября 2020 г.
  22. ^ Перейти обратно: а б «Анонимные функции в GoLang» . Документы GoLang . 9 января 2020 г. Проверено 24 ноября 2020 г.
  23. ^ «Документация Госу» (PDF) . Проверено 4 марта 2013 г.
  24. ^ «Отличная документация» . Архивировано из оригинала 22 мая 2012 года . Проверено 29 мая 2012 г.
  25. ^ «Анонимная функция — HaskellWiki» . wiki.haskell.org . Проверено 14 января 2022 г.
  26. ^ «Лямбда» . Haxe — Кроссплатформенный набор инструментов . Проверено 14 января 2022 г.
  27. ^ «Функции — JavaScript | MDN» . http://developer.mozilla.org . Проверено 14 января 2022 г.
  28. ^ «Функции · Язык Джулии» . docs.julialang.org . Проверено 24 ноября 2020 г.
  29. ^ «Функции высшего порядка и лямбды — язык программирования Kotlin» . Котлин . Проверено 24 ноября 2020 г.
  30. ^ «Программирование на Lua: 6» . www.lua.org . Проверено 24 ноября 2020 г.
  31. ^ «Программирование на Maple: 1.6: Анонимные функции и выражения — Центр приложений» . www.maplesoft.com . Проверено 24 ноября 2020 г.
  32. ^ «Анонимные функции — MATLAB и Simulink» . www.mathworks.com . Проверено 14 января 2022 г.
  33. ^ «Руководство Maxima 5.17.1: 39. Определение функций» . maths.cnam.fr . Проверено 24 ноября 2020 г.
  34. ^ Перейти обратно: а б «Руководство Нима» . nim-lang.github.io .
  35. ^ «Примеры кода — OCaml» . ocaml.org . Проверено 24 ноября 2020 г.
  36. ^ «GNU Octave: анонимные функции» . Octave.org . Проверено 24 ноября 2020 г.
  37. ^ «Функциональные литералы» . Руководство пользователя OpenSCAD . Викикниги . Проверено 22 февраля 2021 г.
  38. ^ Перейти обратно: а б «perlsub — Подпрограммы Perl — Браузер Perldoc» . perldoc.perl.org . Проверено 24 ноября 2020 г.
  39. ^ «PHP: Анонимные функции — Руководство» . www.php.net . Проверено 24 ноября 2020 г.
  40. ^ Перейти обратно: а б «6. Выражения — документация Python 3.9.0» . docs.python.org . Проверено 24 ноября 2020 г.
  41. ^ «4.4 Функции: лямбда» . docs.racket-lang.org . Проверено 24 ноября 2020 г.
  42. ^ «Функции» . docs.raku.org . Проверено 14 января 2022 г.
  43. ^ Перейти обратно: а б Сосински, Роберт (21 декабря 2008 г.). «Понимание блоков Ruby, процедур и лямбд» . Реактивный.ИО. Архивировано из оригинала 31 мая 2014 г. Проверено 30 мая 2014 г.
  44. ^ «Замыкания: анонимные функции, которые могут захватывать свое окружение — язык программирования Rust» . doc.rust-lang.org . Проверено 14 января 2022 г.
  45. ^ «Анонимные функции» . Документация Скала . Проверено 14 января 2022 г.
  46. ^ «Декламация 3: Функции высшего порядка» . www.cs.cornell.edu . Проверено 14 января 2022 г.
  47. ^ Перейти обратно: а б «Замыкания — язык программирования Swift (Swift 5.5)» . docs.swift.org .
  48. ^ «Документация — повседневные типы» . www.typescriptlang.org . Проверено 14 января 2022 г.
  49. ^ Перейти обратно: а б «Проекты/Вала/Руководство — GNOME Wiki!» . Wiki.gnome.org . Проверено 24 ноября 2020 г.
  50. ^ Кэтлин Доллард (15 сентября 2021 г.). «Лямбда-выражения — Visual Basic» . docs.microsoft.com . Проверено 14 января 2022 г.
  51. ^ «Справочник по языку/Термины/Анонимные предикаты — wiki.visual-prolog.com» . wiki.visual-prolog.com . Проверено 14 января 2022 г.
  52. ^ «Чистая анонимная функция: элементарное введение в язык Wolfram» . www.wolfram.com . Проверено 14 января 2022 г.
  53. ^ «Лямбды, замыкания и все, что между ними · Проблема № 1048 · зигланг/зиг» . Гитхаб . Проверено 21 августа 2023 г.
  54. ^ «Выражения операторов (с использованием коллекции компиляторов GNU (GCC))» . gcc.gnu.org . Проверено 12 января 2022 г.
  55. ^ «Спецификация языка для блоков — документация Clang 13» . clang.llvm.org . Проверено 14 января 2022 г.
  56. ^ «Лямбда-выражения (начиная с C++11) — cppreference.com» . ru.cppreference.com . Проверено 14 января 2022 г.
  57. ^ Ярви, Яакко; Пауэлл, Гэри (nd). «Глава 16. Boost.Lambda» . Документация по повышению . Способствовать росту . Проверено 22 декабря 2014 г.
  58. ^ Перейти обратно: а б с д и ж г Скит, Джон (23 марта 2019 г.). C# в глубине . Мэннинг. ISBN  978-1617294532 .
  59. ^ Перейти обратно: а б Альбахари, Джозеф (2022). C# 10 в двух словах О'Рейли. ISBN  978-1-098-12195-2 .
  60. ^ «Спецификация языка C# 5.0» . Центр загрузки Microsoft .
  61. ^ «Что нового в JDK 8» .
  62. ^ Перейти обратно: а б Учебные пособия по Java: лямбда-выражения , docs.oracle.com
  63. ^ «Глава 15. Выражения» . docs.oracle.com .
  64. ^ "jdk/LambdaMethod.java" . Гитхаб .
  65. ^ «Программирование на Lua — еще о функциях» . Архивировано из оригинала 14 мая 2008 года . Проверено 25 апреля 2008 г.
  66. ^ «2.7. Анонимные функции · GitBook» . www.cs.cornell.edu .
  67. ^ http://php.net/create_function в верхней части страницы это указано как «(PHP 4 >= 4.0.1, PHP 5)»
  68. ^ «PHP: rfc:closures» . wiki.php.net .
  69. ^ «Анонимные предикаты» . в справочнике по языку Visual Prolog
  70. ^ «Замыкания — пример ржавчины» . doc.rust-lang.org .
  71. ^ Перейти обратно: а б «В качестве входных параметров — пример Rust» . doc.rust-lang.org .
  72. ^ «Время жизни — ржавчина на примере» . doc.rust-lang.org .
  73. ^ «Синтаксис анонимной функции — документация Scala» . Архивировано из оригинала 23 июля 2013 г. Проверено 31 декабря 2010 г.
  74. ^ применить страницу руководства , получено 6 сентября 2012 г.
  75. ^ Справочное руководство Vala , получено 9 июня 2021 г.
[ редактировать ]
Arc.Ask3.Ru: конец переведенного документа.
Arc.Ask3.Ru
Номер скриншота №: ea500d38afd2e8e2d244509c94a94e78__1721260260
URL1:https://arc.ask3.ru/arc/aa/ea/78/ea500d38afd2e8e2d244509c94a94e78.html
Заголовок, (Title) документа по адресу, URL1:
Anonymous function - Wikipedia
Данный printscreen веб страницы (снимок веб страницы, скриншот веб страницы), визуально-программная копия документа расположенного по адресу URL1 и сохраненная в файл, имеет: квалифицированную, усовершенствованную (подтверждены: метки времени, валидность сертификата), открепленную ЭЦП (приложена к данному файлу), что может быть использовано для подтверждения содержания и факта существования документа в этот момент времени. Права на данный скриншот принадлежат администрации Ask3.ru, использование в качестве доказательства только с письменного разрешения правообладателя скриншота. Администрация Ask3.ru не несет ответственности за информацию размещенную на данном скриншоте. Права на прочие зарегистрированные элементы любого права, изображенные на снимках принадлежат их владельцам. Качество перевода предоставляется как есть. Любые претензии, иски не могут быть предъявлены. Если вы не согласны с любым пунктом перечисленным выше, вы не можете использовать данный сайт и информация размещенную на нем (сайте/странице), немедленно покиньте данный сайт. В случае нарушения любого пункта перечисленного выше, штраф 55! (Пятьдесят пять факториал, Денежную единицу (имеющую самостоятельную стоимость) можете выбрать самостоятельно, выплаичвается товарами в течение 7 дней с момента нарушения.)