function - programming - closures übersetzung




Was ist der Unterschied zwischen einer "Schließung" und einem "Lambda"? (7)

Könnte jemand erklären? Ich verstehe die grundlegenden Konzepte dahinter, aber ich sehe sie oft synonym verwendet und ich werde verwirrt.

Und jetzt, wo wir hier sind, wie unterscheiden sie sich von einer normalen Funktion?


Aus der Sicht von Programmiersprachen sind das zwei völlig verschiedene Dinge.

Grundsätzlich brauchen wir für eine Turing-Komplettsprache nur sehr wenige Elemente, zB Abstraktion, Anwendung und Reduktion. Abstraktion und Anwendung bietet die Möglichkeit, den Lamdba-Ausdruck aufzubauen, und Reduktion definiert die Bedeutung des Lambda-Ausdrucks.

Lambda bietet eine Möglichkeit, den Berechnungsprozess zu abstrahieren. Um beispielsweise die Summe zweier Zahlen zu berechnen, kann ein Prozess abstrahiert werden, der zwei Parameter x, y und die Rückgabe x + y akzeptiert. Im Schema können Sie es als schreiben

(lambda (x y) (+ x y))

Sie können die Parameter umbenennen, aber die abgeschlossene Aufgabe ändert sich nicht. In fast allen Programmiersprachen können Sie dem Lambda-Ausdruck einen Namen geben, die Funktionen genannt werden. Aber es gibt keinen großen Unterschied, sie können konzeptionell nur als Syntax Zucker betrachtet werden.

OK, jetzt stell dir vor, wie das implementiert werden kann. Immer wenn wir den Lambda-Ausdruck auf einige Ausdrücke anwenden, z

((lambda (x y) (+ x y)) 2 3)

Wir können die Parameter einfach durch den auszuwertenden Ausdruck ersetzen. Dieses Modell ist bereits sehr leistungsfähig. Aber dieses Modell ermöglicht es uns nicht, die Werte von Symbolen zu ändern, z. B. können wir den Statuswechsel nicht nachahmen. Daher brauchen wir ein komplexeres Modell. Um es kurz zu machen, wenn wir die Bedeutung des Lambda-Ausdrucks berechnen wollen, setzen wir das Symbolpaar und den entsprechenden Wert in eine Umgebung (oder Tabelle). Dann wird der Rest (+ xy) ausgewertet, indem die entsprechenden Symbole in der Tabelle nachgeschlagen werden. Wenn wir jetzt einige Primitive bereitstellen, die direkt mit der Umgebung arbeiten, können wir die Statusänderungen modellieren!

Mit diesem Hintergrund überprüfen Sie diese Funktion:

(lambda (x y) (+ x y z))

Wir wissen, dass xy ​​bei der Auswertung des Lambda-Ausdrucks in eine neue Tabelle eingebunden wird. Aber wie und wo können wir nach oben schauen? Tatsächlich wird z eine freie Variable genannt. Es muss eine äußere Umgebung geben, die z enthält. Andernfalls kann die Bedeutung des Ausdrucks nicht nur durch Bindung von x und y bestimmt werden. Um dies zu verdeutlichen, können Sie im Schema wie folgt schreiben:

((lambda (z) (lambda (x y) (+ x y z))) 1)

Also wäre z in einer äußeren Tabelle an 1 gebunden. Wir erhalten immer noch eine Funktion, die zwei Parameter akzeptiert, aber die wahre Bedeutung hängt auch von der äußeren Umgebung ab. Mit anderen Worten schließt sich die äußere Umgebung auf die freien Variablen. Mit Hilfe von set! Können wir die Funktion stateful machen, dh sie ist keine Funktion im Sinne von Mathe. Was es zurückgibt, hängt nicht nur von der Eingabe ab, sondern auch von z.

Das wissen Sie schon sehr gut, eine Methode von Objekten beruht fast immer auf dem Zustand von Objekten. Manche Leute sagen deshalb, dass "Verschlüsse die Objekte des armen Menschen sind". Aber wir können auch Objekte als Verschlusssachen für Arme betrachten, da wir wirklich erstklassige Funktionen mögen.

Ich benutze Schema, um die Ideen zu veranschaulichen, weil dieses Schema eine der frühesten Sprachen ist, die echte Schließungen hat. Alle Materialien sind hier in SICP Kapitel 3 viel besser dargestellt.

Lambda und Schließung sind also wirklich unterschiedliche Konzepte. Ein Lambda ist eine Funktion. Eine Schließung ist ein Lambda-Paar und die entsprechende Umgebung, die das Lambda schließt.


Das Konzept ist das gleiche wie oben beschrieben, aber wenn Sie von PHP-Hintergrund sind, erklären Sie dies mit PHP-Code weiter.

$input = array(1, 2, 3, 4, 5);
$output = array_filter($input, function ($v) { return $v > 2; });

Funktion ($ v) {return $ v> 2; } ist die Lambda-Funktionsdefinition. Wir können es sogar in einer Variablen speichern, damit es wiederverwendbar ist:

$max = function ($v) { return $v > 2; };

$input = array(1, 2, 3, 4, 5);
$output = array_filter($input, $max);

Was nun, wenn Sie die maximal zulässige Anzahl im gefilterten Array ändern möchten? Sie müssten eine andere Lambda-Funktion schreiben oder eine Closure erstellen (PHP 5.3):

$max_comp = function ($max) {
  return function ($v) use ($max) { return $v > $max; };
};

$input = array(1, 2, 3, 4, 5);
$output = array_filter($input, $max_comp(2));

Eine Closure ist eine Funktion, die in ihrer eigenen Umgebung ausgewertet wird, die über eine oder mehrere gebundene Variablen verfügt, auf die beim Aufruf der Funktion zugegriffen werden kann. Sie kommen aus der funktionalen Programmierwelt, in der eine Reihe von Konzepten im Spiel sind. Verschlüsse sind wie Lambda-Funktionen, aber intelligenter in dem Sinne, dass sie mit Variablen aus der äußeren Umgebung interagieren können, in der die Schließung definiert ist.

Hier ist ein einfacheres Beispiel für die PHP-Schließung:

$string = "Hello World!";
$closure = function() use ($string) { echo $string; };

$closure();

Schön in diesem Artikel erklärt.


Ein Lambda ist nur eine anonyme Funktion - eine Funktion, die ohne Namen definiert ist. In einigen Sprachen, z. B. Scheme, entsprechen sie benannten Funktionen. Tatsächlich wird die Funktionsdefinition neu geschrieben, indem ein Lambda intern an eine Variable gebunden wird. In anderen Sprachen, wie Python, gibt es einige (ziemlich unnötige) Unterschiede zwischen ihnen, aber sie verhalten sich ansonsten genauso.

Eine Schließung ist eine Funktion, die sich über die Umgebung schließt, in der sie definiert wurde. Dies bedeutet, dass er auf Variablen zugreifen kann, die nicht in seiner Parameterliste enthalten sind. Beispiele:

def func(): return h
def anotherfunc(h):
   return func()

Dies führt zu einem Fehler, da func nicht in einer anderen Umgebung über die Umgebung anotherfunc - h ist nicht definiert. func schließt nur über die globale Umgebung. Das wird funktionieren:

def anotherfunc(h):
    def func(): return h
    return func()

Denn hier ist anotherfunc in einer anderen anotherfunc definiert, und in python 2.3 und höher (oder in einer anotherfunc Zahl), wenn sie fast geschlossen sind (Mutation funktioniert immer noch nicht), bedeutet das, dass sie sich über die Umgebung einer anderen anotherfunc schließt und darauf zugreifen kann Variablen innerhalb davon. In Python 3.1+ funktioniert die Mutation auch mit dem nonlocal Schlüsselwort .

Ein weiterer wichtiger Punkt - func wird sich weiterhin über die Umgebung eines anderen anotherfunc , auch wenn es nicht mehr in einer anderen Funktion ausgewertet anotherfunc . Dieser Code funktioniert auch:

def anotherfunc(h):
    def func(): return h
    return func

print anotherfunc(10)()

Dies wird 10 drucken.

Dies hat, wie Sie bemerken, nichts mit Lambda s zu tun - es sind zwei verschiedene (wenn auch verwandte) Konzepte.


Ein Lambda ist nur eine anonyme Funktion - eine Funktion, die ohne Namen definiert wird. Eine Schließung ist eine Funktion, die über die Umgebung schließt, in der sie definiert wurde. Dies bedeutet, dass er auf Variablen zugreifen kann, die nicht in seiner Parameterliste enthalten sind.


Nicht alle Verschlüsse sind Lambdas und nicht alle Lambdas sind Verschlüsse. Beides sind Funktionen, aber nicht unbedingt in der Art, wie wir es gewohnt sind zu wissen.

Ein Lambda ist im Wesentlichen eine Funktion, die inline definiert wird und nicht die Standardmethode zum Deklarieren von Funktionen. Lambdas können häufig als Objekte herumgereicht werden.

Eine Schließung ist eine Funktion, die ihren umgebenden Zustand umschließt, indem sie auf Felder außerhalb ihres Körpers verweist. Der eingeschlossene Zustand bleibt über Aufrufe des Verschlusses erhalten.

In einer objektorientierten Sprache werden Schließungen normalerweise durch Objekte bereitgestellt. Einige OO-Sprachen (z. B. C #) implementieren jedoch spezielle Funktionen, die näher an der Definition von Closures liegen, die von rein funktionalen Sprachen (z. B. Lisp) bereitgestellt werden, die keine Objekte enthalten, die den Status einschließen.

Interessant ist, dass die Einführung von Lambdas und Closures in C # die funktionale Programmierung der Mainstream-Nutzung näher bringt.


So einfach ist das: Lambda ist ein Sprachkonstrukt, also einfach Syntax für anonyme Funktionen; Eine Schließung ist eine Technik, um sie zu implementieren - oder irgendeine erstklassige Funktion, namentlich genannt oder anonym.

Genauer gesagt, eine Schließung ist, wie eine erstklassige Funktion zur Laufzeit dargestellt wird, als ein Paar ihres "Codes" und einer Umgebung, die über alle nicht-lokalen Variablen, die in diesem Code verwendet werden, "schließt". Auf diese Weise sind diese Variablen auch dann noch zugänglich, wenn die äußeren Bereiche, aus denen sie stammen, bereits verlassen wurden.

Leider gibt es viele Sprachen, die Funktionen nicht als erstklassige Werte unterstützen oder nur in verkrüppelter Form unterstützen. So benutzen Leute oft den Begriff "Schließung", um "das echte Ding" zu unterscheiden.


Wenn die meisten Leute an Funktionen denken, denken sie an benannte Funktionen :

function foo() { return "This string is returned from the 'foo' function"; }

Diese werden natürlich namentlich genannt:

foo(); //returns the string above

Mit Lambda-Ausdrücken können Sie anonyme Funktionen haben :

 @foo = lambda() {return "This is returned from a function without a name";}

Im obigen Beispiel können Sie das Lambda über die Variable aufrufen, der es zugewiesen wurde:

foo();

Nützlicher als das Zuweisen anonymer Funktionen zu Variablen, leiten Sie sie jedoch an oder von Funktionen höherer Ordnung weiter, dh Funktionen, die andere Funktionen akzeptieren / zurückgeben. In vielen Fällen ist das Benennen einer Funktion nicht erforderlich:

function filter(list, predicate) 
 { @filteredList = [];
   for-each (@x in list) if (predicate(x)) filteredList.add(x);
   return filteredList;
 }

//filter for even numbers
filter([0,1,2,3,4,5,6], lambda(x) {return (x mod 2 == 0)}); 

Eine Schließung kann eine benannte oder anonyme Funktion sein, ist aber als solche bekannt, wenn sie Variablen in dem Bereich, in dem die Funktion definiert ist, "schließt", dh der Abschluss bezieht sich immer noch auf die Umgebung mit beliebigen äußeren Variablen, die in der Umgebung verwendet werden Schließung selbst. Hier ist eine benannte Schließung:

@x = 0;

function incrementX() { x = x + 1;}

incrementX(); // x now equals 1

Das scheint nicht viel zu sein, aber was wäre, wenn das alles in einer anderen Funktion wäre und du incrementX an eine externe Funktion übergeben hättest?

function foo()
 { @x = 0;

   function incrementX() 
    { x = x + 1;
      return x;
    }

   return incrementX;
 }

@y = foo(); // y = closure of incrementX over foo.x
y(); //returns 1 (y.x == 0 + 1)
y(); //returns 2 (y.x == 1 + 1)

So erhalten Sie statusbehaftete Objekte in der funktionalen Programmierung. Da die Benennung von "incrementX" nicht benötigt wird, können Sie in diesem Fall ein Lambda verwenden:

function foo()
 { @x = 0;

   return lambda() 
           { x = x + 1;
             return x;
           };
 }






closures