it-swarm.com.de

Was ist der Unterschied zwischen "Schließung" und "Lambda"?

Könnte jemand erklären? Ich verstehe die grundlegenden Konzepte dahinter, sehe sie aber oft austauschbar und verwirrt mich. 

Und jetzt, wo wir hier sind, wie unterscheiden sie sich von einer regulären Funktion?

725
sker

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

EIN schließung ist jede Funktion welche schließt sich das umgebung in dem es 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 dies nicht tut schließe vorbei Die Umgebung in anotherfunc - h ist nicht definiert. func schließt nur in der globalen Umgebung. Das wird funktionieren:

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

Denn hier ist func in anotherfunc definiert, und in Python 2.3 und höher (oder einer ähnlichen Zahl wie diesem) fast Schließungen korrekt (Mutation funktioniert immer noch nicht), bedeutet dies schließt sich anotherfuncs Umgebung und kann auf die darin enthaltenen Variablen zugreifen. In Python 3.1+ funktioniert die Mutation auch, wenn das nonlocal-Schlüsselwort verwendet wird.

Ein weiterer wichtiger Punkt - func - wird über der Umgebung von anotherfunc auch dann geschlossen, wenn sie nicht mehr in anotherfunc ausgewertet wird. Dieser Code wird auch funktionieren:

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

print anotherfunc(10)()

Dies wird 10 drucken.

Das hat, wie Sie feststellen, nichts damit zu tun lambdas - es gibt zwei verschiedene (wenn auch verwandte) Konzepte.

642
Claudiu

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 beim Namen 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";}

Mit dem 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 ist jedoch das Weiterleiten an oder von Funktionen höherer Ordnung, d. H. Funktionen, die andere Funktionen akzeptieren/zurückgeben. In vielen Fällen ist die Benennung 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)}); 

Ein close kann eine benannte oder anonyme Funktion sein, ist aber als solche bekannt, wenn sie Variablen im Gültigkeitsbereich, in dem die Funktion definiert ist, "schließt", dh der Closure bezieht sich immer noch auf die Umgebung mit äußeren Variablen werden im Verschluss selbst verwendet. 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 dies alles in einer anderen Funktion wäre und Sie incrementX an eine externe Funktion übergeben hätten?

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 Stateful-Objekte in der Funktionsprogrammierung. Da der Name "incrementX" nicht erforderlich ist, können Sie in diesem Fall ein Lambda verwenden:

function foo()
 { @x = 0;

   return lambda() 
           { x = x + 1;
             return x;
           };
 }
168
Mark Cidade

Nicht alle Schließungen sind Lambdas und nicht alle Lambdas sind Schließungen. Beides sind Funktionen, aber nicht notwendigerweise in der Art und Weise, wie wir sie kennen.

Ein Lambda ist im Wesentlichen eine Funktion, die inline definiert ist 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 einschließt, indem auf Felder außerhalb ihres Körpers Bezug genommen wird. Der eingeschlossene Zustand bleibt über die Aufrufe der Schließung hinweg erhalten.

In einer objektorientierten Sprache werden Schließungen normalerweise durch Objekte bereitgestellt. Einige OO -Sprachen (z. B. C #) implementieren jedoch eine spezielle Funktionalität, die der Definition von Schließungen näher kommt, die von reinen { funktionalen Sprachen (wie z. B. LISP) bereitgestellt werden und keine Objekte enthalten, die den Zustand einschließen.

Interessant ist, dass durch die Einführung von Lambdas und Closures in C # die funktionale Programmierung der normalen Nutzung näher gebracht wird.

52
Michael Brown

So einfach ist das: Lambda ist ein Sprachkonstrukt, d. H. Einfach Syntax für anonyme Funktionen. Ein Abschluss ist eine Technik zum Implementieren - oder beliebige erstklassige Funktionen, benannt oder anonym.

Genauer gesagt ist ein Abschluss, wie eine First-Class-Funktion zur Laufzeit dargestellt wird, als ein Paar aus "Code" und einer Umgebung, die "Closing" für alle nichtlokalen Variablen, die in diesem Code verwendet werden. Auf diese Weise sind diese Variablen auch dann noch verfügbar, wenn die äußeren Gültigkeitsbereiche, aus denen sie stammen, bereits verlassen wurden.

Leider gibt es viele Sprachen, die Funktionen nicht als erstklassige Werte oder nur in verkrüppelter Form unterstützen. Daher wird oft der Begriff "Schließung" verwendet, um "das Reale" zu unterscheiden.

14

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

Grundsätzlich brauchen wir für eine vollständige Turing-Sprache nur sehr begrenzte Elemente, z. Abstraktion, Anwendung und Reduktion. Abstraktion und Anwendung bieten die Möglichkeit, einen Lamdba-Ausdruck aufzubauen und die Bedeutung des Lambda-Ausdrucks zu reduzieren.

Mit Lambda können Sie den Berechnungsprozess abstrahieren. B. um die Summe zweier Zahlen zu berechnen, kann ein Prozess abstrahiert werden, der zwei Parameter x, y verwendet und x + y zurückgibt. Im Schema können Sie es als schreiben

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

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

OK, stellen Sie sich jetzt vor, wie dies umgesetzt werden kann. Wann immer 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 .. __ Dieses Modell ermöglicht es uns jedoch nicht, die Werte von Symbolen zu ändern, z. Wir können die Statusänderung nicht nachahmen. Daher brauchen wir ein komplexeres Modell. Um es kurz zu machen: Wann immer wir die Bedeutung des Lambda-Ausdrucks berechnen wollen, fügen wir das Symbolpaar und den entsprechenden Wert in eine Umgebung (oder eine Tabelle) ein. Dann wird der Rest (+ x y) ausgewertet, indem die entsprechenden Symbole in der Tabelle nachgeschlagen werden. Wenn wir nun einige Grundelemente zur direkten Bearbeitung der Umgebung bereitstellen, können wir die Statusänderungen modellieren!

Überprüfen Sie vor diesem Hintergrund diese Funktion:

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

Wir wissen, dass x y in einer neuen Tabelle gebunden wird, wenn wir den Lambda-Ausdruck auswerten. Aber wie und wo können wir nachschlagen? Eigentlich wird z als freie Variable bezeichnet. Es muss eine äußere Umgebung geben, die z enthält. Andernfalls kann die Bedeutung des Ausdrucks nicht nur durch die Bindung von x und y bestimmt werden. Um dies klar zu machen, können Sie im Schema Folgendes 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 tatsächliche Bedeutung dieser Funktion hängt auch von der äußeren Umgebung ab ... _ Mit anderen Worten, die äußere Umgebung schließt sich mit den freien Variablen ab. Mit Hilfe von set! Können wir die Funktion stateful machen, d. Was es zurückgibt, hängt nicht nur von der Eingabe ab, sondern auch von z.

Dies ist etwas, was Sie bereits sehr gut kennen. Eine Methode von Objekten hängt fast immer vom Zustand der Objekte ab. Deshalb sagen manche Leute "Verschlüsse sind Objekte des armen Mannes". Aber wir könnten Objekte auch als Verschlüsse des armen Mannes betrachten, da wir erstklassige Funktionen wirklich mögen.

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

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

12
Wei Qiu

Das Konzept ist dasselbe wie oben beschrieben, aber wenn Sie den Hintergrund PHP haben, wird dies anhand von PHP Code weiter erläutert. 

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

funktion ($ v) {return $ v> 2; } ist die Definition der Lambda-Funktion. Wir können es sogar in einer Variablen speichern, damit es wiederverwendet werden kann:

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

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

Was ist, wenn Sie die maximal zulässige Anzahl im gefilterten Array ändern möchten? Sie müssten eine weitere Lambda-Funktion schreiben oder einen Abschluss 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));

Ein Abschluss 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 Welt der funktionalen Programmierung, in der eine Reihe von Konzepten im Spiel sind. Verschlüsse sind wie Lambda-Funktionen, aber intelligenter in dem Sinne, dass sie die Möglichkeit haben, mit Variablen aus der Umgebung, in der der Verschluss definiert ist, zu interagieren.

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

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

$closure();

Schön in diesem Artikel erklärt.

7
Developer

Diese Frage ist alt und hat viele Antworten. Mit Java 8 und Official Lambda, die inoffizielle Schließungsprojekte sind, wird die Frage erneut aufgegriffen.

Die Antwort im Java-Kontext (über Lambdas und Closures - Was ist der Unterschied? ):

"Ein Abschluss ist ein Lambda-Ausdruck, der mit einer Umgebung gepaart ist, die jede seiner freien Variablen an einen Wert bindet. In Java werden Lambda-Ausdrücke mittels Schließungen implementiert, sodass die beiden Begriffe in der Community austauschbar verwendet werden."

6
philippe lhardy

Einfach gesagt, Schließung ist ein Trick über den Umfang, Lambda ist eine anonyme Funktion. Wir können den Verschluss mit Lambda eleganter realisieren und Lambda wird oft als Parameter verwendet, der an eine höhere Funktion übergeben wird

4
feilengcui008

Ein Lambda-Ausdruck ist nur eine anonyme Funktion. In einfachem Java können Sie es zum Beispiel so schreiben:

Function<Person, Job> mapPersonToJob = new Function<Person, Job>() {
    public Job apply(Person person) {
        Job job = new Job(person.getPersonId(), person.getJobDescription());
        return job;
    }
};

dabei wird die Klasse Function nur in Java-Code erstellt. Jetzt können Sie mapPersonToJob.apply(person) irgendwo anrufen, um es zu verwenden. das ist nur ein Beispiel. Das war ein Lambda, bevor es eine Syntax dafür gab. Lambda ist eine Abkürzung dafür.

Schließung:

ein Lambda wird zu einem Closure, wenn es auf Variablen außerhalb dieses Gültigkeitsbereichs zugreifen kann. Man kann sagen, dass es magisch ist, es kann sich auf magische Weise um die Umgebung wickeln, in der es erstellt wurde, und die Variablen außerhalb seines Gültigkeitsbereichs verwenden (äußerer Gültigkeitsbereich).

in Kotlin kann ein Lambda immer auf seinen Abschluss zugreifen (die Variablen, die sich in seinem äußeren Gültigkeitsbereich befinden).

1
j2emanue

Es hängt davon ab, ob eine Funktion eine externe Variable verwendet oder eine Operation ausführt. 

Externe Variablen - Variablen, die außerhalb des Funktionsumfangs definiert sind.

  • Lambda-Ausdrücke sind stateless , weil die Ausführung von Operationen von Parametern, internen Variablen oder Konstanten abhängt.

    Function<Integer,Integer> lambda = t -> {
        int n = 2
        return t * n 
    }
    
  • Closures hold state , weil externe Variablen (d. H. Variablen, die außerhalb des Funktionskörpers definiert sind) sowie Parameter und Konstanten zum Ausführen von Operationen verwendet werden.

    int n = 2
    
    Function<Integer,Integer> closure = t -> {
        return t * n 
    }
    

Wenn Java eine Schließung erstellt, behält es die Variable n mit der Funktion bei, so dass sie referenziert werden kann, wenn sie an andere Funktionen übergeben oder an anderer Stelle verwendet wird.

0
DIPANSHU GOYAL