Rachunek lambda to model obliczeniowy wynaleziony przez Alonzo Church w latach 30. Składnia i semantyka większości funkcjonalnych języków programowania są bezpośrednio lub pośrednio inspirowane rachunkiem lambda.
Rachunek lambda w najbardziej podstawowej formie ma dwie operacje: Abstrakcję (tworzenie (anonimowej) funkcji) i aplikację (zastosowanie funkcji). Abstrakcja jest wykonywana za pomocą operatora λ, nadając rachunku lambda swoją nazwę.
- Wyrażenia lambda
- Funkcje Lambda
Funkcje anonimowe są często nazywane „lambdami”, „funkcjami lambda” lub „wyrażeniami lambda”, ponieważ, jak powiedziałem powyżej, λ było symbolem tworzenia funkcji anonimowych w rachunku lambda (a słowo lambda
to jest używane do tworzenia funkcji anonimowych w wielu seplenieniach języki oparte na tym samym celu).
Nie jest to termin powszechnie używany, ale zakładam, że oznacza to programowanie przy użyciu anonimowych funkcji lub programowanie przy użyciu funkcji wyższego rzędu.
Trochę więcej informacji na temat lambd w C ++ 0x, ich motywacji i ich związku ze wskaźnikami funkcyjnymi (wiele z nich jest prawdopodobnie powtórzeniem tego, co już wiesz, ale mam nadzieję, że pomoże to wyjaśnić motywację lambdas i ich różnice ze wskaźników funkcji):
Wskaźniki funkcji, które już istniały w C, są bardzo przydatne np. Do przekazania funkcji porównawczej do funkcji sortującej. Istnieją jednak ograniczenia ich przydatności:
Na przykład, jeśli chcesz posortować wektor wektorów według i
elementu th każdego wektora (gdzie i
jest parametrem czasu wykonywania), nie możesz tego rozwiązać za pomocą wskaźnika funkcji. Funkcja, która porównuje dwa wektory według ich i
elementu, musiałaby wziąć trzy argumenty ( i
i dwa wektory), ale funkcja sortująca wymagałaby funkcji przyjmującej dwa argumenty. Potrzebujemy sposobu, aby jakoś dostarczyć argument i
do funkcji przed przekazaniem jej do funkcji sortowania, ale nie możemy tego zrobić za pomocą zwykłych funkcji C.
Aby rozwiązać ten problem, C ++ wprowadził pojęcie „obiektów funkcji” lub „funktorów”. Funktor to w zasadzie obiekt posiadający operator()
metodę. Teraz możemy zdefiniować klasę CompareByIthElement
, która przyjmuje argument i
jako argument konstruktora, a następnie przyjmuje dwa wektory do porównania jako argumenty do operator()
metody. Aby posortować wektor wektorów według i
tego elementu, możemy teraz utworzyć CompareByIthElement
obiekt i
jako argument, a następnie przekazać ten obiekt do funkcji sortowania.
Ponieważ obiekty funkcyjne są tylko obiektami, a nie funkcjami technicznymi (nawet jeśli mają się tak zachowywać), nie można ustawić wskaźnika funkcji na obiekt funkcji (można oczywiście mieć wskaźnik na obiekt funkcji, ale to miałby typ podobny, CompareByIthElement*
a zatem nie byłby wskaźnikiem funkcji).
Większość funkcji w standardowej bibliotece C ++, które przyjmują funkcje jako argumenty, są definiowane przy użyciu szablonów, dzięki czemu działają one ze wskaźnikami funkcji oraz obiektami funkcji.
Teraz do lambdas:
Zdefiniowanie całej klasy do porównania za pomocą i
elementu th jest nieco zbyt szczegółowe, jeśli kiedykolwiek użyjesz jej tylko raz do posortowania wektora. Nawet w przypadku, gdy potrzebujesz tylko wskaźnika funkcji, zdefiniowanie nazwanej funkcji jest nieoptymalne, jeśli zostanie użyte tylko raz, ponieważ a) zanieczyszcza przestrzeń nazw ib) funkcja zwykle będzie bardzo mała i tak naprawdę nie ma dobry powód do wyodrębnienia logiki we własną funkcję (poza tym, że nie można mieć wskaźników funkcji bez zdefiniowania funkcji).
Aby to naprawić, wprowadzono lambdas. Lambdy są obiektami funkcyjnymi, a nie wskaźnikami funkcji. Jeśli użyjesz literału typu lambda, [x1, x2](y1,y2){bla}
generowany jest kod, który zasadniczo wykonuje następujące czynności:
- Zdefiniuj klasę, która ma dwie zmienne składowe (
x1
i x2
) i an operator()
z argumentami ( y1
i y2
) i treścią bla
.
- Utwórz instancję klasy, ustawiając zmienne składowe
x1
oraz x2
wartości zmiennych x1
i x2
obecnie w zasięgu.
Zatem lambdy zachowują się jak obiekty funkcyjne, z tym wyjątkiem, że nie można uzyskać dostępu do klasy, która została wygenerowana w celu zaimplementowania lambda w jakikolwiek inny sposób niż użycie lambda. W związku z tym każda funkcja, która akceptuje funktory jako argumenty (zasadniczo oznacza dowolną funkcję inną niż C w bibliotece standardowej), zaakceptuje lambdas, ale żadna funkcja akceptująca tylko wskaźniki funkcji nie.