Was ist ein Lambda und warum ist es nützlich? [geschlossen]


56

Bisher hörte ich von:

  • Lambda-Kalkül
  • Lambda-Programmierung
  • Lambda-Ausdrücke
  • Lambda funktioniert

Was alles mit funktionaler Programmierung zu tun zu haben scheint ...

Anscheinend wird es in C ++ 1x integriert, so dass ich es jetzt besser verstehen könnte:

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

Kann jemand kurz definieren, was Lambdas Dinge sind und wo es nützlich sein kann?


2
Beachten Sie, dass die Terminologie in der Vergangenheit von der Suche nach einer guten Möglichkeit stammt, über die durch einen Ausdruck dargestellte Funktion zu sprechen. Die durch x + 1 dargestellte Funktion wird dann Lambda x geschrieben. x + 1.
Kasterma

In Lambda-Form isst eine Funktion eine andere Funktion und / oder einen Eingabewert und erzeugt eine andere Funktion. Dies setzt sich fort, bis eine Funktion eine Lösung erzeugt. Auch Alligatoreier .
SD

Es ist alles Griechisch für mich. Ich glaube, ich gehe einen Gyro haben, ich mag Lamm, duh.

Antworten:


44
  • Lambda-Kalkül

Die Lambda-Berechnung ist ein Berechnungsmodell, das in den 30er Jahren von Alonzo Church erfunden wurde. Die Syntax und die Semantik der meisten funktionalen Programmiersprachen sind direkt oder indirekt von der Lambda-Rechnung inspiriert.

Der Lambda-Kalkül hat in seiner grundlegendsten Form zwei Operationen: Abstraktion (Erstellen einer (anonymen) Funktion) und Anwendung (Anwenden einer Funktion). Die Abstraktion erfolgt mit dem λ-Operator, der dem Lambda-Kalkül seinen Namen gibt.

  • Lambda-Ausdrücke
  • Lambda funktioniert

Anonyme Funktionen werden oft als "Lambdas", "Lambda-Funktionen" oder "Lambda-Ausdrücke" bezeichnet, da λ, wie oben erwähnt, das Symbol für die Erstellung anonymer Funktionen im Lambda-Kalkül war (und das Wort lambdafür die Erstellung anonymer Funktionen in vielen lisp verwendet wird -basierte Sprachen aus dem gleichen Grund).

  • Lambda-Programmierung

Dies ist kein allgemein gebräuchlicher Begriff, aber ich gehe davon aus, dass dies das Programmieren mit anonymen Funktionen oder das Programmieren mit Funktionen höherer Ordnung bedeutet.


Ein bisschen mehr Informationen über Lambdas in C ++ 0x, ihre Motivation und ihre Beziehung zu Funktionszeigern (eine Menge davon ist wahrscheinlich eine Wiederholung dessen, was Sie bereits wissen, aber ich hoffe, es hilft, die Motivation von Lambdas zu erklären und wie sie sich unterscheiden von Funktionszeigern):

Funktionszeiger, die es in C bereits gab, sind sehr nützlich, um z. B. eine Vergleichsfunktion an eine Sortierfunktion zu übergeben. Ihre Nützlichkeit ist jedoch begrenzt:

Wenn Sie beispielsweise einen Vektor von Vektoren nach dem ith-Element jedes Vektors sortieren möchten (wobei ies sich um einen Laufzeitparameter handelt), können Sie dies nicht mit einem Funktionszeiger lösen. Eine Funktion, die zwei Vektoren nach ihrem ith-Element vergleicht, müsste drei Argumente ( iund die beiden Vektoren) annehmen , während die Sortierfunktion eine Funktion benötigt, die zwei Argumente annimmt. Was wir brauchen, ist eine Möglichkeit, das Argument irgendwie ian die Funktion zu übergeben, bevor es an die Sortierfunktion übergeben wird, aber wir können dies nicht mit einfachen C-Funktionen tun.

Um dies zu lösen, führte C ++ das Konzept der "Funktionsobjekte" oder "Funktoren" ein. Ein Funktor ist im Grunde ein Objekt, das eine operator()Methode hat. Jetzt können wir eine Klasse definieren CompareByIthElement, die das Argument ials Konstruktorargument und dann die beiden zu vergleichenden Vektoren als Argumente für die operator()Methode verwendet. Um einen Vektor von Vektoren nach dem ith-Element zu sortieren, können wir jetzt ein CompareByIthElementObjekt mit ials Argument erstellen und dieses Objekt dann an die Sortierfunktion übergeben.

Da Funktionsobjekte nur Objekte und keine technischen Funktionen sind (obwohl sie sich wie diese verhalten sollen), können Sie einen Funktionszeiger nicht auf ein Funktionsobjekt verweisen lassen (Sie können natürlich einen Zeiger auf ein Funktionsobjekt haben, aber es hätte einen Typ wie CompareByIthElement*und wäre somit kein Funktionszeiger).

Die meisten Funktionen in der C ++ - Standardbibliothek, die Funktionen als Argumente verwenden, werden mithilfe von Vorlagen definiert, sodass sie sowohl mit Funktionszeigern als auch mit Funktionsobjekten arbeiten.

Nun zu Lambdas:

Das Definieren einer ganzen Klasse zum Vergleichen durch das ith-Element ist etwas ausführlich, wenn Sie sie nur einmal zum Sortieren eines Vektors verwenden. Selbst wenn Sie nur einen Funktionszeiger benötigen, ist die Definition einer benannten Funktion suboptimal, wenn sie nur einmal verwendet wird, da a) sie den Namespace verschmutzt und b) die Funktion normalerweise sehr klein ist und es nicht wirklich eine gibt Ein guter Grund, die Logik in eine eigene Funktion zu abstrahieren (ansonsten können Sie keine Funktionszeiger haben, ohne eine Funktion zu definieren).

Um dies zu beheben, wurden Lambdas eingeführt. Lambdas sind Funktionsobjekte, keine Funktionszeiger. Wenn Sie ein Lambda-Literal verwenden, wird ein ähnlicher [x1, x2](y1,y2){bla}Code generiert, der im Grunde Folgendes bewirkt:

  1. Definieren Sie eine Klasse mit zwei Mitgliedsvariablen ( x1und x2) und einem operator()mit den Argumenten ( y1und y2) und dem Hauptteil bla.
  2. Erstellen Sie eine Instanz der Klasse, die Einstellung der Elementvariablen x1und x2auf die Werte der Variablen x1und x2zur Zeit in ihrem Umfang.

Lambdas verhalten sich also wie Funktionsobjekte, mit der Ausnahme, dass Sie nicht auf die Klasse zugreifen können, die generiert wurde, um ein Lambda auf eine andere Weise als mit dem Lambda zu implementieren. Folglich akzeptiert jede Funktion, die Funktoren als Argumente akzeptiert (was im Grunde genommen jede Nicht-C-Funktion in der Standardbibliothek bedeutet), Lambdas, aber jede Funktion, die nur Funktionszeiger akzeptiert, nicht.


Sollen anonyme Funktionen mit Funktionszeigern verwendet werden? Wenn nicht, was ist der Unterschied?
jokoon

1
@jokoon: Nein, anonyme Funktionen können nicht als Parameter an Funktionen übergeben werden, die nur Funktionszeiger verwenden. Die meisten Funktionen, die Funktionen als Argumente verwenden, werden mithilfe von Vorlagen definiert, sodass sie alle Arten von Funktionsobjekten als Argument verwenden können, nicht nur Funktionszeiger. Das heißt, an den meisten Stellen, an denen Sie std::sortbeispielsweise Funktionszeiger verwenden können , können Sie stattdessen anonyme Funktionen verwenden. Wenn Sie jedoch eine Funktion definieren, die eine anonyme Funktion als Argument verwenden soll, müssen Sie entweder eine Vorlage oder std::functionden Typ des Arguments verwenden.
2.

Ein Funktionszeiger kann also kein Lambda enthalten ...
jokoon

1
+1 Hervorragende Erklärung - das konnte ich auch nicht herausfinden.
Michael K

2
Ich bin mit Michael dabei. Das ist sehr umfassend. +1von mir.
sbi

18

Grundsätzlich sind Lambda-Funktionen Funktionen, die Sie "on the fly" erstellen. In C ++ 1x könnten sie verwendet werden, um die Unterstützung für die funktionale Programmierung zu verbessern:

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

Dies führt in etwa zu einem ähnlichen Code:

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

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

Wenn Sie some_functornur für diesen einen Aufruf benötigen std::for_each(), dann hat diese Lambda-Funktion mehrere Vorteile gegenüber:

  • Was in der Schleife gemacht wird, wird genau dort angegeben, wo die Schleifenfunktion aufgerufen wird
  • Es befreit Sie davon, einen Teil des Kesselschildcodes zu schreiben
  • Es gibt keinen Functor, der in einem Namespace-Bereich herumliegt, sodass sich jeder, der sich den Code ansieht, fragt, wofür er benötigt wird

7

Eine Lambda-Funktion ist ein anderer Name für eine anonyme Funktion - im Wesentlichen eine Funktion ohne Namen.

Normalerweise verwenden Sie dies in Sprachen, in denen Sie die Funktion nur einmal verwenden müssen. Zum Beispiel statt

def add(a, b)
  return a+b

und dann diese Funktion in eine andere Funktion wie diese übergeben

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

Mit einem Lambda würden Sie einfach tun

reduce(lambda x, y: a+b, [5,3,2])
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.