Co to jest lambda i dlaczego miałaby być przydatna? [Zamknięte]

56

Do tej pory słyszałem o:

  • Rachunek Lambda
  • Programowanie lambda
  • Wyrażenia lambda
  • Funkcje Lambda

Co wydaje się mieć związek z programowaniem funkcjonalnym ...

Najwyraźniej zostanie zintegrowany z C ++ 1x, więc lepiej zrozumiem teraz:

http://en.wikipedia.org/wiki/C%2B%2B0x#Lambda_functions_and_expressions

Czy ktoś może krótko zdefiniować, czym są rzeczy lambdas i podać, gdzie mogą być przydatne?

żart
źródło
2
Zauważ, że terminologia historycznie wywodzi się z potrzeby dobrego sposobu mówienia o funkcji reprezentowanej przez wyrażenie. Funkcja reprezentowana przez x + 1 jest następnie zapisywana jako lambda x. x + 1.
kasterma
W sposób lambda funkcja zjada inną funkcję i / lub wartość wejściową, tworzy inną funkcję. Trwa to do momentu, aż funkcja wygeneruje rozwiązanie. Również jajka aligatora .
SD
Nic z tego nie rozumiem. Myślę, że pójdę na żyroskop, lubię jagnię, duh.

Odpowiedzi:

44
  • Rachunek Lambda

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 lambdato jest używane do tworzenia funkcji anonimowych w wielu seplenieniach języki oparte na tym samym celu).

  • Programowanie lambda

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 ielementu th każdego wektora (gdzie ijest parametrem czasu wykonywania), nie możesz tego rozwiązać za pomocą wskaźnika funkcji. Funkcja, która porównuje dwa wektory według ich ielementu, musiałaby wziąć trzy argumenty ( ii dwa wektory), ale funkcja sortująca wymagałaby funkcji przyjmującej dwa argumenty. Potrzebujemy sposobu, aby jakoś dostarczyć argument ido 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 ijako argument konstruktora, a następnie przyjmuje dwa wektory do porównania jako argumenty do operator()metody. Aby posortować wektor wektorów według itego elementu, możemy teraz utworzyć CompareByIthElementobiekt ijako 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ą ielementu 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:

  1. Zdefiniuj klasę, która ma dwie zmienne składowe ( x1i x2) i an operator()z argumentami ( y1i y2) i treścią bla.
  2. Utwórz instancję klasy, ustawiając zmienne składowe x1oraz x2wartości zmiennych x1i x2obecnie 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.

sepp2k
źródło
Czy anonimowych funkcji można używać ze wskaźnikami funkcji? Jeśli nie, jaka jest różnica?
Jokoon
1
@ jokoon: Nie, anonimowe funkcje nie mogą być przekazywane jako parametry do funkcji, które pobierają tylko wskaźniki funkcji. Jednak większość funkcji, które przyjmują funkcje jako argumenty, są definiowane za pomocą szablonów, dzięki czemu mogą przyjmować dowolny obiekt funkcji jako argument, a nie tylko wskaźnik funkcji. Oznacza to, że w większości miejsc, w których można używać wskaźników funkcji ( std::sortna przykład), można zamiast tego korzystać z funkcji anonimowych. Jednak podczas definiowania funkcji, która powinna przyjmować funkcję anonimową jako argument, musisz użyć szablonu lub użyć jej std::functionjako typu argumentu.
sepp2k,
więc wskaźnik funkcji nie może zawierać lambda ...
Jokoon
1
+1 Doskonałe wyjaśnienie - ja też nie byłem w stanie się tego dowiedzieć.
Michael K
2
Jestem z Michaelem w tej sprawie. To jest bardzo wyczerpujące. +1ode mnie.
sbi,
18

Zasadniczo funkcje lambda to funkcje tworzone „w locie”. W C ++ 1x można je wykorzystać do poprawy obsługi programowania funkcjonalnego:

std::for_each( begin, end, [](int i){std::cout << i << '\n';} );

Z grubsza spowoduje to kod podobny do tego:

struct some_functor {
  void operator()(int i) {std::cout << i << '\n';}
};

std::for_each( begin, end, some_functor() );

Jeśli potrzebujesz some_functortylko jednego wywołania std::for_each(), funkcja lambda ma kilka zalet:

  • To, co zostało zrobione w pętli, jest określone dokładnie tam, gdzie wywoływana jest funkcja zapętlania
  • odciąża cię to od napisania kodu kotła
  • nie ma funktora leżącego w jakimś zakresie przestrzeni nazw, który sprawia, że ​​wszyscy patrząc na kod zastanawiają się, do czego jest potrzebny
sbi
źródło
7

Funkcja lambda to inna nazwa funkcji anonimowej - zasadniczo funkcja bez nazwy.

Zwykle używasz tego w językach, w których wystarczy użyć tej funkcji tylko raz. Na przykład zamiast

def add(a, b)
  return a+b

a następnie przekazanie tej funkcji do innej takiej funkcji

reduce(add, [5,3,2])

Z lambda po prostu byś to zrobił

reduce(lambda x, y: a+b, [5,3,2])
Martin Konecny
źródło