stringtranslate.com

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

В компьютерном программировании анонимная функция ( функциональный литерал , лямбда-абстракция , лямбда-функция , лямбда-выражение или блок ) — это определение функции , не привязанное к идентификатору . Анонимные функции часто представляют собой аргументы, передаваемые функциям более высокого порядка или используемые для создания результата функции более высокого порядка, которая должна возвращать функцию. [1] Если функция используется только один раз или ограниченное количество раз, анонимная функция может быть синтаксически проще, чем использование именованной функции. Анонимные функции повсеместно распространены в языках функционального программирования и других языках с первоклассными функциями , где они выполняют для типа функции ту же роль, что и литералы для других типов данных .

Анонимные функции берут свое начало в работе Алонзо Чёрча , когда он изобрел лямбда -исчисление , в котором все функции анонимны, в 1936 году, до появления электронных компьютеров. [2] В некоторых языках программирования анонимные функции вводятся с использованием ключевого слова лямбда , а анонимные функции часто называют лямбда-выражениями или лямбда-абстракциями. Анонимные функции были особенностью языков программирования со времен Лиспа в 1958 году, и все большее число современных языков программирования поддерживают анонимные функции.

Имена

Названия «лямбда-абстракция», «лямбда-функция» и «лямбда-выражение» относятся к обозначениям абстракции функции в лямбда-исчислении, где обычная функция f ( x ) = M будет записана x . M ) ( M is выражение, которое использует x ). Сравните с синтаксисом Python .lambda x: M

Название «стрелочная функция» относится к математическому « сопоставлению » символа xM . Сравните с синтаксисом JavaScript . [3]x => M

Использование

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

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

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

Следующие примеры написаны на Python 3.

Сортировка

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

Рассмотрим этот код Python, сортирующий список строк по длине строки:

>>>  a  =  [ 'дом' ,  'машина' ,  'велосипед' ] >>>  a . sort ( key = лямбда  x :  len ( x )) >>>  a [ 'машина' ,  'велосипед' ,  'дом' ]

Анонимной функцией в этом примере является лямбда-выражение:

лямбда  х :  лен ( х )

Анонимная функция принимает один аргумент xи возвращает длину этого аргумента, которая затем используется методом sort()в качестве критерия сортировки.

Основной синтаксис лямбда-функции в Python:

лямбда  arg1 ,  arg2 ,  arg3 ,  ... :  < операция  над  аргументами  ,  возвращающими  значение  > _

Выражение, возвращаемое лямбда-функцией, можно присвоить переменной и использовать в коде в нескольких местах.

>>>  добавить  =  лямбда  а :  а  +  а >>>  добавить ( 20 ) 40

Другим примером может быть сортировка элементов в списке по имени их класса (в Python все имеет класс):

>>>  а  =  [ 10 ,  'число' ,  11,2 ] >>>  а . сортировка ( ключ = лямбда  x :  x . __class__ . __name__ ) >>>  a [ 11.2 ,  10 ,  'число' ]

Обратите внимание, что 11.2имеет имя класса " float", 10имеет имя класса " int" и 'number'имеет имя класса " str". Порядок сортировки: " float", " int", затем " str".

Замыкания

Замыкания — это функции, вычисляемые в среде, содержащей связанные переменные . В следующем примере переменная «порог» привязывается к анонимной функции, которая сравнивает входные данные с порогом.

def  comp ( порог ):  вернуть  лямбда  x :  x  <  порог

Это можно использовать как своего рода генератор функций сравнения:

>>>  func_a  =  комп ( 10 ) >>>  func_b  =  комп ( 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  разделить ( x ,  y ): ...  вернуть  x  /  y>>>  def  делитель ( d ): ...  вернуть  лямбда  x :  разделить ( x ,  d )>>>  половина  =  делитель ( 2 ) >>>  треть  =  делитель ( 3 )>>>  распечатать ( половина ( 32 ),  третья ( 32 )) 16,0  10,666666666666666>>>  распечатать ( половина ( 40 ),  третья ( 40 )) 20.0  13.333333333333334

Хотя использование анонимных функций, возможно, не является обычным явлением при каррировании, его все же можно использовать. В приведенном выше примере функция divisor генерирует функции с указанным делителем. Функции half и Third каррируют функцию деления с фиксированным делителем.

Функция делителя также формирует замыкание, связывая переменную d.

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

Функция высшего порядка — это функция, которая принимает функцию в качестве аргумента или возвращает ее в качестве результата. Обычно это используется для настройки поведения обобщенно определенной функции, часто это конструкция цикла или схема рекурсии. Анонимные функции — удобный способ указать аргументы таких функций. Следующие примеры относятся к Python 3.

карта

Функция карты выполняет вызов функции для каждого элемента списка. В следующем примере каждый элемент массива возводится в квадрат с помощью анонимной функции.

>>>  a  =  [ 1 ,  2 ,  3 ,  4 ,  5 ,  6 ] >>>  список ( map ( лямбда  x :  x * x ,  a )) [ 1 ,  4 ,  9 ,  16 ,  25 ,  36 ]

Анонимная функция принимает аргумент и умножает его на себя (возводит в квадрат). Вышеупомянутая форма не одобряется создателями языка, которые утверждают, что форма, представленная ниже, имеет то же значение и больше соответствует философии языка:

>>>  a  =  [ 1 ,  2 ,  3 ,  4 ,  5 ,  6 ] >>>  [ x * x  для  x  в  a ] [ 1 ,  4 ,  9 ,  16 ,  25 ,  36 ]

Фильтр

Функция фильтра возвращает все элементы из списка, которые оценивают True при передаче определенной функции.

>>>  a  =  [ 1 ,  2 ,  3 ,  4 ,  5 ,  6 ] >>>  список ( фильтр ( лямбда  x :  x  %  2  ==  0 ,  a )) [ 2 ,  4 ,  6 ]

Анонимная функция проверяет, является ли переданный ей аргумент четным. Как и в случае с картой, более подходящей считается форма ниже:

>>>  a  =  [ 1 ,  2 ,  3 ,  4 ,  5 ,  6 ] >>>  [ x  для  x  в  a  , если  x  %  2  ==  0 ] [ 2 ,  4 ,  6 ]

Складывать

Функция сгиба проходит по всем элементам структуры (для списков обычно слева направо, «левая складка», называемая reduceв Python), накапливая значение по мере его выполнения. Это можно использовать для объединения всех элементов структуры в одно значение, например:

>>>  из  functools  import  уменьшить >>>  a  =  [ 1 ,  2 ,  3 ,  4 ,  5 ] >>>  уменьшить ( лямбда  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 ), обычно имеют поддержку анонимных функций, поэтому функции можно определять и передавать так же легко, как и другие данные. типы.

Примеры

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

АПЛ

Лишь некоторые диалекты поддерживают анонимные функции, например dfns , в неявном стиле или их комбинацию.

 f ​​{ × } Как dfn f 1 2 3 1 4 9 g × Как неявный 3 - поезд ( вилка ) g 1 2 3 1 4 9 h × Как производная неявная функция h 1 2 _ 3 1 4 9                                  

C (нестандартное расширение)

Анонимная функция не поддерживается стандартным языком программирования C, но поддерживается некоторыми диалектами C, такими как GCC [53] и Clang .

GCC

Коллекция компиляторов GNU (GCC) поддерживает анонимные функции, смешанные с вложенными функциями и выражениями операторов. Он имеет форму:

( { return_type имя_анонимной_функции ( параметры ) { тело_функции } имя анонимной_функции ; } )          

Следующий пример работает только с GCC. Из-за того, как макросы раскрываются, они l_bodyне могут содержать запятые вне круглых скобок; GCC рассматривает запятую как разделитель между аргументами макроса. Аргумент l_ret_typeможно удалить, если __typeof__он доступен; в приведенном ниже примере использование __typeof__on array вернет testtype *, которое при необходимости можно разыменовать для получения фактического значения.

#include <stdio.h> //* это определение анонимной функции */ #define лямбда(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 ; интервал б ; } Тип теста ;      недействительная распечатка ( const testtype * array ) { int i ; for ( i = 0 ; i < 3 ; ++ i ) printf ( «%d %d \n » , массив [ i ] .a , массив [ i ].b ) ; printf ( " \n " ); }                     int main ( void ) { массив testtype [] = { { 0 , 1 }, { 2 , 3 }, { 4 , 5 } };          распечатка ( массив ); /* анонимная функция задается как функция для foreach */ forEachInArray ( testtype , array , лямбда ( testtype , ( void * item ), { int temp = ( * ( testtype * ) item ). a ; ( * ( testtype * ) item ) .a = ( * ( testtype * ) item ) .b ; ( * ( testtype * ) item ) .b = temp ; return ( * ( testtype * ) item ); })); распечатка ( массив ); вернуть 0 ; }                                       

Clang (C, C++, Objective-C, Objective-C++)

Clang поддерживает анонимные функции, называемые блоками [54] , которые имеют форму:

^ тип_возврата ( параметры ) { тело_функции }      

Тип блоков выше 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 ( "ах ах ах \n " ); };                   /* Передача в качестве параметра в другую функцию */ send_async ( dispatch_get_global_queue ( DISPATCH_QUEUE_PRIORITY_DEFAULT , 0 ), count_loop );   /* Непосредственный вызов */ count_loop ();  вернуть 0 ; } 

Код с блоками должен быть скомпилирован -fblocksи связан с-lBlocksRuntime

С++ (начиная с С++11)

C++11 поддерживает анонимные функции (технически функциональные объекты ), называемые лямбда-выражениями , [55] которые имеют форму:

[ захватывает ] ( параметры ) требуются спецификации ( необязательно ) { тело }          

где " specs" имеет форму " в указанном порядке; каждый из этих компонентов является необязательным". Если он отсутствует, тип возвращаемого значения выводится из операторов, как если бы это была функция с объявленным типом возвращаемого значения .specifiers exception attr trailing-return-typereturnauto

Это пример лямбда-выражения:

[]( int x , int y ) { return x + y ; }         

C++11 также поддерживает замыкания , называемые здесь захватами. Захваты определяются в квадратных скобках [и ]в объявлении лямбда-выражения. Механизм позволяет захватывать эти переменные по значению или по ссылке. Следующая таблица демонстрирует это:

[] // Никаких захватов, лямбда неявно конвертируется в указатель на функцию. [ x , & y ] // x фиксируется по значению, а y фиксируется по ссылке. [ & ] // Любая внешняя переменная неявно фиксируется по ссылке, если она используется. [ = ] // Любая внешняя переменная неявно фиксируется по значению, если она используется. [ & , x ] // x захватывается по значению. Другие переменные будут захватываться по ссылке. [ = , & z ] // z захватывается по ссылке. Другие переменные будут фиксироваться по значению.         

Переменные, захватываемые по значению, по умолчанию являются постоянными. Добавление mutableпосле списка параметров делает их непостоянными.

C++14 и более новые версии поддерживают init-capture, например:

std :: unique_ptr < int > ptr = std :: make_unique < int > ( 42 ); [ ptr ]{ /* ... */ }; // назначение копирования удаляется для уникального указателя [ ptr = std :: move ( ptr )]{ /* ... */ }; // хорошо           автоматический счетчик = [ я = 0 ]() изменяемый { возвращение я ++ ; }; // для изменения счетчика 'i' требуется изменяемый объект (); // 0 счетчик (); // 1 счетчик (); // 2              

Следующие два примера демонстрируют использование лямбда-выражения:

std :: vector <int> some_list { 1 , 2 , 3 , 4 , 5 } ; _ целое число = 0 ; std :: for_each ( begin ( some_list ), end ( some_list ), [ & total ]( int x ) { total += x ; }); // Обратите внимание, что std::accumulate здесь будет лучшей альтернативой...                   

При этом вычисляется общее количество всех элементов в списке. Переменная totalсохраняется как часть замыкания лямбда-функции. Поскольку это ссылка на переменную стека total, она может изменить свое значение.

std :: vector <int> some_list { 1 , 2 , 3 , 4 , 5 } ; _ целое число = 0 ; целое значение = 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 <функционал> #include <iostream> #include <вектор>   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 = []( двойной x ) { return x ; }; decltype ( f0 ) fa [ 3 ] = { f0 , f1 , [] ( double x ) { return x * x ; }}; std :: vector < decltype ( f0 ) > fv = { f0 , f1 }; фв . 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 ::                                                                                                     конец ; } 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 ); //вызывает лямбду.              

Начиная с C++17 , можно объявлять лямбду constexpr, а начиная с C++20constevalс обычной семантикой. Эти спецификаторы идут после списка параметров, например mutable. Начиная с C++23 , лямбда также может быть, staticесли у нее нет захватов. Спецификаторы staticи mutableне разрешается комбинировать.

Кроме того, начиная с C++23, лямбда-выражение может быть рекурсивным через явное значение thisпервого параметра:

auto fibonacci = []( this auto self , int n ) { return n <= 1 ? n : сам ( n - 1 ) + сам ( n - 2 ); }; Фибоначчи ( 7 ); // 13                        

В дополнение к этому в C++23 изменен синтаксис, так что круглые скобки можно опускать в случае лямбды, не принимающей аргументов, даже если лямбда имеет спецификатор. Также сделано так, что последовательность спецификаторов атрибутов, которая появляется перед списком параметров, лямбда-спецификаторами или спецификатором noException (один из них должен быть), применяется к оператору вызова функции или шаблону оператора типа замыкания. В противном случае это относится к типу оператора вызова функции или шаблону оператора. Раньше такая последовательность всегда применялась к типу оператора вызова функции или шаблону оператора типа замыкания, что делало, например, атрибут [[noreturn]]невозможным для использования с лямбда-выражениями.

Библиотека Boost также предоставляет собственный синтаксис для лямбда-функций, используя следующий синтаксис: [56]

for_each ( a.begin ( ) , a.end ( ), std :: cout << _1 << ' ' ) ;      

Начиная с C++14 , параметры функции лямбды могут быть объявлены с помощью auto. Полученная лямбда называется общей лямбдой и, по сути, представляет собой анонимный шаблон функции, поскольку правила вывода типа автоматических параметров являются правилами вывода аргументов шаблона. Начиная с C++20 , параметры шаблона также могут быть объявлены явно с помощью следующего синтаксиса:

[ захватывает ] <tparams> требует ( необязательно ) ( параметры ) спецификации требует ( необязательно ) { тело } _ _              

С#

В C# поддержка анонимных функций расширилась благодаря различным версиям компилятора языка. Язык версии 3.0, выпущенный в ноябре 2007 года вместе с .NET Framework версии 3.5, имеет полную поддержку анонимных функций. [57] : 7–8  [58] : 26  C# называет их лямбда-выражениями , следуя исходной версии анонимных функций — лямбда-исчислению . [59] [57] : 7–8, 91  [58] : 91 

// первое int — это тип x' // второе int — возвращаемый тип // <see href="http://msdn.microsoft.com/en-us/library/bb549151.aspx" />Func<int,int> foo = x => x * x;Console.WriteLine(foo(7));

Хотя функция анонимна, ее нельзя присвоить неявно типизированной переменной, поскольку синтаксис лямбда может использоваться для обозначения анонимной функции или дерева выражений, и компилятор не может автоматически определить выбор. [57] : 101–103  Например, это не работает:

// НЕ скомпилируется! вар foo = ( int x ) => x * x ;        

Однако лямбда-выражение может участвовать в выводе типа и может использоваться в качестве аргумента метода , например, для использования анонимных функций с возможностью Map, доступной с помощью System.Collections.Generic.ListConvertAll()методе):

// Инициализируем список: var Values ​​= new List < int > () { 7 , 13 , 4 , 9 , 3 }; // Сопоставляем анонимную функцию со всеми элементами списка, возвращаем новый список var foo = values . ConvertAll ( d => d * d ) ; // результат переменной foo имеет тип System.Collections.Generic.List<Int32>                    

Предыдущие версии C# имели более ограниченную поддержку анонимных функций. C# v1.0, представленный в феврале 2002 года вместе с .NET Framework v1.0, обеспечивал частичную поддержку анонимных функций за счет использования делегатов . [57] : 6  C# называет их лямбда-выражениями , следуя исходной версии анонимных функций — лямбда-исчислению . [57] : 91  Эта конструкция чем-то похожа на делегаты PHP. В C# 1.0 делегаты подобны указателям на функции, которые ссылаются на явно названный метод внутри класса. (Но в отличие от PHP, имя не требуется во время использования делегата.) C# v2.0, выпущенный в ноябре 2005 года вместе с .NET Framework v2.0, представил концепцию анонимных методов как способа написания безымянных встроенных операторов. блоки, которые могут быть выполнены при вызове делегата. [57] : 6–7  C# 3.0 продолжает поддерживать эти конструкции, но также поддерживает конструкцию лямбда-выражения.

Этот пример компилируется в C# 3.0 и демонстрирует три формы:

 общественный класс TestDriver { делегат int SquareDelegate ( int d ); static int Square ( int d ) { return d * d ; } static void Main ( string [] args ) { // C# 1.0: необходим исходный синтаксис делегата // инициализация именованным методом. SquareDelegate A = новый SquareDelegate ( Square ); Система . Консоль . WriteLine ( A ( 3 )); // C# 2.0: Делегат можно инициализировать с помощью // встроенного кода, называемого «анонимным методом». Этот // метод принимает int в качестве входного параметра. SquareDelegate B = делегат ( int d ) { return d * d ; }; Система . Консоль . WriteLine ( B ( 5 )); // С# 3.0. Делегат можно инициализировать // с помощью лямбда-выражения. Лямбда принимает целое число и возвращает целое число. // Тип x определяется компилятором. SquareDelegate C = x => x * x ; Система . Консоль . WriteLine ( C ( 7 )); // С# 3.0. Делегат, который принимает один ввод и // возвращает один вывод, также может быть неявно объявлен с типом Func<>. Система . Func < int , int > D = x => x * x ; Система . Консоль . WriteLine ( D ( 9 )); } }                                                                           

В случае версии C# 2.0 компилятор C# берет блок кода анонимной функции и создает статическую закрытую функцию. Внутри функция, конечно, получает сгенерированное имя; это сгенерированное имя основано на имени метода, в котором объявлен делегат. Но это имя не раскрывается коду приложения, кроме как с помощью отражения . [57] : 103  В случае версии C# 3.0 применяется тот же механизм.

Язык разметки ColdFusion (CFML)

Используяфункцияключевое слово:

fn  =  function (){  // операторы };

Или используя функцию стрелки:

fn  =  ()  =>  {  // операторы };fn  =  ()  =>  SingleExpression  // SingleExpression возвращается неявно. Нет необходимости в фигурных скобках или ключевом слове return.fn  =  singleParam  =>  { // если стрелочная функция имеет только один параметр, скобки  // не нужны  }fn  =  ( x ,  y )  =>  {  // если стрелочная функция имеет ноль или несколько параметров, необходимо использовать скобки  // операторы }

CFML поддерживает любые операторы в определении функции, а не просто выражения.

CFML поддерживает рекурсивные анонимные функции:

факториал  =  функция ( n ) {  return  n  >  1  ?  n  *  факториал ( n - 1 )  :  1 ; };

Анонимные функции CFML реализуют замыкание.

Д

D использует встроенные делегаты для реализации анонимных функций. Полный синтаксис встроенного делегата:

делегат return_type ( аргументы ){ /*body*/ } 

Если однозначно, тип возвращаемого значения и ключевое слово делегат можно опустить.

( x ){ return x * x ;} Deleate ( x ){ return x * x ;} // если требуется больше подробностей ( int x ) { return x * x ;} // если тип параметра не может быть выведен делегатом ( int x ){ return x * x ;} // то же самое делегат double ( int x ){ return x * x ;} // если тип возвращаемого значения необходимо принудительно указать вручную               

Начиная с версии 2.0, D размещает замыкания в куче, если только компилятор не докажет, что в этом нет необходимости; ключевое scopeслово можно использовать для принудительного выделения стека. Начиная с версии 2.058 можно использовать сокращенную запись:

х => х * х ; ( int x ) => x * x ; ( Икс , y ) => Икс * y ; ( int x , int y ) => x * y ;            

Анонимную функцию можно присвоить переменной и использовать следующим образом:

auto sqr = ( double x ) { return x * x ;}; двойной у = sqr ( 4 );        

Дарт

Dart поддерживает анонимные функции. [11]

вар sqr = ( x ) => x * x ; печать ( sqr ( 5 ));       

или

print ((( x ) => x * x )( 5 ));    

Дельфи

Delphi представила анонимные функции в версии 2009.

демо-версия программы ; введите TSimpleProcedure = ссылка на процедуру ; TSimpleFunction = ссылка на функцию ( const x : string ) : Integer ;             вар x1 : TSimpleProcedure ; y1 : TSimpleFunction ;    Begin x1 := процедура Begin Writeln ( 'Hello World' ) ; конец ; х1 ; //вызываем только что определенный анонимный метод         y1 := функция ( const x : строка ) : целое начало Результат := длина ( x ) ; конец ; Writeln ( y1 ( 'бар' )) ; конец .            

ПаскальABC.NET

PascalABC.NET поддерживает анонимные функции, используя синтаксис лямбда.

начать вар n := 10000000 ; var pp := Диапазон ( 1 , n ) . Выберите ( x -> Rec ( Random () , Random ())) . Где ( p -> sqr ( p . Item1 ) + sqr ( p . Item2 ) < 1 ) . Граф / n * 4 ; Печать ( стр. ) ; конец .            

Эликсир

Эликсир использует замыкание fn для анонимных функций. [15]

сумма = fn ( a , b ) -> a + b конечная сумма . ( 4 , 3 ) #=> 7         квадрат = fn ( x ) -> x * x end Enum . карта [ 1 , 2 , 3 , 4 ], квадрат #=> [1, 4, 9, 16]            

Эрланг

Erlang использует синтаксис анонимных функций, аналогичный синтаксису именованных функций. [16]

% Анонимная функция, привязанная к переменной Square Square = fun ( X ) -> X * X end .       % Именованная функция с той же функциональностью Square ( X ) - > X * X.    

Идти

Go поддерживает анонимные функции. [21]

foo := func ( x int ) int { return x * x } fmt . Println ( фу ( 10 ))        

Хаскелл

Haskell использует краткий синтаксис для анонимных функций (лямбда-выражений). Обратная косая черта должна напоминать λ.

\ х -> х * х    

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

map ( \ x -> x * x ) [ 1 .. 5 ] — возвращает [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 = функция ( x ) return x * x ; ж ( 8 ); // 64      ( функция ( x , y ) возвращает x + y )( 5 , 6 ); // 11   

Джава

Java поддерживает анонимные функции, называемые Lambda Expressions , начиная с JDK 8 . [60]

Лямбда-выражение состоит из списка формальных параметров, разделенных запятыми, заключенных в круглые скобки, маркера стрелки ( ->) и тела. Типы данных параметров всегда можно опустить, как и круглые скобки, если имеется только один параметр. Тело может состоять из одного оператора или блока операторов. [61]

// без параметра () -> System . вне . println ( «Привет, мир!» )  // с одним параметром (данный пример — идентификационная функция). а -> а  // с одним выражением ( a , b ) -> a + b     // с явной информацией о типе ( длинный идентификатор , строковое имя ) -> "id: " + id + ", name:" + name           // с блоком кода ( a , b ) -> { return a + b ; }        // с несколькими операторами в теле лямбда-выражения. Ему нужен блок кода. // Этот пример также включает два вложенных лямбда-выражения (первое из них также является замыканием). ( id , defaultPrice ) -> { Необязательно < Продукт > Product = ProductList . транслировать (). фильтр ( p -> p . getId () == id ). НайтиПервый (); возврат товара . карта ( p -> p . getPrice ()). илиЕльсе ( Цена по умолчанию ); }               

Лямбда-выражения преобразуются в «функциональные интерфейсы» (определяемые как интерфейсы, которые содержат только один абстрактный метод в дополнение к одному или нескольким методам по умолчанию или статическим методам), [61] , как в следующем примере:

Калькулятор общественного класса { интерфейс IntegerMath { int операция ( int a , int b );            по умолчанию IntegerMath swap () { return ( a , b ) -> операция ( b , a ); } }            Private static int apply ( int a , int b , IntegerMath op ) { return op . операция ( а , б ); }              public static void main ( String ... args ) { IntegerMath дополнение = ( a , b ) -> a + b ; Вычитание IntegerMath = ( a , b ) -> a - b ; Система . вне . println ( "40 + 2 = " + применить ( 40 , 2 , сложение )); Система . вне . println ( "20 - 10 =" + применить ( 20 , 10 , вычитание )); Система . вне . println ( "10 - 20 = " + применить ( 20 , 10 , вычитание . поменять местами ())); } }                                        

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добавляют два параметра:

IntegerMathonymousClass = new IntegerMath ( ) { @Override public int Operation ( int a , int b ) { return a + b ; } }; IntegerMath лямбда-выражение = ( a , b ) -> a + b ;                          

Основное отличие здесь заключается в том, что лямбда-выражению не обязательно нужно выделять новый экземпляр для IntegerMath, и оно может возвращать один и тот же экземпляр каждый раз при запуске этого кода. [62] Кроме того, по крайней мере в реализации OpenJDK , лямбды компилируются для вызова динамических инструкций, при этом тело лямбды вставляется как статический метод в окружающий класс, [63] вместо того, чтобы полностью генерировать новый файл класса.

Ограничения Java

Лямбды Java 8 имеют следующие ограничения:

JavaScript

JavaScript / ECMAScript поддерживает анонимные функции.

предупреждение (( функция ( x ) { return x * x ; }) ( 10 ));    

ES6 поддерживает синтаксис «стрелочной функции», где символ => отделяет список параметров анонимной функции от тела:

оповещение (( x => x * x )( 10 ));    

Эта конструкция часто используется в Букмарклетах . Например, чтобы изменить заголовок текущего документа (видимый в строке заголовка его окна ) на его URL-адрес , может показаться, что работает следующий букмарклет.

документ . заголовок = местоположение . href ;

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

Вместо этого можно использовать анонимную функцию, которая не возвращает значение:

( функция () { document . title = location . href ;})();

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

вар f = функция () { документ . заголовок = местоположение . href ;}; е ();    

Используйте void() , чтобы избежать появления новых страниц для произвольных анонимных функций:

void ( function () { return document . title = location . href ;}()); 

или просто:

void ( document.title = location.href ) ; _ _ _

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

( функция (){ ... }())  

и

( функция (){ ... })()  

Представляя " function(){ ... }" by f, формы конструкций представляют собой скобки внутри скобок (f())и скобки , применяемые к скобкам (f)().

Обратите внимание на общую синтаксическую неоднозначность выражения в скобках, аргументов функции в скобках и круглых скобок вокруг формальных параметров в определении функции. В частности, JavaScript определяет ,оператор (запятая) в контексте выражения в скобках. То, что синтаксические формы выражения и аргументов функции совпадают (без учета синтаксиса формальных параметров функции) – не простое совпадение! Если f. не идентифицирован в приведенных выше конструкциях, они становятся (())и ()(). Первый не дает синтаксического намека на какую-либо резидентную функцию, но второй ДОЛЖЕН оценить первую скобку как функцию, чтобы быть законным JavaScript. (Кроме того: например, это ()может быть ([],{},42,"abc",function(){}), если выражение оценивается как функция.)

Кроме того, функция является экземпляром объекта (аналогично объекты являются экземплярами функции), а скобки обозначения литерала объекта {}для заключенного в скобки кода используются при таком определении функции (в отличие от использования new Function(...)). В очень широком, нестрогом смысле (особенно учитывая, что глобальные привязки скомпрометированы), произвольную последовательность заключенных в скобки операторов JavaScript {stuff}можно рассматривать как фиксированную точку

( функция (){( функция (){( ... {( функция (){ материал }() )} ... )}() )}() )         

Правильнее, но с оговорками,

( функция () { материал }() ) ~= A_Fixed_Point_of ( функция () { функция возврата () { возврат ... { функция возврата () { материал }() } ... }() }() )                 

Обратите внимание на значение анонимной функции в следующих фрагментах JavaScript:

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

Юлия

В Julia анонимные функции определяются с использованием синтаксиса (arguments)->(expression):

Юлия> ж = х -> х * х ; ж ( 8 ) 64 Юлия> (( x , y ) -> x + y )( 5 , 6 ) 11       

Котлин

Kotlin поддерживает анонимные функции с синтаксисом {arguments -> expression},

val sum = { x : Int , y : Int -> x + y } sum ( 5 , 6 ) // возвращает 11 val Even = { x : Int -> x % 2 == 0 } Even ( 4 ) // возвращает истинный                     

Лисп

Lisp и Scheme поддерживают анонимные функции с использованием конструкции «лямбда», которая является ссылкой на лямбда-исчисление . Clojure поддерживает анонимные функции со специальной формой «fn» и синтаксисом чтения #().

( лямбда ( аргумент ) ( * аргумент аргумент ))    

Общий Лисп

В Common Lisp есть концепция лямбда-выражений. Лямбда-выражение записывается в виде списка с символом «лямбда» в качестве первого элемента. Затем список содержит список аргументов, документацию или объявления и тело функции. Лямбда-выражения можно использовать внутри лямбда-форм и со специальным оператором «функция».

( функция ( лямбда ( arg ) ( сделать что-нибудь arg )))    

«функция» может быть сокращена до #'. Кроме того, существует лямбда -макрос , который расширяется до функциональной формы:

; использование резкой кавычки #' ( лямбда ( arg ) ( сделай что-нибудь arg )) ; используя лямбда-макрос: ( лямбда ( arg ) ( сделать что-нибудь arg ))      

Одним из типичных применений анонимных функций в Common Lisp является передача их функциям более высокого порядка, таким как Mapcar , который применяет функцию к каждому элементу списка и возвращает список результатов.

( mapcar #' ( лямбда ( x ) ( * x x )) ' ( 1 2 3 4 ) ) ; -> (1 4 9 16)         

Лямбда -форма в Common Lisp позволяет записать лямбда-выражение при вызове функции:

(( лямбда ( x y ) ( + ( sqrt x ) ( sqrt y ))) 10,0 12,0 )         

Анонимным функциям в Common Lisp позже можно будет дать глобальные имена:

( setf ( символ-функция 'sqr ) ( лямбда ( x ) ( * x x ))) ; что позволяет нам вызывать его, используя имя SQR: ( sqr 10.0 )        

Схема

Именованные функции Scheme — это просто синтаксический сахар для анонимных функций, привязанных к именам:

( определить ( какое-то имя arg ) ( сделать что-нибудь arg ))    

расширяется (и эквивалентно) до

( определить какое-нибудь имя ( лямбда ( arg ) ( сделать что-нибудь arg )))     

Кложур

Clojure поддерживает анонимные функции через специальную форму «fn»:

( фн [х] ( + х 3 ))    

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

#( + % %2%3 ) ; Определяет анонимную функцию, которая принимает три аргумента и суммирует их.   

Как и Scheme, «именованные функции» Clojure — это просто синтаксический сахар для лямбда-выражений, привязанных к именам:

( defn func [arg] ( + 3 arg ))     

расширяется до:

( def func ( fn [arg] ( + 3 arg )))      

Луа

В Lua (как и в Scheme) все функции анонимны. Именованная функция в Lua — это просто переменная, содержащая ссылку на объект функции. [64]

Таким образом, в Луа

функция  foo ( x )  возвращает  2 * x  конец

это просто синтаксический сахар для

foo  =  функция ( x )  возвращает  2 * x  конец

Пример использования анонимных функций для сортировки в обратном порядке:

table.sort ( сеть ,  функция ( a , b )  возвращает  a . name  >  b . name end )

Язык Wolfram, Mathematica

Wolfram Language — это язык программирования Mathematica . Анонимные функции важны при программировании последних. Есть несколько способов их создания. Ниже приведены несколько анонимных функций, которые увеличивают число. Первый является наиболее распространенным. #1ссылается на первый аргумент и &отмечает конец анонимной функции.

 #1 + 1 & Функция [ x , x + 1 ] x \ [ Функция ] x + 1    

Так, например:

 ж := #1 ^ 2 & ; ж [ 8 ] 64 #1 + #2 и [ 5 , 6 ] 11    

Кроме того, в Mathematica есть добавленная конструкция для создания рекурсивных анонимных функций. Символ «#0» относится ко всей функции. Следующая функция вычисляет факториал входных данных:

 Если [ #1 == 1 , 1 , #1 * #0 [ #1 -1 ]] &      

Например, 6-факториал будет выглядеть так:

 Если [ #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 ) % Работает только в октаве ans = 11          

Максима

В Maxima анонимные функции определяются с использованием синтаксиса lambda(argument-list,expression):

f : лямбда ([ x ], x * x ); ж ( 8 );   64лямбда ([ x , y ], x + y )( 5 , 6 ); 11

МЛ

Различные диалекты ML поддерживают анонимные функции.

OCaml

Анонимные функции в OCaml — это функции без объявленного имени. Вот пример анонимной функции, которая умножает свои входные данные на два:

весело  х  ->  х * 2

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

Ф#

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

( весело x -> x * x ) 20 // 400       

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

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

fn arg => arg * arg

Ним

Nim поддерживает многострочные анонимные функции с несколькими выражениями. [33]

var anon = proc ( var1 , var2 : int ): int = var1 + var2 утверждать anon ( 1 , 2 ) == 3               

Многострочный пример:

var anon = func ( x : int ): bool = if x > 0 : result = true else : result = false                   утверждать анон ( 9 ) 

Анонимные функции могут передаваться в качестве входных параметров других функций:

var города = @[ "Франкфурт" , "Токио" , "Нью-Йорк" ]     города . сортировка ( proc ( x , y : строка ): int = cmp ( x . len , y . len ) )        

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

Перл

Перл 5

Perl 5 поддерживает анонимные функции [37] следующим образом:

( sub { print "Мне позвонили\n" }) -> (); # 1. полностью анонимный, вызывается по мере создания     мой $squarer = sub { мой $x = сдвиг ; * }; # 2. присвоено переменной             суб карри { my ( $sub , @args ) = @_ ; return sub { $sub -> ( @args , @_ ) }; # 3. как возвращаемое значение другой функции }              # пример каррирования в программировании на Perl sub sum { my $tot = 0 ; $tot += $_ для @_ ; $tot } # возвращает сумму своих аргументов my $curried = curry \& sum , 5 , 7 , 9 ; напечатайте $curried -> ( 1 , 2 , 3 ), "\n" ; # печатает 27 (= 5 + 7 + 9 + 1 + 2 + 3)                        

Другие конструкции принимают в качестве аргументов голые блоки , которые выполняют функцию, аналогичную лямбда-функциям с одним параметром, но не имеют того же соглашения о передаче параметров, что и функции — @_ не установлен.

мои @squares = map { $_ * $_ } 1 .. 10 ; # карты и grep не используют ключевое слово sub my @square2 = map $_ * $_ , 1 .. 10 ; # скобки не нужны для одного выражения                  мой @bad_example = карта { печать для @_ } 1 .. 10 ; # значения не передаются, как обычная функция Perl          

PHP

До версии 4.0.1 в PHP не было поддержки анонимных функций. [66]

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;" ); эхо  $foo ( 10 );

Список аргументов и тело функции должны быть заключены в одинарные кавычки или знаки доллара должны быть экранированы. В противном случае PHP предполагает, что " $x" означает переменную $x, и подставит ее в строку (несмотря на то, что она, возможно, не существует) вместо того, чтобы оставить " $x" в строке. Для функций с кавычками или функций с большим количеством переменных может оказаться довольно утомительным проверять, соответствует ли тело предполагаемой функции тому, что интерпретирует PHP.

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

PHP 5.3

В PHP 5.3 добавлен новый класс Closureи магический метод __invoke(), который делает экземпляр класса вызываемым. [67]

 =  3 ; $func  =  функция ( $z )  {  возвращение  $z  *  2 ;  }; эхо  $func ( $x );  // печатает 6

В этом примере $funcявляется экземпляром Closureи echo $func($x)эквивалентен echo $func->__invoke($x). PHP 5.3 имитирует анонимные функции, но не поддерживает настоящие анонимные функции, поскольку функции PHP по-прежнему не являются объектами первого класса.

PHP 5.3 поддерживает замыкания, но переменные должны быть явно указаны как таковые:

 =  3 ; $func  =  function ()  use ( & $x )  {  $x  *=  2 ;  }; $функ (); эхо  ;  // печатает 6

Переменная $xсвязана по ссылке, поэтому вызов $funcизменяет ее, и изменения видны вне функции.

PHP 7.4

Функции стрелок были представлены в PHP 7.4.

 =  3 ; $func  =  fn ( $z )  =>  $z  *  2 ; эхо  $func ( $x );  // печатает 6

Диалекты Пролога

Логток

Logtalk использует следующий синтаксис для анонимных предикатов (лямбда-выражений):

{ FreeVar1 , FreeVar2 , ... } / [ LambdaParameter1 , LambdaParameter2 , ...] >> Цель

Простой пример без свободных переменных и с использованием предиката сопоставления списка:

| ?- мета :: map([ X , Y ] >> ( Y  равно  2 * X ), [ 1 , 2 , 3 ], Ys ). Ys  = [ 2 , 4 , 6 ]да

Также поддерживается каррирование. Приведенный выше пример можно записать так:

| ?- мета :: map([ X ] >> ([ Y ] >> ( Y  равно  2 * X )), [ 1 , 2 , 3 ], Ys ). Ys  = [ 2 , 4 , 6 ]да

Визуальный Пролог

Анонимные функции (в общем анонимные предикаты ) были введены в Visual Prolog в версии 7.2. [68] Анонимные предикаты могут захватывать значения из контекста. Если он создан в члене объекта, он также может получить доступ к состоянию объекта (путем захвата This).

mkAdderвозвращает анонимную функцию, которая захватила аргумент Xв замыкании. Возвращаемая функция — это функция, которая добавляет Xк своему аргументу:

предложения  mkAdder ( X )  =  {  ( Y )  =  X + Y  }.

Питон

Python поддерживает простые анонимные функции через лямбда-форму. [39] Исполняемое тело лямбды должно быть выражением и не может быть оператором, что является ограничением, ограничивающим его полезность. Значение, возвращаемое лямбда-выражением, является значением содержащегося выражения. Лямбда-формы можно использовать везде, где можно использовать обычные функции. Однако эти ограничения делают его очень ограниченной версией обычной функции. Вот пример:

>>> foo  =  лямбда  x :  x  *  x >>> foo ( 10 ) 100

В целом, соглашение Python поощряет использование именованных функций, определенных в той же области, что и анонимные функции в других языках. Это приемлемо, поскольку локально определенные функции реализуют всю мощь замыканий и почти так же эффективны, как использование лямбда-выражений в Python. В этом примере можно сказать, что встроенная степенная функция была каррирована :

>>> def  make_pow ( n ): ...  def  фиксированная_экспонента_pow ( x ): ...  return  pow ( x ,  n ) ...  return  фиксированная_экспонента_pow ... >>> sqr  =  make_pow ( 2 ) >>> sqr ( 10 ) 100 >>> куб  =  make_pow ( 3 ) >>> куб ( 10 ) 1000

р

В R анонимные функции определяются с использованием синтаксиса function(argument-list)expression, который с версии 4.1.0 имеет сокращение \, похожее на Haskell.

> f <- функция ( x ) x * x ; f ( 8 ) [1] 64 > ( функция ( x , y ) x + y )( 5 , 6 ) [1] 11 > # Поскольку R 4.1.0 > ( \ ( x , y ) x + y )( 5 , 6 ) [1] 11     

Раку

В Raku все блоки (даже связанные с if, while и т.п.) являются анонимными функциями. Блок, который не используется в качестве значения r , выполняется немедленно.

  1. полностью анонимный, называется как созданный
    { сказать  «Мне позвонили» };
  2. присвоено переменной
    мой  $squarer1 = -> $x { $x * $x }; № 2а. заостренный блок my  $squarer2 = { $^x * $^x }; № 2б. twigil my  $squarer3 = { my  $x = сдвиг  @_ ;  *  }; № 2в. Стиль Перл 5
  3. карри
    sub  add ( $m , $n ) { $m + $n } my  $seven = add ( 3 , 4 ); мой  $add_one = &add . предполагая ( m => 1); мой $eight =  $add_one ( $seven );
  4. Объект WhatWordCode
    мой  $w = * - 1 ; # Объект WhatCode my  $b = { $_ - 1 }; # та же функциональность, но как блок Callable

Рубин

Ruby поддерживает анонимные функции, используя синтаксическую структуру, называемую блоком . В Ruby существует два типа данных для блоков. Procs ведут себя аналогично замыканиям , тогда как lambdas ведут себя более аналогично анонимной функции. [42] При передаче методу блок в некоторых случаях преобразуется в Proc.

# Пример 1: # Чисто анонимные функции, использующие блоки. бывший = [ 16 . 2 , 24 . 1 , 48 . 3 , 32 . 4 , 8 . 5 ] => [ 16 . 2 , 24 . 1 , 48 . 3 , 32 . 4 , 8 . 5 ] пр . сортировка_по { | х | х - х . to_i } # Сортировка по дробной части, игнорируя целую часть. => [ 24 . 1 , 16 . 2 , 48 . 3 , 32 . 4 , 8 . 5 ]                       # Пример 2: # Функции первого класса как явный объект Proc - ex = Proc . new { помещает "Привет, мир!" } => #<Proc:0x007ff4598705a0@(irb):7> ex . звонок Привет , мир! => ноль         # Пример 3: # Функция, которая возвращает объект лямбда-функции с параметрами def Multiple_of? ( п ) лямбда { | х | x % n == 0 } end => ноль Multiple_four = Multiple_of? ( 4 ) => #<Proc:0x007ff458b45f88@(irb):12 (лямбда)> Multiple_four . вызов ( 16 ) => true Multiple_four [ 15 ] => false             

Ржавчина

В Rust анонимные функции называются замыканиями. [69] Они определяются с использованием следующего синтаксиса:

|< параметр - имя > : < тип >|  -> < возврат - тип > { < тело > };   

Например:

пусть ж = | х : i32 | -> i32 { х * 2 };         

Однако с помощью вывода типа компилятор может определить тип каждого параметра и тип возвращаемого значения, поэтому приведенную выше форму можно записать как:

пусть ж = | х | { х * 2 };        

При замыканиях с одним выражением (т. е. телом с одной строкой) и неявным возвращаемым типом фигурные скобки можно опустить:

пусть ж = | х | х * 2 ;      

Замыкания без входного параметра записываются так:

пусть f = || распечататьлн! ( "Привет, мир!" );    

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

// Функция, которая принимает указатель функции в качестве аргумента и вызывает ее // со значением `5`. fn  apply ( f : fn ( i32 )  -> i32 )  -> i32  { // Нет точки с запятой, чтобы указать неявный возврат f ( 5 ) }  fn  main () { // Определение замыкания let f = | х | х * 2 ;          распечататьлн! ( "{}" , применить ( f )); // 10 println! ( "{}" , f ( 5 )); // 10 }     

Однако для описания того, как фиксируются значения в теле замыкания, могут потребоваться сложные правила. Они реализованы с использованием черт Fn, FnMutи FnOnce: [70]

Благодаря этим особенностям компилятор будет захватывать переменные наименее ограничительным образом. [70] Они помогают управлять тем, как значения перемещаются между областями действия, что очень важно, поскольку Rust следует конструкции жизненного цикла, чтобы гарантировать, что значения «заимствованы» и перемещены предсказуемым и явным образом. [71]

Ниже показано, как можно передать замыкание в качестве входного параметра, используя этот Fnпризнак:

// Функция, которая принимает значение типа F (который определяется как // универсальный тип, реализующий признак `Fn`, например замыкание) // и вызывает его со значением `5`. fn  apply_by_ref < F > ( f : F )  -> i32  где F : Fn ( i32 ) -> i32 { f ( 5 ) }   fn  main () { let f = | х | { печать! ( «Я получил значение: {}» , x ); х * 2 }; // Применяет функцию перед печатью возвращаемого значения println! ( "5 * 2 = {}" , apply_by_ref ( f )); }                // ~~ Вывод программы ~~ // Я получил значение: 5 // 5 * 2 = 10

Предыдущее определение функции также можно для удобства сократить следующим образом:

fn  apply_by_ref ( f : impl Fn ( i32 ) -> i32 ) -> i32 { f ( 5 ) }     

Скала

В Scala анонимные функции используют следующий синтаксис: [72]

( x : Int , y : Int ) => x + y       

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

список значений = Список ( 1 , 2 , 3 , 4 ) список . уменьшитьLeft ( ( x , y ) => x + y ) // Здесь компилятор может сделать вывод, что оба типа x и y — Int. // Таким образом, аннотации типов для параметров анонимной функции не требуются.              список . уменьшитьLeft ( _ + _ ) // Каждое подчеркивание обозначает новый безымянный параметр в анонимной функции. // Это приводит к еще более короткому эквиваленту анонимной функции, указанной выше.     

Болтовня

В Smalltalk анонимные функции называются блоками и вызываются (вызываются) путем отправки им сообщения «значение». Если необходимо передать несколько аргументов, необходимо использовать сообщение «value:...value:» с соответствующим количеством аргументов-значений.

Например, в GNU Smalltalk

ст >  ж := [ : х | х * х ] . значение  f  :  8  . 64 ст> [ : x  : y | x + y ] значение:  5  значение:  6  . 11

Блоки Smalltalk технически являются замыканиями, что позволяет им выйти за рамки своей определяющей области и по-прежнему ссылаться на объявленные в них переменные.

ст >  ж  := [ : а | [ : н | a + n ]] значение:  100  . BlockClosure  «возвращает внутренний блок, который добавляет 100 (захваченных в переменной « a » ) к своему аргументу». значение st> f : 1 . 101 ст> значение f : 2 . 102        

Быстрый

В Swift анонимные функции называются замыканиями. [46] Синтаксис имеет следующий вид:

{ ( параметры ) -> returnType в операторе }     

Например:

{ ( s1 : String , s2 : String ) -> Bool в ответ s1 > s2 }           

Для краткости и выразительности типы параметров и тип возвращаемого значения можно опустить, если их можно вывести:

{ s1 , s2 взамен s1 > s2 } _        

Аналогичным образом, Swift также поддерживает неявные операторы возврата для замыканий с одним оператором:

{ s1 , s2 в s1 > s2 }       

Наконец, имена параметров также можно опустить; если они опущены, ссылки на параметры используются с использованием сокращенных имен аргументов, состоящих из символа $, за которым следует их позиция (например, $0, $1, $2 и т. д.):

{ $0 > $1 }    

Ткл

В Tcl применение анонимной функции возведения в квадрат к 2 выглядит следующим образом: [73]

apply { x {expr { $x * $x }}} 2 # возвращает 4    

В этом примере участвуют два кандидата на роль функции в Tcl. Самый общий вариант обычно называется префиксом команды , и если переменная f содержит такую ​​функцию, то способ выполнения приложения функции f ( x ) будет следующим:

{ * } $f $x 

где {*}находится префикс расширения (новое в Tcl 8.5). Префикс команды в приведенном выше примере — apply. {x {expr {$x*$x}}}Имена команд можно привязать к префиксам команд с помощью команды interp alias. Префиксы команд поддерживают каррирование . Префиксы команд очень распространены в API Tcl .

Другой кандидат на роль «функции» в Tcl обычно называется лямбда и появляется как {x {expr {$x*$x}}}часть приведенного выше примера. Это та часть, которая кэширует скомпилированную форму анонимной функции, но ее можно вызвать только путем передачи команде apply. Лямбды не поддерживают каррирование, если только они не объединены с applyпрефиксом команды. Лямбды редко встречаются в API Tcl.

Вала

В Vala анонимные функции поддерживаются как лямбда-выражения. [74]

делегат int IntOp ( int x , int y );      void main () { IntOp foo = ( x , y ) => x * y ; стандартный вывод . printf ( "%d \n " , foo ( 10 , 5 )); }            

Визуальный Бейсик .NET

Visual Basic .NET 2008 представил анонимные функции через лямбда-форму. В сочетании с неявной типизацией VB обеспечивает экономичный синтаксис для анонимных функций. Как и в Python, в VB.NET анонимные функции должны быть определены в одной строке; они не могут быть составными утверждениями. Более того, анонимная функция в VB.NET действительно должна быть VB.NET Function— она должна возвращать значение.

Dim foo = Функция ( x ) x * x Консоль . WriteLine ( фу ( 10 ))      

В Visual Basic.NET 2010 добавлена ​​поддержка многострочных лямбда-выражений и анонимных функций без возвращаемого значения. Например, функция для использования в потоке.

Dim t As New System . Резьба . Thread ( Sub () For n As Integer = от 0 до 10 'Считаем до 10 Console.WriteLine ( n ) ' Распечатываем каждое число Next End Sub ) t . Начинать ()                    

Смотрите также

Рекомендации

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

Внешние ссылки