Funkcja anonimowa - Anonymous function

W programowaniu komputerowym , w anonimowej funkcji ( funkcja dosłownym , lambda abstrakcji , funkcja lambda , wyrażenie lambda lub bloku ) jest funkcja definicja, która nie jest związana do identyfikatora . Funkcje anonimowe to często argumenty przekazywane do funkcji wyższego rzędu lub używane do konstruowania wyniku funkcji wyższego rzędu, która musi zwrócić funkcję. Jeśli funkcja jest używana tylko raz lub ograniczoną liczbę razy, funkcja anonimowa może być składniowo lżejsza niż użycie funkcji nazwanej. Funkcje anonimowe są wszechobecne w funkcjonalnych językach programowania i innych językach z funkcjami pierwszej klasy , w których pełnią taką samą rolę dla typu funkcji jak literały dla innych typów danych .

Funkcje anonimowe pochodzą w pracach Alonzo Church w jego wynalezienie rachunku lambda , w którym wszystkie funkcje są anonimowe, w 1936 roku, przed komputerami elektronicznych. W kilku językach programowania funkcje anonimowe są wprowadzane za pomocą słowa kluczowego lambda , a funkcje anonimowe są często określane jako lambda lub abstrakcje lambda. Funkcje anonimowe są cechą języków programowania od Lisp w 1958 roku, a rosnąca liczba nowoczesnych języków programowania obsługuje funkcje anonimowe.

Nazwy

Nazwy „abstrakcja lambda”, „funkcja lambda” i „wyrażenie lambda” odnoszą się do zapisu abstrakcji funkcji w rachunku lambda, gdzie zwykła funkcja f ( x ) = M zostałaby zapisana x .  M ) ( M to wyrażenie, które używa x ). Porównaj ze składnią Pythona . lambda x: M

Nazwa „funkcja strzałki” odnosi się do matematycznego symbolu „ odwzorowuje na ”, xM . Porównaj ze składnią JavaScript . x => M

Zastosowania

Funkcje anonimowe mogą być używane do przechowywania funkcji, które nie muszą być nazwane i prawdopodobnie do krótkotrwałego użytku. Niektóre godne uwagi przykłady to zamknięcia i curry .

Użycie funkcji anonimowych to kwestia stylu. Korzystanie z nich nigdy nie jest jedynym sposobem rozwiązania problemu; każda funkcja anonimowa może być zamiast tego zdefiniowana jako nazwana funkcja i wywoływana według nazwy. Niektórzy programiści używają anonimowych funkcji do enkapsulacji określonego, jednorazowego kodu bez zaśmiecania kodu wieloma małymi, jednowierszowymi normalnymi funkcjami.

W niektórych językach programowania funkcje anonimowe są zwykle implementowane do bardzo konkretnych celów, takich jak wiązanie zdarzeń z wywołaniami zwrotnymi lub tworzenie instancji funkcji dla określonych wartości, co może być bardziej wydajne, bardziej czytelne i mniej podatne na błędy niż wywoływanie bardziej ogólnej nazwanej funkcji .

Poniższe przykłady zostały napisane w Pythonie 3.

Sortowanie

Podczas próby sortowania w niestandardowy sposób może być łatwiej zawrzeć logikę sortowania jako funkcję anonimową zamiast tworzyć nazwaną funkcję. Większość języków udostępnia ogólną funkcję sortowania, która implementuje algorytm sortowania, który sortuje dowolne obiekty. Ta funkcja zwykle akceptuje dowolną funkcję, która określa sposób porównywania, czy dwa elementy są równe lub czy jeden jest większy lub mniejszy od drugiego.

Rozważmy poniższy kod Pythona sortujący listę ciągów znaków według długości ciągu:

>>> a = ['house', 'car', 'bike']
>>> a.sort(key=lambda x: len(x))
>>> a
['car', 'bike', 'house']

Funkcja anonimowa w tym przykładzie to wyrażenie lambda:

lambda x: len(x)

Funkcja anonimowa przyjmuje jeden argument xi zwraca długość swojego argumentu, który jest następnie używany przez sort()metodę jako kryterium sortowania.

Podstawowa składnia funkcji lambda w Pythonie to

lambda arg1, arg2, arg3, ...: <operation on the arguments returning a value>

Wyrażenie zwracane przez funkcję lambda można przypisać do zmiennej i używać w kodzie w wielu miejscach.

>>> add = lambda a: a + a
>>> add(20)
40

Innym przykładem może być sortowanie pozycji na liście według nazwy ich klasy (w Pythonie wszystko ma klasę):

>>> a = [10, 'number', 11.2]
>>> a.sort(key=lambda x: x.__class__.__name__)
>>> a
[11.2, 10, 'number']

Zauważ, że 11.2ma nazwę klasy „ float”, 10ma nazwę klasy „ int” i 'number'ma nazwę klasy „ str”. Posortowana kolejność to „ float”, „ int”, a następnie „ str”.

Domknięcia

Zamknięcia to funkcje oceniane w środowisku zawierającym powiązane zmienne . Poniższy przykład wiąże zmienną "próg" w funkcji anonimowej, która porównuje dane wejściowe z progiem.

def comp(threshold):
    return lambda x: x < threshold

Może to być używane jako rodzaj generatora funkcji porównawczych:

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

Tworzenie funkcji dla każdej możliwej funkcji porównania byłoby niepraktyczne i może być zbyt niewygodne, aby utrzymać próg do dalszego użytku. Bez względu na powód, dla którego używane jest zamknięcie, funkcja anonimowa to jednostka zawierająca funkcję porównującą.

Curry

Currying to proces zmiany funkcji, tak aby zamiast przyjmować wiele danych wejściowych, pobierała jedno dane wejściowe i zwracała funkcję, która akceptuje drugie dane wejściowe i tak dalej. W tym przykładzie funkcja wykonująca dzielenie przez dowolną liczbę całkowitą jest przekształcana w taką, która wykonuje dzielenie przez określoną liczbę całkowitą.

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

Chociaż korzystanie z funkcji anonimowych może nie jest powszechne w currying, nadal można z nich korzystać. W powyższym przykładzie dzielnik funkcji generuje funkcje z określonym dzielnikiem. Funkcje połowa i trzecia tworzą funkcję dzielenia ze stałym dzielnikiem.

Funkcja dzielnika również tworzy zamknięcie, wiążąc zmienną d.

Funkcje wyższego rzędu

Funkcja wyższego rzędu to funkcja, która przyjmuje funkcję jako argument. Jest to powszechnie używane do dostosowywania zachowania ogólnie zdefiniowanej funkcji, często konstrukcji pętli lub schematu rekurencji. Funkcje anonimowe są wygodnym sposobem określania takich argumentów funkcji. Poniższe przykłady są w Pythonie 3.

Mapa

Funkcja map wykonuje wywołanie funkcji na każdym elemencie listy. Poniższy przykład powoduje kwadratury każdego elementu w tablicy za pomocą funkcji anonimowej.

>>> a = [1, 2, 3, 4, 5, 6]
>>> list(map(lambda x: x*x, a))
[1, 4, 9, 16, 25, 36]

Funkcja anonimowa przyjmuje argument i samodzielnie go mnoży (podnosi do kwadratu). Powyższa forma jest odradzana przez twórców języka, którzy utrzymują, że przedstawiona poniżej forma ma to samo znaczenie i jest bardziej zgodna z filozofią języka:

>>> a = [1, 2, 3, 4, 5, 6]
>>> [x*x for x in a]
[1, 4, 9, 16, 25, 36]

Filtr

Funkcja filtru zwraca wszystkie elementy z listy, która po przekazaniu do określonej funkcji oblicza True.

>>> a = [1, 2, 3, 4, 5, 6]
>>> list(filter(lambda x: x % 2 == 0, a))
[2, 4, 6]

Funkcja anonimowa sprawdza, czy przekazany do niej argument jest parzysty. To samo, co w przypadku poniższego formularza mapy, jest uważane za bardziej odpowiednie:

>>> a = [1, 2, 3, 4, 5, 6]
>>> [x for x in a if x % 2 == 0]
[2, 4, 6]

Zginać

Funkcja fold działa przez wszystkie elementy w strukturze (w przypadku list zwykle od lewej do prawej, „zgięcie w lewo”, nazywane reducew Pythonie), gromadząc wartość w trakcie. Można to wykorzystać do połączenia wszystkich elementów konstrukcji w jedną wartość, na przykład:

>>> from functools import reduce
>>> a = [1, 2, 3, 4, 5]
>>> reduce(lambda x,y: x*y, a)
120

To wykonuje

Funkcja anonimowa jest tutaj mnożeniem dwóch argumentów.

Wynik fałdu nie musi być jedną wartością. Zamiast tego zarówno mapę, jak i filtr można utworzyć za pomocą fold. W map wartością, która jest skumulowana, jest nowa lista zawierająca wyniki zastosowania funkcji do każdego elementu oryginalnej listy. W filtrze skumulowana wartość to nowa lista zawierająca tylko te elementy, które spełniają dany warunek.

Lista języków

Poniżej znajduje się lista języków programowania, które w pełni lub częściowo obsługują nienazwane funkcje anonimowe jako pewien wariant lub wcale.

Ta tabela przedstawia kilka ogólnych trendów. Po pierwsze, języki, które nie obsługują funkcji anonimowych ( C , Pascal , Object Pascal ) to wszystkie języki z typami statycznymi. Jednak języki o typie statycznym mogą obsługiwać funkcje anonimowe. Na przykład języki ML są typowane statycznie i zasadniczo zawierają funkcje anonimowe, a Delphi , dialekt Object Pascal , został rozszerzony o obsługę funkcji anonimowych, podobnie jak C++ (według standardu C++11 ). Po drugie, języki, które traktują funkcje jako funkcje pierwszej klasy ( Dylan , Haskell , JavaScript , Lisp , ML , Perl , Python , Ruby , Scheme ) generalnie obsługują funkcje anonimowe, dzięki czemu funkcje mogą być definiowane i przekazywane równie łatwo jak inne dane typy.

Lista języków
Język Wsparcie Uwagi
ActionScript Zielony kleszczTak
Ada Czerwony Xn Funkcje wyrażeń są częścią Ada2012
ALGOL 68 Zielony kleszczTak
APL Zielony kleszczTak Dyalog, ngn i dzaima APL w pełni obsługują zarówno funkcje dfns, jak i milczące. GNU APL ma dość ograniczone wsparcie dla dfns.
Języki asemblera Czerwony Xn
Grzmotnąć Zielony kleszczTak Stworzono bibliotekę do obsługi anonimowych funkcji w Bash.
C Czerwony Xn Wsparcie jest dostarczane w Clang i wraz z biblioteką kompilatora-rt LLVM . Wsparcie GCC jest podane dla implementacji makr, która daje możliwość użycia. Zobacz poniżej więcej szczegółów.
C# Zielony kleszczTak
C++ Zielony kleszczTak Od standardu C++11
CFML Zielony kleszczTak Od Railo 4, ColdFusion 10
Clojure Zielony kleszczTak
COBOL Czerwony Xn Niestandardowy zarządzany dialekt COBOL w Micro Focus obsługuje wyrażenia lambda, które są nazywane anonimowymi delegatami/metodami.
Kędzior Zielony kleszczTak
D Zielony kleszczTak
Strzałka Zielony kleszczTak
Delfy Zielony kleszczTak
Dylan Zielony kleszczTak
Eiffla Zielony kleszczTak
Wiąz Zielony kleszczTak
Eliksir Zielony kleszczTak
Erlang Zielony kleszczTak
F# Zielony kleszczTak
Przewyższać Zielony kleszczTak Funkcja arkusza Excel, wersja beta 2021
Czynnik Zielony kleszczTak „Cytaty” to wspierają
Fortran Czerwony Xn
Frink Zielony kleszczTak
Udać się Zielony kleszczTak
Gosu Zielony kleszczTak
Groovy Zielony kleszczTak
Haskell Zielony kleszczTak
Haxe Zielony kleszczTak
Jawa Zielony kleszczTak Obsługiwane w Javie 8 . Szczegółowe informacje można znaleźć w poniższej sekcji Ograniczenia dotyczące języka Java .
JavaScript Zielony kleszczTak
Julia Zielony kleszczTak
Kotlin Zielony kleszczTak
Seplenienie Zielony kleszczTak
Logtalk Zielony kleszczTak
Lua Zielony kleszczTak
ŚWINKA Czerwony Xn
Matematyka Zielony kleszczTak
Klon Zielony kleszczTak
MATLAB Zielony kleszczTak
Maxima Zielony kleszczTak
Powłoka nowej generacji Zielony kleszczTak
Nimi Zielony kleszczTak
OCaml Zielony kleszczTak
Oktawa Zielony kleszczTak
Obiekt Pascal Zielony kleszczTak Delphi, dialekt Object Pascal, obsługuje funkcje anonimowe (formalnie, anonimowe metody ) natywnie od Delphi 2009. Dialekt Oxygene Object Pascal również je obsługuje.
Cel-C (Mac OS X 10.6+) Zielony kleszczTak Nazywane bloki ; oprócz Objective-C, bloki mogą być również używane w C i C++ podczas programowania na platformie Apple.
OpenSCAD Zielony kleszczTak Obsługa literału funkcji została wprowadzona w wersji 2021.01.
Pascal Czerwony Xn
Perl Zielony kleszczTak
PHP Zielony kleszczTak Od PHP 5.3.0 obsługiwane są prawdziwe funkcje anonimowe. Wcześniej obsługiwane były tylko częściowe funkcje anonimowe, które działały podobnie jak implementacja C#.
PL/I Czerwony Xn
Pyton Zielony kleszczTak Python obsługuje funkcje anonimowe za pomocą składni lambda, która obsługuje tylko wyrażenia, a nie instrukcje.
r Zielony kleszczTak
Rakieta Zielony kleszczTak
Raku Zielony kleszczTak
Rexx Czerwony Xn
RPG Czerwony Xn
Rubin Zielony kleszczTak Anonimowe funkcje Rubiego, odziedziczone po Smalltalk , nazywane są blokami .
Rdza Zielony kleszczTak
Scala Zielony kleszczTak
Schemat Zielony kleszczTak
Pogawędka Zielony kleszczTak Anonimowe funkcje Smalltalka nazywane są blokami .
Standardowy ML Zielony kleszczTak
Szybki Zielony kleszczTak Anonimowe funkcje Swifta nazywają się Zamknięciami.
Maszynopis Zielony kleszczTak
Tcl Zielony kleszczTak
Wala Zielony kleszczTak
Visual Basic .NET v9 Zielony kleszczTak
Wizualny Prolog v 7.2 Zielony kleszczTak
WLanguage v25 Zielony kleszczTak Język W PCSoft używany przez pakiet WinDev/WebDev/WinDev Mobile obsługuje anonimowe funkcje od wydania 25 (2019)
Język Wolfram Zielony kleszczTak

Przykłady

Wiele języków obsługuje funkcje anonimowe lub podobne.

APL

Tylko niektóre dialekty obsługują funkcje anonimowe, jako dfns , w stylu milczącym lub w kombinacji obu.

      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 (niestandardowe rozszerzenie)

Funkcja anonimowa nie jest obsługiwana przez standardowy język programowania C, ale jest obsługiwana przez niektóre dialekty C, takie jak GCC i Clang .

GCC

GNU Compiler Collection (GCC) obsługuje funkcje anonimowe, wymieszane z funkcjami zagnieżdżonymi i wyrażeniami instrukcji. Ma postać:

( { return_type anonymous_functions_name (parameters) { function_body } anonymous_functions_name; } )

Poniższy przykład działa tylko z GCC. Ze względu na sposób rozwijania makr l_bodynie może zawierać żadnych przecinków poza nawiasami; GCC traktuje przecinek jako ogranicznik między argumentami makr. Argument l_ret_typemożna usunąć, jeśli __typeof__jest dostępny; w poniższym przykładzie użycie __typeof__on array spowoduje zwrócenie testtype *, które w razie potrzeby można wyłuskać dla rzeczywistej wartości.

#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++, cel-C, cel-C++)

Clang obsługuje funkcje anonimowe, zwane blokami , które mają postać:

^return_type ( parameters ) { function_body }

Typ powyższych bloków to return_type (^)(parameters).

Używając wspomnianego rozszerzenia bloków i Grand Central Dispatch (libdispatch), kod mógłby wyglądać prościej:

#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;
}

Kod z blokami powinien być skompilowany -fblocksi powiązany z-lBlocksRuntime

C++ (od C++11)

C++11 obsługuje funkcje anonimowe, zwane wyrażeniami lambda , które mają postać:

[capture](parameters) -> return_type { function_body }

Oto przykładowe wyrażenie lambda:

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

C++11 obsługuje również domknięcia , tutaj zwane przechwytywaniami. Przechwyty są definiowane w nawiasach kwadratowych [oraz ]w deklaracji wyrażenia lambda. Mechanizm umożliwia przechwytywanie tych zmiennych według wartości lub przez odwołanie. Poniższa tabela pokazuje to:

[]        // 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.

Zmienne przechwytywane przez wartość są domyślnie stałe. Dodanie mutablepo liście parametrów czyni je niestałymi.

Poniższe dwa przykłady demonstrują użycie wyrażenia lambda:

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

Oblicza to sumę wszystkich elementów na liście. Zmienna totaljest przechowywana jako część domknięcia funkcji lambda. Ponieważ jest to odwołanie do zmiennej stosu total, może zmienić jej wartość.

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(); });

Spowoduje to, że zostanie totalon zapisany jako odniesienie, ale valuezostanie zapisany jako kopia.

Zdobycie thisjest wyjątkowe. Może być uchwycony tylko przez wartość, a nie przez odniesienie. thismożna przechwycić tylko wtedy, gdy najbliższa otaczająca funkcja jest niestatyczną funkcją składową. Lambda będzie miała taki sam dostęp jak członek, który ją utworzył, pod względem chronionych/prywatnych członków.

Jeśli thiszostanie przechwycony, jawnie lub niejawnie, testowany jest również zakres zawartych składowych klasy. Dostęp do członków thisnie wymaga jawnego użycia this->składni.

Konkretna implementacja wewnętrzna może się różnić, ale oczekuje się, że funkcja lambda, która przechwytuje wszystko przez odwołanie, będzie przechowywać rzeczywisty wskaźnik stosu funkcji, w której jest tworzona, a nie indywidualne odwołania do zmiennych stosu. Jednak ponieważ większość funkcji lambda jest małych i ma zasięg lokalny, prawdopodobnie są kandydatami do inline , a zatem nie potrzebują dodatkowego miejsca na odwołania.

Jeśli obiekt zamknięcia zawierający odwołania do zmiennych lokalnych jest wywoływany po najbardziej wewnętrznym zakresie bloku jego utworzenia, zachowanie jest undefined .

Funkcje lambda są obiektami funkcyjnymi typu zależnego od implementacji; nazwa tego typu jest dostępna tylko dla kompilatora. Jeśli użytkownik chce przyjąć funkcję lambda jako parametr, typ parametru musi być typem szablonu lub musi utworzyć obiekt std::functionlub podobny obiekt, aby przechwycić wartość lambda. Użycie autosłowa kluczowego może pomóc w przechowywaniu funkcji lambda,

auto my_lambda_func = [&](int x) { /*...*/ };
auto my_onheap_lambda_func = new auto([=](int x) { /*...*/ });

Oto przykład przechowywania anonimowych funkcji w zmiennych, wektorach i tablicach; i przekazanie ich jako nazwanych parametrów:

#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;
}

Wyrażenie lambda z pustą specyfikacją przechwytywania ( []) można niejawnie przekonwertować na wskaźnik funkcji o tym samym typie, w którym zadeklarowano lambdę. Więc to jest legalne:

auto a_lambda_func = [](int x) { /*...*/ };
void (* func_ptr)(int) = a_lambda_func;
func_ptr(4); //calls the lambda.

Doładowania biblioteka udostępnia własną składnię funkcji lambda, a także, używając następującej składni:

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

C#

W C# pogłębiono obsługę funkcji anonimowych dzięki różnym wersjom kompilatora języka. Język v3.0, wydany w listopadzie 2007 z .NET Framework v3.5, ma pełną obsługę funkcji anonimowych. C# nazywa je wyrażeniami lambda , zgodnie z oryginalną wersją funkcji anonimowych, rachunkiem lambda .

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

Chociaż funkcja jest anonimowa, nie można jej przypisać do zmiennej wpisanej niejawnie, ponieważ składnia lambda może być używana do oznaczania funkcji anonimowej lub drzewa wyrażeń, a kompilator nie może automatycznie zdecydować o wyborze. Np. to nie działa:

// will NOT compile!
var foo = (int x) => x * x;

Jednak wyrażenie lambda może brać udział we wnioskowaniu o typie i może być użyte jako argument metody , np. do użycia funkcji anonimowych z funkcją Map dostępną za pomocą System.Collections.Generic.List(w ConvertAll()metodzie):

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

Wcześniejsze wersje C# miały bardziej ograniczoną obsługę funkcji anonimowych. Język C# v1.0, wprowadzony w lutym 2002 r. wraz z .NET Framework v1.0, zapewniał częściową obsługę funkcji anonimowych za pomocą delegatów . Ta konstrukcja jest nieco podobna do delegatów PHP. W C# 1.0 delegaci są jak wskaźniki funkcji, które odwołują się do jawnie nazwanej metody w klasie. (Ale w przeciwieństwie do PHP, nazwa nie jest potrzebna w momencie użycia delegata.) C# v2.0, wydany w listopadzie 2005 z .NET Framework v2.0, wprowadził koncepcję metod anonimowych jako sposób na pisanie nienazwanych instrukcji wbudowanych bloki, które można wykonać w wywołaniu delegata. C# 3.0 nadal obsługuje te konstrukcje, ale obsługuje również konstrukcję wyrażenia lambda.

Ten przykład zostanie skompilowany w C# 3.0 i przedstawi trzy formy:

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

W przypadku wersji C# 2.0 kompilator C# pobiera blok kodu funkcji anonimowej i tworzy statyczną funkcję prywatną. Wewnętrznie funkcja otrzymuje oczywiście wygenerowaną nazwę; ta wygenerowana nazwa jest oparta na nazwie metody, w której Delegate jest zadeklarowany. Ale nazwa nie jest uwidaczniana w kodzie aplikacji, z wyjątkiem użycia odbicia .

W przypadku wersji C# 3.0 obowiązuje ten sam mechanizm.

Język znaczników ColdFusion (CFML)

Używając funkcjonować słowo kluczowe:

fn = function(){
  // statements
};

Lub za pomocą funkcji strzałki:

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 obsługuje dowolne instrukcje w definicji funkcji, a nie tylko wyrażenia.

CFML obsługuje rekurencyjne funkcje anonimowe:

factorial = function(n){
    return n > 1 ? n * factorial(n-1) : 1;
};

Anonimowe funkcje CFML implementują zamknięcie.

D

D używa wbudowanych delegatów do implementowania funkcji anonimowych. Pełna składnia wbudowanego delegata to

return_type delegate(arguments){/*body*/}

Jeśli jest jednoznaczny, typ zwracany i delegat słowa kluczowego można pominąć.

(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

Od wersji 2.0 D alokuje domknięcia na stercie, chyba że kompilator udowodni, że nie jest to konieczne; scopekluczowe mogą być wykorzystywane do wymuszania alokacji stosu. Od wersji 2.058 można używać notacji skróconej:

x => x*x;
(int x) => x*x;
(x,y) => x*y;
(int x, int y) => x*y;

Anonimowa funkcja może być przypisana do zmiennej i używana w następujący sposób:

auto sqr = (double x){return x*x;};
double y = sqr(4);

Strzałka

Dart obsługuje funkcje anonimowe.

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

lub

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

Delfy

Delphi wprowadziło funkcje anonimowe w wersji 2009.

program demo;

type
  TSimpleProcedure = reference to procedure;
  TSimpleFunction = reference to function(const x: string): Integer;

var
  x1: TSimpleProcedure;
  y1: TSimpleFunction;

begin
  x1 := procedure
    begin
      Writeln('Hello World');
    end;
  x1;   //invoke anonymous method just defined

  y1 := function(const x: string): Integer
    begin
      Result := Length(x);
    end;
  Writeln(y1('bar')); 
end.

PascalABC.NET

PascalABC.NET obsługuje funkcje anonimowe przy użyciu składni lambda

begin
  var n := 10000000;
  var pp := Range(1,n)
    .Select(x->Rec(Random(),Random()))
    .Where(p->sqr(p.Item1)+sqr(p.Item2)<1)
    .Count/n*4;
  Print(pp);
end.

Eliksir

Elixir używa zamknięcia fn dla funkcji anonimowych.

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

Erlang używa składni dla funkcji anonimowych podobnej do składni funkcji nazwanych.

% Anonymous function bound to the Square variable
Square = fun(X) -> X * X end.

% Named function with the same functionality
square(X) -> X * X.

Udać się

Go obsługuje funkcje anonimowe.

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

Haskell

Haskell używa zwięzłej składni dla funkcji anonimowych (wyrażeń lambda). Odwrotny ukośnik ma przypominać λ.

\x -> x * x

Wyrażenia lambda są w pełni zintegrowane z silnikiem wnioskowania o typie i obsługują całą składnię i cechy „zwykłych” funkcji (z wyjątkiem użycia wielu definicji do dopasowywania wzorców, ponieważ lista argumentów jest określona tylko raz).

map (\x -> x * x) [1..5] -- returns [1, 4, 9, 16, 25]

Wszystkie poniższe są równoważne:

f x y = x + y
f x = \y -> x + y
f = \x y -> x + y

Haxe

W Haxe funkcje anonimowe nazywają się lambda i używają składni function(argument-list) expression;.

var f = function(x) return x*x;
f(8); // 64

(function(x,y) return x+y)(5,6); // 11

Jawa

Java obsługuje anonimowe funkcje o nazwie Lambda Expressions , począwszy od JDK 8 .

Wyrażenie lambda składa się z rozdzielonej przecinkami listy parametrów formalnych zawartych w nawiasach, tokenu strzałki ( ->) i treści. Typy danych parametrów można zawsze pominąć, podobnie jak nawiasy, jeśli istnieje tylko jeden parametr. Treść może składać się z jednej instrukcji lub bloku instrukcji.

// 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);
}

Wyrażenia lambda są konwertowane na „interfejsy funkcjonalne” (zdefiniowane jako interfejsy zawierające tylko jedną metodę abstrakcyjną oprócz jednej lub więcej metod domyślnych lub statycznych), jak w poniższym przykładzie:

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()));    
    }
}

W tym przykładzie IntegerMathzadeklarowany jest funkcjonalny interfejs o nazwie . Wyrażenia lambda, które implementują, IntegerMathsą przekazywane do wykonywanej apply()metody. Metody domyślne, takie jak metody swapdefiniowania funkcji.

Java 8 wprowadziła inny mechanizm o nazwie odwołanie do metody ( ::operator) do tworzenia lambda na istniejącej metodzie. Odwołanie do metody nie wskazuje liczby ani typów argumentów, ponieważ są one wyodrębniane z abstrakcyjnej metody interfejsu funkcjonalnego.

IntBinaryOperator sum = Integer::sum;

W powyższym przykładzie interfejs funkcjonalny IntBinaryOperatordeklaruje metodę abstrakcyjną int applyAsInt(int, int), więc kompilator szuka metody int sum(int, int)w klasie java.lang.Integer.

Ograniczenia Javy

Lambdy Java 8 mają następujące ograniczenia:

  • Lambdy mogą zgłaszać sprawdzone wyjątki, ale takie lambdy nie będą działać z interfejsami używanymi przez Collection API.
  • Zmienne znajdujące się w zakresie, w którym zadeklarowana jest lambda, mogą być dostępne wewnątrz lambdy tylko wtedy, gdy są faktycznie końcowe, tj. jeśli zmienna nie jest zmutowana wewnątrz lub poza zakresem lambda.

JavaScript

JavaScript / ECMAScript obsługuje funkcje anonimowe.

alert((function(x){
  return x * x;
})(10));

ES6 obsługuje składnię „funkcji strzałki”, gdzie symbol => oddziela listę parametrów funkcji anonimowej od treści:

alert((x => x * x)(10));

Ta konstrukcja jest często używana w Bookmarklets . Na przykład, aby zmienić tytuł bieżącego dokumentu (widoczny na pasku tytułu okna ) na jego adres URL , następujący bookmarklet może wydawać się działać.

javascript:document.title=location.href;

Jednak ponieważ instrukcja przypisania zwraca wartość (sam adres URL), wiele przeglądarek faktycznie tworzy nową stronę, aby wyświetlić tę wartość.

Zamiast tego można użyć funkcji anonimowej, która nie zwraca wartości:

javascript:(function(){document.title=location.href;})();

Instrukcja funkcji w pierwszej (zewnętrznej) parze nawiasów deklaruje funkcję anonimową, która jest następnie wykonywana, gdy jest używana z ostatnią parą nawiasów. Jest to prawie równoważne poniższemu, które wypełnia środowisko fniepodobną do funkcji anonimowej.

javascript:var f = function(){document.title=location.href;}; f();

Użyj void(), aby uniknąć nowych stron dla dowolnych anonimowych funkcji:

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

Lub tylko:

javascript:void(document.title=location.href);

JavaScript posiada subtelności składniowe dla semantyki definiowania, wywoływania i oceniania funkcji anonimowych. Te podprogowe niuanse są bezpośrednią konsekwencją oceny wyrażeń w nawiasach. Ilustrują to następujące konstrukcje, które są nazywane natychmiast wywoływanymi wyrażeniami funkcyjnymi :

(function(){ ... }())

oraz

(function(){ ... })()

Reprezentujące " function(){ ... }" przez f, formy konstruktów są nawiasem w nawiasie (f())i nawiasem zastosowanym do nawiasu (f)().

Zwróć uwagę na ogólną niejednoznaczność składniową wyrażenia w nawiasie, ujęte w nawiasy argumenty funkcji i nawiasy wokół parametrów formalnych w definicji funkcji. W szczególności JavaScript definiuje ,operator (przecinek) w kontekście wyrażenia w nawiasie. Nie jest to zwykły zbieg okoliczności, że formy składniowe wyrażenia i argumentów funkcji pokrywają się (ignorując składnię parametrów formalnych funkcji)! Jeśli fnie są zidentyfikowane w powyższych konstrukcjach, stają się (())i ()(). Pierwsza nie dostarcza podpowiedzi składniowej jakiejkolwiek funkcji rezydentnej, ale druga MUSI ocenić pierwszy nawias jako funkcję, aby była legalnym JavaScriptem. (Poza: na przykład, ()'s mogą być ([],{},42,"abc",function(){}), o ile wyrażenie jest funkcją.)

Ponadto funkcja jest instancją Object (podobnie obiekty są instancjami Function), a nawiasy notacji literału obiektowego {}dla kodu z nawiasami są używane podczas definiowania funkcji w ten sposób (w przeciwieństwie do używania new Function(...)). W bardzo szerokim sensie rygorystyczny zakaz (zwłaszcza, że globalne powiązania są zagrożone), dowolnej sekwencji usztywnione instrukcji JavaScript, {stuff}może być uważany za punkt stały z

(function(){( function(){( ... {( function(){stuff}() )} ... )}() )}() )

Bardziej poprawnie, ale z zastrzeżeniami,

( function(){stuff}() ) ~=
   A_Fixed_Point_of(
      function(){ return function(){ return ... { return function(){stuff}() } ... }() }()
   )

Zwróć uwagę na konsekwencje funkcji anonimowej w poniższych fragmentach JavaScript:

  • function(){ ... }()bez otoczenia ()jest generalnie nie legalne
  • (f=function(){ ... })nie „zapomina” fglobalnie inaczej(function f(){ ... })
Metryki wydajności do analizy złożoności przestrzennej i czasowej wywołań funkcji, stosu wywołań itp. w silniku interpretera JavaScript można łatwo zaimplementować za pomocą tych ostatnich anonimowych konstrukcji funkcji. Z implikacji wyników można wywnioskować niektóre szczegóły implementacji rekurencyjnej w porównaniu z iteracyjną, zwłaszcza rekurencję ogonową .

Julia

W Julii funkcje anonimowe definiuje się za pomocą składni (arguments)->(expression),

julia> f = x -> x*x; f(8)
64
julia> ((x,y)->x+y)(5,6)
11

Seplenienie

Lisp i Scheme obsługują funkcje anonimowe za pomocą konstrukcji „lambda”, która jest odniesieniem do rachunku lambda . Clojure obsługuje funkcje anonimowe ze specjalnym formularzem „fn” i składnią czytnika #().

(lambda (arg) (* arg arg))

Wspólne seplenienie

Common Lisp ma koncepcję wyrażeń lambda. Wyrażenie lambda jest zapisywane jako lista z symbolem „lambda” jako pierwszym elementem. Lista zawiera następnie listę argumentów, dokumentację lub deklaracje oraz treść funkcji. Wyrażenia lambda mogą być używane wewnątrz formularzy lambda oraz ze specjalnym operatorem "funkcja".

(function (lambda (arg) (do-something arg)))

"funkcja" może być skrócona jako #'. Istnieje również makro lambda , które rozwija się do postaci funkcji:

; using sharp quote
#'(lambda (arg) (do-something arg))
; using the lambda macro:
(lambda (arg) (do-something arg))

Jednym z typowych zastosowań funkcji anonimowych w Common Lisp jest przekazywanie ich do funkcji wyższego rzędu, takich jak mapcar , która stosuje funkcję do każdego elementu listy i zwraca listę wyników.

(mapcar #'(lambda (x) (* x x))
        '(1 2 3 4))
; -> (1 4 9 16)

Forma lambda w Common Lisp pozwala na zapisanie wyrażenia lambda w wywołaniu funkcji:

((lambda (x y)
   (+ (sqrt x) (sqrt y)))
 10.0
 12.0)

Anonimowym funkcjom w Common Lisp można później nadać globalne nazwy:

(setf (symbol-function 'sqr)
      (lambda (x) (* x x)))
; which allows us to call it using the name SQR:
(sqr 10.0)

Schemat

Nazwane funkcje schematu to po prostu cukier syntaktyczny dla funkcji anonimowych związanych z nazwami:

(define (somename arg)
  (do-something arg))

rozszerza się (i jest równoważne) do

(define somename
  (lambda (arg)
    (do-something arg)))

Clojure

Clojure obsługuje funkcje anonimowe poprzez specjalny formularz „fn”:

(fn [x] (+ x 3))

Istnieje również składnia czytnika do definiowania lambdy:

#(+ % %2%3) ; Defines an anonymous function that takes three arguments and sums them.

Podobnie jak Scheme, "nazwane funkcje" Clojure są po prostu cukrem składniowym dla lambd związanych z nazwami:

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

rozszerza się do:

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

Lua

W Lua (podobnie jak w Scheme) wszystkie funkcje są anonimowe. Nazwie funkcji w Lua jest po prostu zmienna trzyma odwołanie do obiektu funkcyjnego.

Tak więc w Lua

function foo(x) return 2*x end

to tylko cukier syntaktyczny dla

foo = function(x) return 2*x end

Przykład użycia funkcji anonimowych do sortowania w odwrotnej kolejności:

table.sort(network, function(a,b)
  return a.name > b.name
end)

Język Wolfram, matematyka

Wolfram język jest językiem programowania Mathematica . Funkcje anonimowe są ważne w programowaniu tych ostatnich. Istnieje kilka sposobów ich tworzenia. Poniżej znajduje się kilka anonimowych funkcji, które zwiększają liczbę. Pierwszy jest najczęstszy. #1odnosi się do pierwszego argumentu i &oznacza koniec funkcji anonimowej.

     #1+1&
     Function[x,x+1]
     x \[Function] x+1

Na przykład:

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

Ponadto Mathematica ma dodaną konstrukcję do tworzenia rekurencyjnych funkcji anonimowych. Symbol „#0” odnosi się do całej funkcji. Poniższa funkcja oblicza silnię swojego wejścia:

     If[#1 == 1, 1, #1 * #0[#1-1]]&

Na przykład silnia 6 to:

     If[#1 == 1, 1, #1 * #0[#1-1]]&[6]
720

MATLAB, Oktawa

Funkcje anonimowe w MATLAB lub Octave definiuje się za pomocą składni @(argument-list)expression. Wszelkie zmienne, których nie ma na liście argumentów, są dziedziczone z otaczającego zakresu i są przechwytywane przez wartość.

>> f = @(x)x*x; f(8)
ans =  64
>> (@(x,y)x+y)(5,6) % Only works in Octave
ans =  11

Maxima

W Maximie funkcje anonimowe definiuje się za pomocą składni lambda(argument-list,expression),

 f: lambda([x],x*x); f(8);
 64

 lambda([x,y],x+y)(5,6);
 11

ML

Różne dialekty ML obsługują funkcje anonimowe.

OCaml

Funkcje anonimowe w OCaml to funkcje bez zadeklarowanej nazwy. Oto przykład funkcji anonimowej, która mnoży swoje dane wejściowe przez dwa:

fun x -> x*2

W tym przykładzie fun jest słowem kluczowym wskazującym, że funkcja jest funkcją anonimową. Przekazujemy argument x i ->, aby oddzielić argument od ciała.

F#

F# obsługuje funkcje anonimowe w następujący sposób:

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

Standardowy ML

Standard ML obsługuje funkcje anonimowe w następujący sposób:

fn  arg => arg * arg

Powłoka nowej generacji

Next Generation Shell ma kilka składni dla funkcji anonimowych ze względu na ich powszechność w języku i różne przypadki użycia.

Składnie:

f = X*X; f(8)                       # Result: 64
f = { A*B+C }; f(2,3,4)             # Result: 10
f = F(x:Int, y:Int) x*y+2; f(3, 4)  # Result: 14

f = "${X} is all about ${Y}"
f("programming", "semantics")       # Result: "programming is all about semantics"

Przykłady użycia funkcji anonimowych:

[0,1,2].map(X*2)                    # Result: [0,2,4]

data = {"a": "xxx", "b": "yyy"}
data.map("${X} is ${Y}")            # Result: ["a is xxx", "b is yyy"]

Nimi

Nim obsługuje wieloliniowe funkcje anonimowe z wieloma wyrażeniami.

var anon = proc (var1, var2: int): int = var1 + var2
assert anon(1, 2) == 3

Przykład wielowierszowy:

var anon = func (x: int): bool =
             if x > 0:
               result = true
             else: 
               result = false

assert anon(9)

Funkcje anonimowe mogą być przekazywane jako parametry wejściowe innych funkcji:

var cities = @["Frankfurt", "Tokyo", "New York"]

cities.sort(
  proc (x, y: string): int = cmp(x.len, y.len)
)

Funkcja anonimowa to w zasadzie funkcja bez nazwy.

Perl

Perl 5

Perl 5 obsługuje funkcje anonimowe w następujący sposób:

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

Inne konstrukcje przyjmują jako argumenty gołe bloki , które obsługują funkcję podobną do funkcji lambda jednego parametru, ale nie mają tej samej konwencji przekazywania parametrów co funkcje -- @_ nie jest ustawione.

my @squares = map { $_ * $_ } 1..10;   # map and grep don't use the 'sub' keyword
my @square2 = map $_ * $_, 1..10;      # braces unneeded for one expression

my @bad_example = map { print for @_ } 1..10; # values not passed like normal Perl function

PHP

Przed 4.0.1 PHP nie posiadało obsługi funkcji anonimowych.

PHP 4.0.1 do 5.3

PHP 4.0.1 wprowadziło, create_functionktóra była początkową obsługą funkcji anonimowych. To wywołanie funkcji tworzy nową losowo nazwaną funkcję i zwraca jej nazwę (jako ciąg)

$foo = create_function('$x', 'return $x*$x;');
$bar = create_function("\$x", "return \$x*\$x;");
echo $foo(10);

Lista argumentów i treść funkcji muszą być ujęte w pojedyncze cudzysłowy lub znaki dolara muszą być pominięte. W przeciwnym razie PHP zakłada, że ​​" $x" oznacza zmienną $xi zastąpi ją w łańcuchu (mimo że prawdopodobnie nie istnieje) zamiast pozostawiać " $x" w łańcuchu. W przypadku funkcji z cudzysłowami lub funkcji z wieloma zmiennymi, upewnienie się, że zamierzona treść funkcji jest tym, co interpretuje PHP, może być dość żmudne.

Każde wywołanie create_functionpowoduje tworzenie nowej funkcji, która istnieje dla reszty programu i nie może być zbierana , wykorzystując nieodwracalnie pamięć w programie. Wielokrotne użycie tego do tworzenia anonimowych funkcji, np. w pętli, może powodować problemy, takie jak rozdęcie pamięci.

PHP 5,3

PHP 5.3 dodało nową klasę wywoływaną Closurei magiczną metodę, __invoke()która sprawia, że ​​instancja klasy jest wywoływana.

$x = 3;
$func = function($z) { return $z * 2; };
echo $func($x); // prints 6

W tym przykładzie $funcjest instancją Closurei echo $func($x)jest równoważne echo $func->__invoke($x). PHP 5.3 naśladuje funkcje anonimowe, ale nie obsługuje prawdziwych funkcji anonimowych, ponieważ funkcje PHP nadal nie są obiektami pierwszej klasy.

PHP 5.3 obsługuje domknięcia, ale zmienne muszą być wyraźnie wskazane jako takie:

$x = 3;
$func = function() use(&$x) { $x *= 2; };
$func();
echo $x; // prints 6

Zmienna $xjest powiązana przez referencję, więc wywołanie funkcji $funcmodyfikuje ją, a zmiany są widoczne poza funkcją.

PHP 7,4

Funkcje strzałek zostały wprowadzone w PHP 7.4

$x = 3;
$func = fn($z) => $z * 2;
echo $func($x); // prints 6

Dialekty Prologu

Logtalk

Logtalk używa następującej składni dla predykatów anonimowych (wyrażeń lambda):

{FreeVar1, FreeVar2, ...}/[LambdaParameter1, LambdaParameter2, ...]>>Goal

Prosty przykład bez wolnych zmiennych i przy użyciu predykatu mapowania listy to:

| ?- meta::map([X,Y]>>(Y is 2*X), [1,2,3], Ys).
Ys = [2,4,6]
yes

Obsługiwane jest również curry. Powyższy przykład można zapisać jako:

| ?- meta::map([X]>>([Y]>>(Y is 2*X)), [1,2,3], Ys).
Ys = [2,4,6]
yes

Prolog wizualny

Funkcje anonimowe (w ogólności predykaty anonimowe ) zostały wprowadzone w Visual Prologu w wersji 7.2. Predykaty anonimowe mogą przechwytywać wartości z kontekstu. Jeśli zostanie utworzony w elemencie obiektu, może również uzyskać dostęp do stanu obiektu (przez przechwytywanie This).

mkAdderzwraca funkcję anonimową, która przechwyciła argument Xw zamknięciu. Zwracana funkcja to funkcja, która dodaje Xdo swojego argumentu:

clauses
    mkAdder(X) = { (Y) = X+Y }.

Pyton

Python obsługuje proste funkcje anonimowe za pośrednictwem formularza lambda. Wykonywalna treść lambda musi być wyrażeniem i nie może być instrukcją, co jest ograniczeniem, które ogranicza jej użyteczność. Wartość zwracana przez lambda jest wartością zawartego wyrażenia. Formy lambda mogą być używane wszędzie tam, gdzie mogą to być zwykłe funkcje. Jednak te ograniczenia sprawiają, że jest to bardzo ograniczona wersja normalnej funkcji. Oto przykład:

>>> foo = lambda x: x * x
>>> foo(10)
100

Ogólnie rzecz biorąc, konwencja Pythona zachęca do używania nazwanych funkcji zdefiniowanych w tym samym zakresie, ponieważ można zwykle używać funkcji anonimowych w innych językach. Jest to akceptowalne, ponieważ lokalnie zdefiniowane funkcje implementują pełną moc domknięć i są prawie tak wydajne, jak użycie lambdy w Pythonie. W tym przykładzie można powiedzieć, że wbudowana funkcja zasilania została curried :

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

W R funkcje anonimowe definiuje się za pomocą składni function(argument-list)expression.

> f <- function(x)x*x; f(8)
[1] 64
> (function(x,y)x+y)(5,6)
[1] 11

Raku

W Raku wszystkie bloki (nawet te związane z if, while itd.) są funkcjami anonimowymi. Blok, który nie jest używany jako wartość r, jest wykonywany natychmiast.

  1. w pełni anonimowy, zwany jako stworzony
    { say "I got called" };
    
  2. przypisane do zmiennej
    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. curry
    sub add ($m, $n) { $m + $n }
    my $seven   = add(3, 4);
    my $add_one = &add.assuming(m => 1);
    my $eight   = $add_one($seven);
    
  4. Obiekt WhateverCode
    my $w = * - 1;       # WhateverCode object
    my $b = { $_ - 1 };  # same functionality, but as Callable block
    

Rubin

Ruby obsługuje funkcje anonimowe przy użyciu struktury syntaktycznej zwanej block . W Rubim istnieją dwa typy danych dla bloków. Procs zachowują się podobnie do domknięć , podczas gdy lambdas zachowują się bardziej analogicznie do funkcji anonimowej. Po przekazaniu do metody blok jest w pewnych okolicznościach konwertowany na Proc.

irb(main):001:0> # Example 1:
irb(main):002:0* # Purely anonymous functions using blocks.
irb(main):003:0* ex = [16.2, 24.1, 48.3, 32.4, 8.5]
=> [16.2, 24.1, 48.3, 32.4, 8.5]
irb(main):004:0> 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]
irb(main):005:0> # Example 2:
irb(main):006:0* # First-class functions as an explicit object of Proc -
irb(main):007:0* ex = Proc.new { puts "Hello, world!" }
=> #<Proc:0x007ff4598705a0@(irb):7>
irb(main):008:0> ex.call
Hello, world!
=> nil
irb(main):009:0> # Example 3:
irb(main):010:0* # Function that returns lambda function object with parameters
irb(main):011:0* def is_multiple_of(n)
irb(main):012:1>   lambda{|x| x % n == 0}
irb(main):013:1> end
=> nil
irb(main):014:0> multiple_four = is_multiple_of(4)
=> #<Proc:0x007ff458b45f88@(irb):12 (lambda)>
irb(main):015:0> multiple_four.call(16)
=> true
irb(main):016:0> multiple_four[15]
=> false

Rdza

W Rust funkcje anonimowe nazywane są domknięciami. Są one definiowane przy użyciu następującej składni:

|<parameter-name>: <type>| -> <return-type> { <body> };

Na przykład:

let f = |x: i32| -> i32 { x * 2 };

Jednak dzięki wnioskowaniu o typie kompilator jest w stanie wywnioskować typ każdego parametru i typ zwracany, więc powyższy formularz można zapisać jako:

let f = |x| { x * 2 };

W przypadku zamknięć z jednym wyrażeniem (tj. korpus z jedną kreską) można pominąć nawiasy klamrowe:

let f = |x| x * 2;

Zamknięcia bez parametru wejściowego pisze się tak:

let f = || println!("Hello, world!");

Zamknięcia mogą być przekazywane jako parametry wejściowe funkcji, które oczekują wskaźnika do funkcji:

// 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
}

Jednak, aby opisać, jak wartości w treści domknięcia są uchwycone, mogą być potrzebne złożone reguły. Są realizowane przy użyciu cech Fn, FnMut, i FnOnce:

  • Fn: zamknięcie przechwytuje przez odniesienie ( &T). Są używane do funkcji, które nadal mogą być wywoływane, jeśli mają tylko dostęp referencyjny (za pomocą &) do swojego środowiska.
  • FnMut: zamknięcie przechwytuje przez zmienne odniesienie ( &mut T). Są używane do funkcji, które mogą być wywoływane, jeśli mają dostęp do zmiennych referencji (za pomocą &mut) do swojego środowiska.
  • FnOnce: zamknięcie przechwytuje przez wartość ( T). Są używane do funkcji, które są wywoływane tylko raz.

Dzięki tym cechom kompilator przechwyci zmienne w możliwie najmniej restrykcyjny sposób. Pomagają zarządzać sposobem przenoszenia wartości między zakresami, co jest bardzo ważne, ponieważ Rust podąża za konstrukcją życia, aby zapewnić, że wartości są „pożyczane” i przenoszone w przewidywalny i wyraźny sposób.

Poniżej pokazano, w jaki sposób można przekazać zamknięcie jako parametr wejściowy za pomocą Fncechy:

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

Scala

W Scali funkcje anonimowe używają następującej składni:

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

W niektórych kontekstach, na przykład gdy funkcja anonimowa jest parametrem przekazywanym do innej funkcji, kompilator może wywnioskować typy parametrów funkcji anonimowej i można je pominąć w składni. W takich kontekstach możliwe jest również użycie skrótu dla funkcji anonimowych z wykorzystaniem znaku podkreślenia do wprowadzenia parametrów nienazwanych.

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.

Pogawędka

W Smalltalku funkcje anonimowe nazywane są blokami i są wywoływane (wywoływane) poprzez wysłanie im komunikatu „wartość”. Jeśli mają zostać przekazane argumenty, należy użyć komunikatu „wartość:...wartość:” z odpowiednią liczbą argumentów wartości.

Na przykład w GNU Smalltalk ,

st> f:=[:x|x*x]. f value: 8 .
64
st> [:x :y|x+y] value: 5 value: 6 .
11

Bloki Smalltalk są technicznie domknięciami, co pozwala im przeżyć ich zakres definiujący i nadal odwoływać się do zadeklarowanych w nich zmiennych.

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

Szybki

W Swift funkcje anonimowe są nazywane domknięciami. Składnia ma następującą postać:

{ (parameters) -> returnType in
  statement
}

Na przykład:

{ (s1: String, s2: String) -> Bool in
  return s1 > s2
}

Ze względu na zwięzłość i wyrazistość typy parametrów i typ zwracany można pominąć, jeśli można je wywnioskować:

{ s1, s2 in return s1 > s2 }

Podobnie, Swift obsługuje również niejawne instrukcje powrotu dla zamknięć jednoinstrukcyjnych:

{ s1, s2 in s1 > s2 }

Na koniec można również pominąć nazwy parametrów; jeśli zostanie pominięty, odwołanie do parametrów następuje za pomocą skróconych nazw argumentów, składających się z symbolu $, po którym następuje ich pozycja (np. $0, $1, $2 itd.):

{ $0 > $1 }

Tcl

W Tcl zastosowanie funkcji anonimowej kwadratury do 2 wygląda następująco:

apply {x {expr {$x*$x}}} 2
# returns 4

Ten przykład obejmuje dwóch kandydatów na to, co to znaczy być funkcją w Tcl. Najbardziej ogólny jest zwykle nazywany prefiksem polecenia , a jeśli zmienna f zawiera taką funkcję, to sposób wykonania funkcji f ( x ) byłby

{*}$f $x

gdzie {*}jest prefiks rozszerzenia (nowy w Tcl 8.5). Prefiks polecenia w powyższym przykładzie to {x {expr {$x*$x}}} Apply Nazwy poleceń można powiązać z przedrostkami poleceń za pomocą interp aliaspolecenia. Przedrostki poleceń obsługują currying . Prefiksy poleceń są bardzo powszechne w interfejsach API Tcl .

Drugi kandydat na "funkcję" w Tcl jest zwykle nazywany lambda i pojawia się jako {x {expr {$x*$x}}}część powyższego przykładu. Jest to część, która buforuje skompilowaną formę funkcji anonimowej, ale można ją wywołać tylko przez przekazanie do applypolecenia. Lambdy nie obsługują curryingu, chyba że w połączeniu z applyprzedrostkiem polecenia. Lambdy są rzadkością w interfejsach API Tcl.

Wala

W Vala funkcje anonimowe są obsługiwane jako wyrażenia lambda.

delegate int IntOp (int x, int y);

void main () {
	IntOp foo = (x, y) => x * y;
	stdout.printf("%d\n", foo(10,5));
}

Visual Basic .NET

Visual Basic .NET 2008 wprowadził funkcje anonimowe poprzez formularz lambda. W połączeniu z niejawnym typowaniem, VB zapewnia ekonomiczną składnię dla funkcji anonimowych. Podobnie jak w Pythonie, w VB.NET funkcje anonimowe muszą być zdefiniowane w jednym wierszu; nie mogą być wyrażeniami złożonymi. Ponadto funkcja anonimowa w VB.NET musi naprawdę być VB.NET Function- musi zwracać wartość.

Dim foo = Function(x) x * x
Console.WriteLine(foo(10))

Visual Basic.NET 2010 dodał obsługę wielowierszowych wyrażeń lambda i funkcji anonimowych bez zwracanej wartości. Na przykład funkcja do użycia w wątku.

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

Zobacz też

Bibliografia

Zewnętrzne linki