Freigabe der Ausgabe eines Baumes von Schließungen

8

Dies ist eine konzeptuelle Frage, wie man das Folgende in Lisp implementieren würde (vorausgesetzt, in meinem Fall würde Common Lisp, aber jeder Dialekt würde funktionieren). Angenommen, Sie haben eine Funktion, die Closures erzeugt, die sequentiell über eine beliebige Sammlung von Daten iterieren (oder auf andere Weise unterschiedliche Werte zurückgeben) und keine NULL ausgeben, wenn sie erschöpft sind, d. H.

%Vor%

Nehmen Sie jetzt an, Sie versuchen, eine Kombination aus einer oder mehreren dieser Sperren zu permutieren. Wie würden Sie eine Funktion implementieren, die einen neuen Abschluss zurückgibt, der anschließend eine Permutation aller darin enthaltenen Closures erzeugt?

%Vor%

, so dass Folgendes gilt:

%Vor%

und so weiter.

Die Art, wie ich es ursprünglich entworfen hatte, bestand darin, dem anfänglichen zählenden Lambda einen "Pause" -Parameter hinzuzufügen, so dass Sie es beim Iterieren immer noch aufrufen und den alten zwischengespeicherten Wert erhalten können, wenn Sie ": pause t" übergeben die Permutation etwas sauberer. Auch wenn das obige Beispiel eine einfache Liste von zwei identischen Closures ist, kann die Liste ein beliebig komplizierter Baum sein (der in der Tiefe permutiert werden kann - erste Ordnung und der resultierende Permutationssatz würde die Form des Baumes haben).

Ich hatte dies implementiert, aber meine Lösung war nicht sehr sauber und versuche herauszufinden, wie andere das Problem angehen würden.

Vielen Dank im Voraus.

bearbeiten Vielen Dank für die Antworten. Was ich am Ende getan habe, war das Hinzufügen eines "continue" -Arguments zum Generator und das Verflachen meiner Struktur durch Ersetzen einer verschachtelten Liste durch eine Schließung, die diese Liste permutierte. Die Generatoren sind nicht vorgegangen und haben immer den letzten zwischengespeicherten Wert zurückgegeben, es sei denn, 'continue' wurde übergeben. Dann habe ich jeden Generator rekursiv aufgerufen, bis ich entweder die letzte cdr oder eine Null erreicht habe. Wenn ich zum letzten cdr kam, stieß ich einfach auf ihn. Wenn ich zu einem NIL gekommen bin, habe ich den einen davor gestoßen und jede nachfolgende Schließung zurückgesetzt.

    
yan 28.01.2011, 23:16
quelle

2 Antworten

2

Sie benötigen eindeutig eine Möglichkeit, jeden von einem Generator zurückgegebenen Wert mehrmals zu verwenden.

Neben Rainer Joswigs Vorschlägen kommen drei Ansätze in den Sinn.

Caching-Werte

permute-closures kann sich natürlich jeden von jedem Generator zurückgegebenen Wert merken, indem er ihn in einer Liste speichert und ihn immer wieder verwendet. Dieser Ansatz beinhaltet offensichtlich einen gewissen Speicheraufwand, und es wird nicht sehr gut funktionieren, wenn die erzeugten Sequenzen unendlich sein können.

Erstellen neuer Generatoren für jede Iteration

Bei diesem Ansatz würden Sie die Signatur von permute-closures so ändern, dass sie als Argumente keine gebrauchsfertigen Generatoren, sondern Thunks verwendet, die sie erstellen. Ihr Beispiel würde dann so aussehen:

%Vor%

Auf diese Weise kann permute-closures einen Generator zurücksetzen, indem er ihn einfach neu erstellt.

Generatorzustände kopierbar machen

Sie können eine Möglichkeit bereitstellen, Kopien von Generatoren zusammen mit ihren Zuständen zu erstellen. Dies ist eine Art Ansatz 2, in dem permute-closures die Generatoren nach Bedarf zurücksetzen würde, außer dass das Zurücksetzen durch Zurücksetzen auf eine Kopie des ursprünglichen Zustands erfolgt. Außerdem könnten Sie partielle Rücksetzungen durchführen (d. H. Rückverfolgung zu einem beliebigen Punkt und nicht nur zum Anfang), wodurch der Code von permute-closures möglicherweise erheblich vereinfacht wird.

Das Kopieren von Generatorzuständen könnte in einer Sprache mit erstklassigen Fortsetzungen (wie Scheme) etwas einfacher sein, aber wenn alle Generatoren einer vordefinierten Struktur folgen, sollte es in Common mit einem define-generator -Makro oder ähnlichem abstrahieren Lisp auch.

    
Matthias Benkard 30.01.2011, 11:35
quelle
1

Ich würde dem Zähler entweder eins hinzufügen:

  • kann den Zähler auf den Anfang zurücksetzen

  • Lassen Sie den Zähler NULL zurückgeben, wenn die Zählung abgeschlossen ist, und beginnen Sie dann beim nächsten Aufruf mit dem ersten Wert erneut

Rainer Joswig 29.01.2011 03:20
quelle