Funkcja anonimowa

rodzaj funkcji w programowaniu

Funkcja anonimowa (również literał funkcyjny lub lambda-abstrakcja) – definicja funkcji, która sama w sobie nie jest powiązana z identyfikatorem (chociaż może być przypisana do zmiennej).

Funkcje anonimowe mogą być[1]:

  1. argumentami przekazywanymi funkcjom wyższego rzędu lub
  2. używane do budowania wyniku funkcji wyższego rzędu, która musi zwracać funkcję.

Jeśli funkcja jest używana tylko jeden raz lub ograniczoną liczbę razy, użycie funkcji anonimowej może być syntaktycznie wygodniejsze niż użycie funkcji nazwanej. Funkcje anonimowe są wszechobecne w funkcyjnych językach programowania i innych językach z obecnymi funkcjami pierwszego rzędu, gdzie pełnią taką samą rolę dla typu funkcji jak literały dla innych typów typów danych.

Funkcje anonimowe biorą początek w pracach Alonzo Churcha nad wynalezieniem rachunku lambda w 1936 roku (przed pojawieniem się komputerów elektronicznych), w którym wszystkie funkcje są anonimowe[2]. Przejawia się to między innymi tym, że w niektórych językach programowania, funkcje anonimowe są tworzone faktycznie przez użycie słowa kluczowego lambda. Ponadto funkcje anonimowe są często nazywane lambdami lub lambda-abstrakcjami. Funkcje anonimowe to jedna z charakterystycznych cech języków programowania od czasu powstania języka Lisp w 1958 roku i coraz większa liczba nowoczesnych języków programowania wspiera funkcje anonimowe.

Funkcje anonimowe są rodzajem funkcji zagnieżdżonych, zapewniając dostęp do zmiennych w zasięgu funkcji zawierającej (zmiennych nielokalnych). Oznacza to, że anonimowe funkcje powinny być implementowane z wykorzystaniem domknięć. W przeciwieństwie do nazwanych funkcji zagnieżdżonych, nie mogą one być rekurencyjne bez zastosowania operatora punktu stałego (również znanego jako anonimowe mocowanie lub anonimowa rekursja) lub przypisywania ich do nazwy[3].

Zastosowanie

edytuj

Funkcje anonimowe mogą być wykorzystane, by zawierać w sobie funkcjonalności, które nie powinny być nazwane oraz, być może mają jedynie krótkotrwały użytek. Niektóre przykłady, o których warto wspomnieć, obejmują domknięcia i currying.

Funkcje anonimowe to kwestia stylu programowania. Ich stosowanie nie jest wymagane. W dowolnym miejscu, w którym można ich użyć, można także zdefiniować specjalną nazwaną funkcję, która działa dokładnie tak samo. Niektórzy programiści wykorzystują funkcje anonimowe dla hermetyzacji niektórych fragmentów kodu, w ten sposób odbierając możliwość ponownego wykorzystania, co zapobiega zaśmiecaniu kodu wieloma małymi jednowierszowymi nazwanymi funkcjami.

W niektórych językach programowania, można określić anonimową funkcję wykonaną dla specjalnego zastosowania, aby dać właśnie to (i tylko), czego chce programista, co jest bardziej wydajne, eleganckie i mniej podatne na błędy pewnych operacji, które korzystają ze stałych wartości.

Cały kod w następujących sekcjach został napisany języku Python 2.x (nie 3.x).

Sortowanie

edytuj

Podczas próby sortowania w niestandardowy sposób może być łatwiej zawrzeć logikę porównania w funkcji anonimowej, niż tworzyć funkcję nazwaną. Większość języków zapewniają generyczną funkcję sortowania, która realizuje algorytm sortowania, który może sortować obiekty dowolnego typu. Funkcja ta zwykle przyjmuje dowolną funkcję porównującą, która przyjmuje dwa argumenty i określa, czy są równe lub czy pierwszy jest „większy” bądź „mniejszy” od drugiego (zwykle zwracając liczbę ujemną, zero lub dodatnią).

Rozważmy sortowanie listy łańcuchów po długości poszczególnych elementów:

>>> a = ['dom', 'samochód', 'rower']
>>> a.sort(lambda x,y: cmp(len(x), len(y)))
>>> print(a)
['samochód', 'rower', 'dom']

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

lambda x,y: cmp(...)

Anonimowa funkcja przyjmuje dwa argumenty: x i u=y oraz zwraca ich porównanie, korzystając z wbudowanej funkcji cmp().

Inny przykład to sortowanie listy elementów według nazw ich klas (w języku Python, wszystko ma klasę):

>>> a = [10, 'liczba', 11.2]
>>> a.sort(lambda x,y: cmp(x.__class__.__name__, y.__class__.__name__))
>>> print(a)
[11.2, 10, 'liczba']

Należy pamiętać, że nazwa klasy 11.2 to „float”, nazwa klasy 10 to „int”, i nazwa klasy 'liczba' to „str”. W posortowanej kolejności-to „float”, „int”, a potem „str”.

Domknięcia

edytuj

Domknięcia to funkcje ewaluowane w środowisku zawierające zmienne o ustalonych wartościach. Poniższy przykład przypisuje „wartość graniczną (threshold)” zmiennej w funkcji anonimowej, która porównuje wejście do argumentu threshold.

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

Może to być używane jako swego rodzaju generator funkcji porównania:

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

Byłoby niepraktyczne tworzenie funkcji nazwanej dla każdej możliwej funkcji porównującej, a zachowywanie wartości granicznej dla przyszłych zastosowań byłoby absolutnie nieeleganckie. Niezależnie od przyczyny zastosowanie domknięcia funkcja anonimowa to jednostka, która zawiera funkcjonalność wykonywania porównania.

Currying

edytuj

Currying to proces modyfikacji funkcji tak, aby przyjmowała mniejszą ilość argumentów (w tym przypadku, transformujemy funkcję, która wykonuje dzielenie przez liczbę całkowitą, w taką która wykonuje dzielenie przez jeden, ustalony dzielnik).

>>> def dziel(x, y):
... return x / y

>>> def dzielenie(d):
... return lambda x: dziel(x, d)

>>> naPol = dzielenie(2)
>>> naTrzy = dzielenie(3)

>>> print naPol(32), naTrzy(32)
16 10

>>> print naPol(40), naTrzy(40)
20 13

Podczas gdy korzystanie z anonimowych funkcji razem z curryingiem nie jest może zbyt powszechne, to wciąż może być stosowane. W powyższym przykładzie funkcja dzielenie generuje funkcję dzielącą przez określony dzielnik. Funkcje naPol oraz naTrzy tworzą funkcje podziału o stałych dzielnikach.

Funkcja dzielenie tworzy również domknięcie poprzez przypisanie zmiennej „d” wartości.

Funkcje wyższego rzędu

edytuj

Python 2.x zawiera kilka funkcji, które pobierają jako argument anonimowe funkcje. W tej sekcji opisano niektóre z nich.

Funkcja Map wykonuje wywołanie funkcji dla każdego elementu listy. W poniższym przykładzie podnosi do kwadratu każdy element tablicy, korzystając z funkcji anonimowej.

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

Anonimowa funkcja przyjmuje argument, który mnoży z samym sobą (podnosi go do kwadratu).

Filter

edytuj

Funkcja filter zwraca wszystkie elementy z listy, które przekazane jako argument do określonej wcześniej funkcji wartościują ją na True.

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

W powyższym przykładzie anonimowa funkcja sprawdza, czy przekazany mu argument jest parzysty.

Funkcje fold/reduce (składanie/redukowanie) przechodzą po wszystkich elementach na liście (zwykle od lewej do prawej), nagromadzając je, w określony sposób, do pewnej wartości. Powszechne wykorzystywane są, aby zredukować wszystkie elementy listy do jednej wartości, np.:

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

Co wykonuje

 .

Zaprezentowana tutaj funkcja anonimowa mnoży dwie wartości.

Wynikiem funkcji fold nie musi koniecznie być jedna wartość - właściwie rzecz biorąc funkcje map i filter mogą być zaimplementowane z użyciem fold. W przypadku funkcji map, wartość nagromadzona to nowa lista, zawierająca wyniki wywołania funkcji dla każdego elementu listy oryginalnej. W filter, wartość nagromadzona to nowa lista zawierająca tylko te elementy, które spełniają określony warunek.

Lista języków

edytuj

Poniżej znajduje się lista języków programowania, które w pełni obsługują nienazwane funkcje anonimowe, wspierają jakiś wariant funkcji anonimowych lub nie mają wsparcia dla funkcji anonimowych.

Ta tabela pokazuje pewne ogólne trendy. Po pierwsze, języki, które nie obsługują funkcji anonimowych – C, Pascal, Object Pascal – są konwencjonalnymi, statycznie pisanymi językami. To jednak nie oznacza, że statycznie wpisane języki są niezdolne do obsługi funkcji anonimowych. Na przykład, języki z rodziny ML są statycznie typowane, jednak fundamentalnie zawierają funkcje anonimowe, a język Delphi, dialekt Object Pascal, został rozbudowany o wsparcie funkcji anonimowych. Po drugie, języki które traktują funkcje jako funkcje pierwszego rzędu – Dylan, JavaScript, Lisp, Scheme, ML, Haskell, Python, Ruby, Perl – generalnie posiadają wsparcie dla funkcji anonimowych, co oznacza, że funkcje mogą być definiowane i przekazywane z taką samą łatwością jak inne typy danych. Gdyby ktoś nie uznawał powyższych przykładów za wystarczające, to wystarczy wspomnieć, że standard C++11 dodaje funkcje anonimowe do C++, czyli do języka konwencjonalnego, statycznie typowanego.

Język Wsparcie Notki
ActionScript Tak
Ada Nie Wyrażenia funkcyjne są częścią Ada2012
ALGOL 68 Tak
Brainfuck Nie
Bash Częściowo Stworzono bibliotekę w celu dodania wsparcia dla funkcji anonimowych[4].
C Nie Wsparcie jest zapewniane w clang, wraz z llvm compiler-rt lib. Wsparcie w GCC jest udostępnione jako implementacja w makrach. Szczegóły zobacz niżej.
C# Tak
C++ Tak Część standardu C++11
CFML Tak Wraz z Railo 4[5] / ColdFusion 10[6]
Clojure Tak
COBOL Nie Niestandardowy dialekt języka Managed COBOL: Micro Focus wspiera lambdy, nazwane anonimowymi delegatami/metodami[7].
Curl Tak
D Tak
Dart Tak
Delphi Tak
Dylan Tak
Eiffel Tak
Erlang Tak
F# Tak
Factor Tak Wsparcie przez „Cudzysłowia”[8]
Fortran Nie
Frink Tak
Go Tak
Gosu Tak
Groovy Tak
Haskell Tak
HaXe Tak
Java Tak Wspierane od Java 8.
JavaScript Tak Nazywane funkcjami strzałkowymi (ang. arrow functions) ze względu na swoją formę: (a, b) => a * b. Dostępne od ES2015.
Julia Tak
Lisp Tak
Logtalk Tak
Lua Tak
MUMPS Nie
Mathematica Tak
Maple Tak
MATLAB Tak
Maxima Tak
OCaml Tak
Octave Tak
Object Pascal Częściowo Delphi, dialekt Object Pascal, implementuje natywne wsparcie dla anonimowych funkcji (formalnie metod anonimowych (ang. anonymous methods)) od konferencji Delphi 2009. Dialekt Oxygene również je wspiera.
Objective-C (Mac OS X 10.6+) Tak Nazywane blokami; ponadto bloki Objective-C, mogą być wykorzystywane również w C and C++ gdy programujemy na platformie firmy Apple.
Pascal Nie
Perl Tak
PHP Tak Od PHP 5.3.0 prawdziwe funkcje anonimowe są wspierane; wcześniej istniało tylko częściowe wsparcie dla funkcji anonimowych, które działało podobnie do implementacji w C#.
PL/I Nie
Python Częściowo Python wspiera funkcje anonimowe poprzez składnie lambda, w którym można używać tylko wyrażeń, nie pełnych instrukcji.
R Tak
Racket Tak
Rexx Nie
RPG Nie
Ruby Tak Funkcje anonimowe Ruby, sprowadzone z języka Smalltalk, są nazywane blokami.
Rust Tak
Scala Tak
Scheme Tak
Smalltalk Tak Funkcje anonimowe są nazywane blokami.
Standard ML Tak
Swift Tak Są nazywane domknięciami (ang. Closures).
TypeScript Tak
Tcl Tak
Vala Tak
Visual Basic .NET v9 Tak
Visual Prolog v 7.2 Tak
Wolfram Language Tak

Przykłady

edytuj

Liczne języki obsługują funkcje anonimowe, lub podobną funkcjonalność.

C (niestandardowe rozszerzenia)

edytuj

Anonimowa funkcje nie są obsługiwane przez standardowy język C, ale są obsługiwane przez niektóre z jego dialektów, takie jak gcc i clang.

GCC zapewnia wsparcie dla anonimowych funkcji, mieszanych przez funkcje zagnieżdżone i pewne wyrażenia. Ma postać:

( { zwracany_typ nazwa_funkcji_anonimowych (parametry) { cialo funkcji } nazwa_funkcji_anonimowych; } )

Poniższy przykład działa tylko z GCC. Należy również pamiętać, że ze względu na sposób działania makr, jeśli twoje l_body zawiera przecinki poza nawiasami, program się nie skompiluje, jako że GCC używa przecinka jako separatora do następnego argumentu w makro. Argument l_ret_type może być usunięty, jeśli __typeof__ jest dostępny. W przykładzie poniżej, użycie __typeof__ na tablicy zwróci wartość testtype *, która może być „wyłuskana”, aby uzyskać właściwą wartość, jeśli to konieczne.

# include <stdio.h>

//* to definicja funkcji anonimowej */
# 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 __test
{
  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);
  /* funkcja anonimowa jest przekazana jako funkcja do 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 (dla C, C++, Objective-C, Objective-c++)

edytuj

Clang zapewnia wsparcie dla funkcji anonimowych, zwanych blokami. Bloki mają formę:

^zwracany_typ ( parametry ) { cialo_funkcji }

Typ bloków powyżej to zwracany_typ (^)(parametery).

Wykorzystując powyższe bloki i 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");
  };

/* Przekazanie jako parametr innej funkcji */
  dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), count_loop);

/* Wywolaj bezposrednio */
  count_loop();

  return 0;
}

Kod z blokami musi być kompilowany z -fBlocksRuntime i linkowany z -lBlocksRuntime

C++ (od C++11)

edytuj

C++11 oferuje wsparcie dla funkcji anonimowych nazywanymi wyrażeniami lambda. Lambda-wyrażenia mają postać:

[domknięcie](parametry) -> zwracany_typ { cialo_funkcji }

Przykładową funkcję lambda określa się w następujący sposób:

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

C++11 obsługuje również domknięcia. Są określane w nawiasach kwadratowych [i ] w deklaracji wyrażenia lambda. Mechanizm pozwala tym zmiennym, aby były przekazywane przez wartość lub przez referencje. Poniższa tabela pokazuje różne warianty:

[] //brak zdefiniowanych zmiennych. Proba uzycia jakichkolwiek zewnetrznych zmiennych w lambdzie to blad.
[x, &y] //x jest przejmowana przez wartosc, y jest przejmowana przez referencje
[&] //jakakolwiek zmienna jest domyslnie przejmowana przez referencje, jesli zostaje uzyta
[=] //jakakolwiek zmienna jest domyslnie przejmowana przez wartosc, jesli zostaje uzyta
[&, x] //x jest jednoznacznie przejmowana przez wartosc. Inne zmienne domyslnie przez referencje
[=, &z] //z jest jednoznacznie przejmowana przez referencje. Inne zmienne domyslnie przez wartosc

Zmienne przekazane przez wartość są domyślnie traktowane jako stałe. Dodawanie mutable po liście parametrów sprawia, że będą traktowane jako zmienne tymczasowe.

Następne dwa przykłady pokazują użycie wyrażeń 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;
});

Powyższy kod oblicza sumę wszystkich elementów listy. Zmienna total jest przechowywana jako część domknięcia funkcji lambda. Jako że jest to referencja do zmiennej total umieszczonej na stosie, funkcja 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), [&, value, this](int x) {
	total += x * value * this->some_func();
});

To spowoduje, że zmienna total będzie przechowywana jako referencja, ale value będzie przechowywana jako kopia.

Przekazywanie zmiennej this jest wyjątkowe. Może być wykonane tylko przez wartość, nie przez referencję. this może być przekazane tylko jeśli najbliższa funkcja zawierająca funkcję nie jest składową statyczną. Lambda będzie miała taki sam dostęp do składowych protected/private jak składowa, która ją utworzyła.

Jeśli this zostaje przekazana, jawnie lub niejawnie, to zasięg otaczających składowych klasy także jest testowany. Dostęp do elementów this nie wymaga jawnego użycia składni this->.

Właściwa wewnętrzna realizacja może się różnić, ale oczekuje się, że funkcji lambda, do której wszystkie argumenty są przekazywane przez referencje, zachowa wskaźnik stosu funkcji, w której jest utworzona, zamiast indywidualnych referencji do zmiennych stosowych. Jednakże funkcje lambda, ze względu na małe wymiary i lokalność w ramach z zasięgu, są dobrymi kandydatami do zastosowania na nich metody inline, zatem nie będą wymagać dodatkowego miejsca na referencje.

Jeśli domknięcie, które zawiera referencje do zmiennych lokalnych, jest wywoływane po najniższym wewnętrznym zasięgu bloku, w którym zostało stworzone, to zachowanie jest niezdefiniowane.

Funkcje lambda to obiekty funkcyjne z typem zależnym od implementacji; nazwa tego typu jest dostępna tylko dla kompilatora. Jeżeli użytkownik życzy sobie pobrania funkcji lambda jako parametru, to jej typ musi być typem parametrycznym lub musi stworzyć std::function lub podobny obiekt, aby uchwycić wartość lambdy. Korzystanie ze słowa kluczowego auto może pomóc w zapisaniu funkcji lambda.

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

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

# include <functional>
# include <vector>
# include <iostream>

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(int i=0;i<fv.size();i++)
		std::cout << fv[i](2.0) << std::endl;
	for(int 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;
	return 0;
}

Wyrażenie lambda z pustym domknięciem ([]) może być niejawnie przekształcone na wskaźnik na funkcję tego samego typu, jak typ, z którym lambda została zadeklarowana. Także to jest poprawne:

auto a_lambda_func = [](int x) { /*...*/ };
void (* func_ptr)(int) = a_lambda_func;
func_ptr(4); //wywoluje lambde

Biblioteka Boost udostępnia własną składnie dla funkcji lambda, korzystając z następującej składni:[9]

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

Obsługa funkcji anonimowych w C# pogłębiała się w kolejnych wersjach kompilatora języka. Język C# v3.0, wydany w listopadzie 2007 roku z .NET Framework v3.5, cechuje się pełną obsługą funkcji anonimowych. Składnia C# odnosi się do nich jako „wyrażeń lambda”, zgodnie z pierwotnym nazewnictwem funkcji anonimowych w rachunku lambda. Zobacz Specyfikację Języka C# 4.0, sekcja 5.3.3.29, aby uzyskać więcej informacji.

 // pierwszy int to typ x'
 // drugi int to typ zwracanej wartosci
 // <see href="http://msdn.microsoft.com/en-us/library/bb549151.aspx" />
 Func<int,int> foo = x => x*x; Console.WriteLine(foo(7));

Funkcja anonimowa nie może być przypisana do pośrednio typowanej zmiennej, ponieważ składnia wyrażenia lambda może być używany dla oznaczenia funkcji anonimowej lub drzewa wyrażeń, a wybór nie może być podejmowany automatycznie przez kompilator. Na przykład to nie działa:

// NIE skompiluje sie!
var foo = (int x) => x*x;

Jednakże wyrażenie lambda może brać udział w interferencji typów, np. aby użyć funkcji anonimowej z funkcjonalnością Map dostępną z System.Collections.Generic.List (w metodzie ConvertAll()):

// Inicjalizowanie listy:
var values = new List<int>() { 7, 13, 4, 9, 3 };
// Mapuj wszystkie elementy listy przez funkcje anonimowa, zwroc nowa liste
var foo = values.ConvertAll(d => d*d) ;
// Rezultat w zmiennej foo jest typu System.Collections.Generic.List<Int32>

Poprzednie wersje C# miały bardziej ograniczoną obsługę funkcji anonimowych. C# w wersji v1.0, wprowadzonej w lutym 2002 roku z NET Framework v1.0, zapewniał częściowa obsługę za pomocą delegatów. Konstrukcja ta jest bardzo podobna do delegatów w PHP. W C# 1.0, delegaci są do podobni do wskaźników na funkcje, które odnoszą się do jednoznacznie nazwanej metody wewnątrz klasy. (Ale w przeciwieństwie do PHP nazwa nie jest potrzebna przy użyciu delegata.) C# w wersji v2.0, wydany w listopadzie 2005 roku razem z .NET Framework v2.0, wprowadził pojęcie metod anonimowych, jako sposób na pisanie wstawianych nienazwanych wyrażeń. C# 3.0 kontynuuje wsparcie dla tych konstrukcji, ale wspiera także funkcje lambda.

Ten przykład będzie się kompilować w C# 3.0 i pokazuje wszystkie trzy metody:

    public class TestDriver
    {
        delegate int SquareDelegate(int d);
        static int Square(int d)
        {
            return d*d;
        }

        static void Main(string[] args)
        {
            // C# 1.0: Pierwotna skladnia delegatow wymagala
            // inicjalizacji z metoda nazwana.
            SquareDelegate A = new SquareDelegate(Square);
            System.Console.WriteLine(A(3));

            // C# 2.0: Delegat moze byc zainicjalizowany
            // z kodem typu inline, zwanym „metoda anonimowa”. Ta
            // metoda pobiera int jako parametr.
            SquareDelegate B = delegate(int d) { return d*d; };
            System.Console.WriteLine(B(5));

            // C# 3.0. Delegat moze byc zainicjalizowany poprzez
            // wyrazenie lambda. Lambda pobiera int, oraz zwraca int.
            // Typ x jest wyprowadzany przez kompilator.
            SquareDelegate C = x => x*x;
            System.Console.WriteLine(C(7));

            // C# 3.0. Delegat akceptujacy jedno wejscie
            // zwracajacy jedno wyjscie moze byc posrednio zdefiniowany z typem Func<>.
            System.Func<int,int> D = x => x*x;
            System.Console.WriteLine(D(9));
        }
    }

W przypadku C# w wersji 2.0, kompilator C# akceptuje blok kodu funkcji anonimowej i tworzy statyczną funkcję prywatną. Oczywiście, wewnętrznie funkcja ta otrzymuje automatycznie wygenerowaną nazwę, opartą na nazwie metody, w której dokonano deklaracji Delegata. Jednak ta nazwa, z wyjątkiem użycia refleksji, nie jest wystawiona na kod aplikacji.

W przypadku 3.0 C#, stosowany jest ten sam mechanizm.

fn = function(){
  // instrukcje
};

CFML obsługuje wszelkie 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;
};

Funkcje anonimowe w CFML implementują domknięcie.

D w celu implementacji funkcji anonimowych wykorzystuje delegatów inline. Pełna składnia dla delegata inline to

zwracany_typ delegate(argumenty){/*cialo*/}

Jeśli jest to jednoznaczne, zwracany typ i słowo kluczowe delegate może być pominięte.

(x){return x*x;}
delegate (x){return x*x;} // jezeli wymagane jest wieksza rozleglosc
(int x){return x*x;} // jezeli parametr nie moze byc wyprowadzony
delegate (int x){return x*x;} // ditto
delegate double(int x){return x*x;} // jezeli typ zwracanej wartosci musi byc wymuszony

Począwszy od wersji 2.0 D, jeżeli kompilator nie dowiedzie, że jest to niepotrzebne, alokuje domknięcia na stercie. Aby wymusić alokacje na stosie, może być użyte słowo kluczowe scope. Począwszy od wersji 2.058, można użyć skróconej notacji:

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

Anonimową funkcję można przypisać do zmiennej i użyć w ten sposób:

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

Dart wspiera funkcje anonimowe.

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

lub

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

Delphi

edytuj

Delphi obsługuje funkcje anonimowe począwszy od wersji 2009.

program demo;

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

var
  x1: TSimpleProcedure;
  y1: TSimpleFunction;

begin
  x1 := procedure
    begin
      Writeln('Hello World');
    end;
  x1;   // wywolanie wlasnie zdefiniowanej metody anonimowej

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

Erlang

edytuj

Eгlang używa podobnej składni dla funkcji anonimowych jak i funkcji nazwanych.

% Funkcja anonimowa przypisana do zmiennej Square
Square = fun(X) -> X * X end.

% Funkcja nazwana o tej samej roli
square(X) -> X * X.

Go wspiera funkcja anonimowe.

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

Haskell

edytuj

Haskell wykorzystuje zwięzłą składnię dla funkcji anonimowych (wyrażeń lambda).

 \x -> x * x

Wyrażenia lambda są w pełni zintegrowane z silnikiem typowania, i obsługują całą składnie i wszystkie funkcjonalności „zwykłych” funkcji (z wyjątkiem korzystania z wielu definicji dla dopasowywania wzorców, ponieważ lista argumentów jest podawana tylko raz).

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

Następujące wyrażenia są sobie równoważne:

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

W HaXe funkcje anonimowe nazywane są lambdami i używają składni function(lista argumentow) wyrazenie; .

var f = function(x) return x*x;
f(8); // 64
(function(x,y) return x+y)(5,6); // 11

Java obsługuje funkcji anonimowe począwszy od wersji JDK 8[10]. W języku java, funkcje anonimowe nazywane są Wyrażeniami Lambda (ang. Lambda Expressions).

Wyrażenie lambda składa się z listy oddzielonych przecinkami parametrów formalnych ujętych w nawiasy, markera strzałki ( -> ) i ciała funkcji. Jeśli istnieje tylko jeden parametr, typy danych parametrów, jak i nawiasy mogą zostać pominięte. Ciało może składać się z jednej instrukcji lub bloku instrukcji[11].

// Bez parametru
() -> System.out.println("Hello, world.")

// Z jednym parametrem (To przykład odzorowania identycznosciowego).
a -> a

// Z prostym wyrazeniem
(a, b) -> a + b

// Z jasna informacja o typie
(long id, String name) -> "id: " + id + ", name:" + name

// Z blokiem kodu
(a, b) -> { return a + b; }

// Z wieloma instukcjami w ciele funkcji. Wymagany jest blok kodu
// Ten przyklad zawiera zagniezdzone wyrazenia lambda (pierwsza jest take domknieciem).
(id, defaultPrice) -> {
  Optional 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” (definiowane jako interfejsy, które oprócz jednej czy więcej metod domyślnych lub statycznych zawierają tylko jedną metodę abstrakcyjną[11]), jak pokazano 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 zostaje zadeklarowany interfejs funkcjonalny o nazwie IntegerMath. Wyrażenia lambda, implementujące IntegerMath są przekazywane do metody apply() w celu ich wykonana. Domyślne metody, takie jak swap określają metody, które można wykonać na funkcjach.

JavaScript

edytuj

JavaScript/ECMAScript obsługuje funkcje anonimowe.

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

W ES6:

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

Konstrukcja ta jest często używane w Bookmarkletach. Na przykład, aby zmienić nazwę bieżącego dokumentu (widoczne w tytule okna przeglądarki) na jego adres URL, następny bookmarklet może sprawiać wrażenie działającego prawidłowo.

javascript:document.title=location.href;

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

Stosując zamiast tego funkcje anonimową, która nie zwraca wartości:

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

Instrukcja function w pierwszej (zewnętrznej) parze nawiasów deklaruje anonimową funkcje, która zostaje później wykonana, o czym świadczy składnia z ostatnimi pustymi nawiasami. Jest to prawie równoznaczne z kodem zaprezentowanym poniżej, który tworzy zmienną f.

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

Należy korzystać z void(), aby uniknąć nowych stron przy wykonywaniu funkcji anonimowych:

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

lub bez użycia funkcji anonimowej:

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

JavaScript posiada subtelne reguły semantyczne dotyczące definiowania, wywoływania oraz ewaluowania funkcji anonimowych. Te trudno dostrzegalne niuanse są bezpośrednią konsekwencją ewaluacji wyrażeń. Poniższe konstrukcje nazywane natychmiastowo-wywoływanymi wyrażeniami funkcyjnymi (ang. immediately-invoked function expression) dobrze to ilustrują:

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

i

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

Skracając zapis „function(){ ... }” przez f, formy konstrukcji są odpowiednio wyrażeniem w nawiasach wewnątrz wyrażenia w nawiasach (f()) i wyrażeniem w nawiasach (f)() wykonanym przez wyrażenie w nawiasach.

Należy zwrócić uwagę na ogólne niejasności składniowe wyrażeń w nawiasach, argumentów funkcji w nawiasach, oraz argumentów formalnych definicji funkcji podanych w nawiasach. W szczególności, JavaScript definiuje operator , (przecinek) w kontekście wyrażeń w nawiasach. Nie jest to przypadkiem, że formy składniowe pokrywają się dla wyrażenia oraz argumentów funkcji (ignorując składnie argumentów formalnych funkcji)! Jeśli f nie jest zdefiniowane w wyrażeniu powyżej, staje się one (()) i ()(). Pierwszy nie zapewnia podpowiedzi składniowej odnośnie do funkcji wewnątrz ale drugi MUSI ewaluować pierwszy nawias jako funkcje aby być prawidłowym kodem JavaScript. (Oprócz tego: przykładowo () może być ([],{},42,"Abc",function () {}), byleby wyrażenie ewaluowało się jako funkcja.)

Ponadto, funkcja jest instancją obiektu (podobnie obiekty są instancjami funkcji), a notacja dla literałów obiektów, {}dla kodu w klamrach, jest używana przy definiowaniu funkcji w taki sposób (w przeciwieństwie do korzystania z new Function(...)). W najszerszym nieścisłym sensie (szczególnie z uwzględnieniem naruszenia powiązań globalnych), dowolna sekwencja instrukcji JavaScript w klamrach, {stuff}, może być traktowana jako punkt stały poniższego wyrażenia

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

Bardziej poprawnie, ale z zastrzeżeniami

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

Należy zwrócić uwagę na konsekwencje zastosowania funkcji anonimowych we fragmentach JavaScript, poniżej:

  • function(){ ... }() bez otaczających (), zwykle nie jest prawidłowa
  • (f=function(){ ... }) nie „zapomnina” globalnie o f w przeciwieństwie do (function f(){ ... }
Wskaźniki wydajności do analizy złożoności przestrzennej i czasowej wywołania funkcji, wywołań na stosie, itp. silnika interpretera JavaScript dają się łatwo zaimplementować za pomocą powyższej konstrukcji funkcji anonimowych. Z interpretacji wyników można pozyskać pewne wiadomości odnośnie do implementacji silnika, dotyczące wydajności iteracji oraz rekursji, a w szczególności rekurencji ogonowej.

W języku Julia funkcje anonimowe są definiowane przy użyciu składni (argumenty)->(wyrażenie),

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

Lisp i Scheme obsługują funkcje anonimowe z pomocą konstrukcji „lambda”, które odnoszą się do rachunku lambda. Clojure obsługuje funkcje anonimowe za pomocą konstrukcji „fn” oraz makra #() czytnika.

(lambda (arg) (* arg arg))

Common Lisp

edytuj

Common Lisp zawiera koncepcje wyrażeń lambda. Wyrażenie lambda jest zapisywane w postaci listy z symbolem „lambda” jako pierwszy element. Lista zawiera także listę argumentów, dokumentacji i deklaracji, oraz ciało funkcji. Wyrażenia lambda mogą być używane wewnątrz innej lambdy ze specjalnym operatorem „function”.

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

„function” może być zapisane w skrócie jako #'. Ponadto istnieje makro „lambda”, które rozwija się do postaci funkcji:

; Uzywajac ostrego cudzyslowia
# '(lambda (arg) (do-something arg))
; Uzywajac makra lambda:
(lambda (arg) (do-something arg))

Jednym z typowych zastosowań funkcji anonimowych w Common Lisp jest przekazywanie ich funkcjom wyższego rzędu jak „mapcar”. „mapcar” wywołuje funkcje dla każdego elementu listy i zwraca listę jako rezultat.

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

„lambda formy” w Common Lisp pozwalają „wyrażeniom lambda” na bycie używanymi w wywołaniach funkcji:

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

Funkcje anonimowe w Common Lisp mogą, po uprzedniej definicji, mieć nadawane nazwy:

(setf (symbol-function 'sqr)
      (lambda (x) (* x x)))
; co pozwala na jej wywolanie przy uzyciu identyfikatora SQR:
(sqr 10.0)

Scheme

edytuj

Co ciekawe, „funkcje nazwane” - to po prostu cukier syntaktyczny dla funkcji anonimowych powiązanych z nazwami:

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

rozwija się do (jest równoważne z)

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

Clojure

edytuj

Clojure obsługuje funkcje anonimowe za pomocą konstrukcji „fn”:

(fn [x] (+ x 3))

Istnieje również składnia czytnika służąca do definicji wyrażenia lambda:

# (+ % %2%3) ; Definiuje funkcje anonimowa, która pobiera trzy argumenty i je sumuje.

Jak Scheme, „funkcje nazwane” Clojure to po prostu cukier syntaktyczny dla wyrażeń lambda związanych z nazwami:

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

rozwija się do:

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

W Lua (jak w Scheme) wszystkie funkcje są anonimowe. Funkcja nazwana w lua-to po prostu zmienna, która przechowuje referencje do obiektu funkcyjnego[12].

Tak więc, w lua

function foo(x) return 2*x end

to po prostu 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)

Wolfram Language/Mathematica

edytuj

Wolfram Language to język programowania systemu Mathematica. Funkcje anonimowe są ważnym elementem programowania w systemie Mathematica. Istnieje kilka sposobów ich tworzenia. Poniżej znajduje się kilka funkcji anonimowych, które inkrementują liczbę. Pierwszy sposób jest najbardziej powszechny. '#1' odnosi się do pierwszego argumentu a '&' oznacza koniec funkcji anonimowej.

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

Tak więc, na przykład:

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

Ponadto, Mathematica ma dodatkową konstrukcję do budowy rekursywnych anonimowych funkcji. Symbol '#0' odnosi się do całej funkcji. Poniższa funkcja oblicza silnię swojego wejścia:

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

MATLAB/Octave

edytuj

Funkcje anonimowe w GNU Octave lub w MATLAB są definiowane za pomocą składni @(lista-argumentów)wyrażenie. Wszystkie zmienne, które nie znalazły się na liście argumentów są dziedziczone z zawierającego zasięgu.

 > f = @(x)x*x; f(8)
 ans = 64
 > (@(x,y)x+y)(5,6) % Dziala tylko w Octave
 ans = 11

Maxima

edytuj

W języku Maxima funkcje anonimowe są definiowane przy użyciu składni lambda(list argumentów,wyrażenie),

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

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

Przeróżne dialekty ML wspierają funkcje anonimowe.

fun arg -> arg * arg
(fun x -> x * x) 20 // 400
fn arg => arg * arg

Perl 5

edytuj

Perl 5 wpiera funkcje anonimowe, w następujący sposób:

(sub { print "I got called\n" })->(); # 1. calkowicie anonimowa, wywolywana przy utworzeniu

my $squarer = sub { my $x = shift; $x * $x }; # 2. przypisana do zmiennej

sub curry {
    my ($sub, @args) = @_;
    return sub { $sub->(@args, @_) };         # 3. jako wartosc zwracana przez inna funkcje
}

# przyklad Curryingu w Perl'u
sub sum { my $tot = 0; $tot += $_ for @_; $tot } # zwraca sume argumentow
my $curried = curry \&sum, 5, 7, 9;
print $curried->(1,2,3), "\n"; # wypisuje 27 ( = 5 + 7 + 9 + 1 + 2 + 3 )

Inne konstrukcje pobierają „gołe bloki” (ang. bare blocks) jako argumenty, co pełni rolę podobną do funkcji lambda z jednym parametrem, w ten sposób nie utrzymując tej samej konwencji przekazywania parametrów, gdyż @_ nie jest ustawione.

my @squares = map { $_ * $_ } 1..10; # map i grep nie uzywaja slowa kluczowego 'sub'
my @square2 = map $_ * $_, 1..10; # nawiasy nie potrzebne dla pojedynczego wyrazenia

my @bad_example = map { print for @_ } 1..10; # przekazywanie wartosci jak normalna funkcja Perl'a

Perl 6

edytuj

W języku Perl 6, wszystkie bloki (nawet te, które są związane z if, while itp.) to funkcje anonimowe. Blok, który nie jest używany jako R-wartość, jest wykonywany natychmiast.

# 1. calkowicie anonimowa, wywolywana przy utworzeniu
{ say "I got called" };

# 2. przypisana do wartosci
my $squarer1 = -> $x { $x * $x }; # 2a. "pointy block"
my $squarer2 = { $^x * $^x }; # 2b. "twigil"
my $squarer3 = { my $x = shift @_; $x * $x }; # 2b. styl Perl 5

# 3. currying
sub add ($m, $n) { $m + $n }
my $seven = add(3, 4);
my $add_one = &add.assuming(m => 1);
my $eight = $add_one($seven);

Przed wydaniem wersji 4.0.1, PHP nie wspierał funkcji anonimowych[13].

PHP w od 4.0.1 do 5,3

edytuj

PHP 4.0.1 wprowadził create_function, co było zaczątkiem wsparcia funkcji anonimowych. Wywołanie tej funkcji tworzy nową funkcję z unikatową nazwą (w postaci łańcucha)

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

Funkcja została usunięta w PHP 8 między innymi ze względu na problemy z zabezpieczeniem danych podawanych do tej funkcji[14].

Innym problem jest to, że każde wywołanie create_function stworzy nową, globalną funkcję, która będzie istnieć aż do końca programu, i nie może być usunięta przy pomocu „garbage collectora[15]. Jeśli ktoś używa tej techniki ponad miarę (np. w pętli), może spowodować nieodwracalne zajęcie pamięci programu.

PHP 5.3

edytuj

W PHP 5.3 dodano nową klasę, zwaną Closure i magiczną metodę __invoke(), która sprawia, że instancja klasy jest wywoływana[16].

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

W tym przykładzie, $func jest instancją Closure, a echo $func() jest odpowiednikiem $func->__invoke($z). PHP 5.3 naśladuje funkcje anonimowe, ale on nie obsługuje prawdziwych funkcji anonimowych, ponieważ funkcje w PHP wciąż nie są obiektami pierwszego rzędu.

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

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

Zmienna $x jest powiązana za pomocą referencji, a więc wywołanie $func modyfikuje ją tak, że zmiany są widoczne poza samą funkcją.

Dialekty języka Prolog

edytuj

Logtalk

edytuj

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 z użyciem predykatu mapującego listy:

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

Currying również jest wspierany. Powyższy przykład może być zapisany jako:

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

Visual Prolog

edytuj

Funkcje anonimowe (generalnie rzecz biorąc anonimowe predykaty) zostały wprowadzone w ramach Prologu 7.2.[17] Anonimowe predykaty może pobierać wartości z kontekstu. Jeśli obiekt został stworzony w składowej obiektu może również uzyskać dostęp do stanu obiektu (poprzez pobieranie This).

mkAdder zwraca anonimową funkcję, która pobrała argument x z domknięcia. Zwracana funkcja to funkcja, która dodaje x do jej argumentu:

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

Python

edytuj

Python obsługuje proste funkcje anonimowe w postaci form Lambda. Wykonywalne ciało lambdy musi być wyrażeniem i nie może być pełną instrukcją, które jest ograniczeniem, która ogranicza jego użyteczność. Wartość zwracana za pomocą wyrażenia lambda jest wartością zawartego w niej wyrażenia. Formy lambda mogą być używane wszędzie tam, gdzie zwykłe funkcje, jednak ograniczenia te sprawiają, że będą to bardzo ograniczona wersja normalnej funkcji. Oto przykład:

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

W zasadzie, konwencja Pythona, podobnie jak ma to miejsce w innych językach, zachęca do korzystania z nazwanych funkcji zdefiniowanych w tym samym zasięgu. Jest to dopuszczalne, gdyż funkcje zdefiniowane lokalnie implementują pełnie funkcjonalności domknięć, a Pythonie są prawie tak samo wydajne jak lambdy. Można powiedzieć, że w poniższy przykładzie wbudowana funkcja potęgowania poddana została technice curry:

>>> def make_pow(n):
... def fixed_exponent_pow(x):
... return pow(x, n)
... return fixed_exponent_pow
...
>>> sqr = make_pow(2)
>>> print (sqr(10))
100
>>> cub = make_pow(3)
>>> print (cub(10))
1000

W GNU R funkcje anonimowe są definiowane z użyciem składni function(argument-list)expression.

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

Rubin obsługuje funkcje anonimowe za pomocą struktury składniowej, zwanej blokiem. Istnieją dwa typy danych dla bloków. Proc zachowują się podobnie do domknięć, a lambda zachowują się bardziej jak funkcje anonimowa[18]. Blok przekazywany do metody może w pewnych sytuacjach być konwertowany do postaci Proc.

irb(main):001:0> # Przyklad 1:
irb(main):002:0* # Funkcja w pelni anonimowa z uzyciem bloku.
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 } # Sortuj po czesci ulamkowej, ignoruj czesc calkowita.
=> [24.1, 16.2, 48.3, 32.4, 8.5]
irb(main):005:0> # Przyklad 2:
irb(main):006:0* # Funkcje pierwszego rzedu jako jednoznaczny obiekt klasy proc
irb(main):007:0* ex = Proc.new { puts "Hello, world!" }
=> #
irb(main):008:0> ex.call
Hello, world!
=> nil
irb(main):009:0> # Przyklad 3:
irb(main):010:0* # Funkcja, ktora zwraca funkcje lambda z parametrami
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)
=> #
irb(main):015:0> multiple_four.call(16)
=> true
irb(main):016:0> multiple_four[15]
=> false

W Scala, funkcje anonimowe wykorzystują następującą składnię:[19]

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

W pewnych kontekstach, na przykład gdy funkcja anonimowa jest parametrem przekazywanym do innej funkcji, kompilator może przewidzieć typy parametrów funkcji anonimowej, i mogą być one pominięte w składni. W takich sytuacjach można również użyć wersji skrótowej dla funkcji anonimowych z użyciem znaku podkreślenia, wprowadzając w ten sposób nienazwane parametry.

 val list = List(1, 2, 3, 4)
 list.reduceLeft( (x, y) => x + y )
// Tutaj kompilator potrafi dojsc do typow x i y : Int, Int
// Tak wiec, nie wymagane sa adnotacje parametrow funkcji anonimowych

 list.reduceLeft( _ + _ )
// Podkreslenie oznacza nowy, nienazwany parametr funkcji anonimowej
// To prowadzi do nawet prostszego ekwiwalentu funkcji anonimowej powyzej

Smalltalk

edytuj

W języku Smalltalk anonimowe funkcje nazywane są blokami

[ :x | x*x ] value: 4
zwraca 16

W Swift, funkcje anonimowe nazywane są domknięciami[20]. Składnia ma następującą formę:

{ (parameters) -> returnType in
  statement
}

Na przykład:

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

Dla zwięzłości i ekspresywności, jeśli typy parametrów oraz typ wartości zwracanej da się wywnioskować w czasie kompilacji to mogą one być pominięte:

{ s1, s2 in return s1 > s2 }

Podobnie, Swift obsługuje również niejawne instrukcje return dla domknięć z jedną instrukcją:

{ s1, s2 in s1 > s2 }

Wreszcie, nazwy parametrów mogą być również pominięte. W takim przypadku można się do nich odnosić za pomocą tzw. skrótowych nazw argumentów, składających się z symbolu $, oraz ich pozycji (na przykład, $0, $1, $2 itd.):

{ $0 > $1 }

W Tcl, zastosowanie funkcji anonimowej do podniesienia liczby 2 do kwadratu wygląda następująco:[21]

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

Należy zauważyć, że w tym przykładzie biorą udział dwie „potencjalne funkcje” języka TCL. Najbardziej uniwersalny jest sposób o nazwie przedrostka polecenia (ang. command prefix), i jeśli zmienna f przechowuje taką funkcję, wtedy wywołanie funkcji f(x) będzie wyglądało następująco:

{*}$f $x

gdzie {*} - to prefiks rozszerzenia (nowość w TCL 8.5). Prefiks polecenia w powyższym przykładzie to apply {x {x {expr {$x*$x}}}. Nazwy poleceń mogą być powiązane z prefiksami z użyciem polecenia interp alias. Prefiksy poleceń obsługują currying. Prefiksy poleceń są bardzo powszechne w API TCL.

Inny kandydat na „funkcję” w TCL bywa zwykle nazywany „lambda”, i jest obecny w powyższym przykładzie jako {x {expr {$x*$x}}}. To ta część pobiera skompilowaną postać funkcji anonimowej, jednak może ona być wywołana tylko za pomocą przekazania polecenia apply. Wyrażenia lambda nie wspierają currying'u, chyba że w połączeniu z apply, aby utworzyć prefiks wyrażenia. Lambda rzadko bywają częścią API TCL.

Visual Basic .NET

edytuj

Visual Basic.NET 2008 wprowadził funkcje anonimowe w postaci wyrażeń lambda. W połączeniu z niejednoznacznym modelem kodowania, VB zapewnia ekonomiczną składnie funkcji anonimowych. Jak w Pythonie, w VB.NET, funkcje anonimowe powinny być definiowane w jednej linii; nie mogą one być złożonymi instrukcjami. Ponadto funkcje anonimowe w VB.NET muszą być typu „Function” - muszą zwracać wartość.

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

Visual Basic.NET 2010 dodał wsparcie dla wielowierszowych wyrażeń lambda i funkcji anonimowych, bez wartości zwracanej. Poniżej przykład funkcji do wykorzystania w wątku (Thread).

Dim t As New System.Threading.Thread(Sub()
    For n as Integer = 0 to 10   'Licz do 10
        Console.WriteLine(n)     'Wypisuj kazda liczbe
    Next
    End Sub)
t.Start()

Zobacz też

edytuj

Przypisy

edytuj
  1. "Higher order functions". learnyouahaskell.com
  2. Fernandez, Maribel (2009), Models of Computation: An Introduction to Computability Theory, Undergraduate Topics in Computer Science, Springer Science & Business Media, p. 33, ISBN 978-1-84882-434-8, The Lambda calculus ... was introduced by Alonzo Church in the 1930s as a precise notation for a theory of anonymous functions
  3. "Lecture 29: Fixpoints and Recursion".
  4. "Bash lambda".
  5. "Closure support". getrailo.org. [zarchiwizowane z tego adresu (2014-01-06)]..
  6. "Whats new in ColdFusion 10". [dostęp 2016-02-10]. [zarchiwizowane z tego adresu (2014-01-06)].
  7. "Managed COBOL Reference".
  8. "Quotations - Factor Documentation"
  9. Järvi, Jaakko; Powell, Gary (n.d.
  10. What's New in JDK 8 [online], www.oracle.com [dostęp 2017-11-18].
  11. a b The Java Tutorials: Lambda Expressions, docs.oracle.com
  12. "Programming in Lua - More about Functions".
  13. http://php.net/create_function the top of the page indicates this with "(PHP 4 >= 4.0.1, PHP 5)"
  14. PHP: create_function - Manual [online], www.php.net [dostęp 2024-10-08] (ang.).
  15. PHP: create_function - Manual [online], www.php.net [dostęp 2024-10-08] (ang.).
  16. PHP: rfc:closures [online], wiki.php.net [dostęp 2019-04-07] [zarchiwizowane z adresu 2012-12-20].
  17. "Anonymous Predicates". in Visual Prolog Language Reference
  18. Sosinski, Robert (2008-12-21).
  19. Zarchiwizowana kopia. [dostęp 2016-02-10]. [zarchiwizowane z tego adresu (2013-07-23)].
  20. The Swift Programming Language (Swift 4): Closures [online], developer.apple.com [dostęp 2017-11-18] (ang.).
  21. apply manual page, retrieved 2012-09-06.

Linki zewnętrzne

edytuj