Beratung / Diskussion über anonyme "selbstreferentielle" Datenstrukturen

8

Entschuldigung für jede irrige Terminologie - Ich bin ziemlich neu in der Informatik, und ich kenne Clojure nur sehr gut (aber ich denke, ich würde sagen, dass ich es ziemlich gut kenne).

Also habe ich nicht viel darüber geforscht, aber manchmal fand ich es nützlich, wenn ich Clojure-Code schreibe, um von einer "Zwischenversion der Datenstruktur, in der ich mich befinde" zu sprechen diese Datenstruktur (viel wie in einem let ). Schnelle Beispiele:

%Vor%

Die Idee ist, dass sich die Struktur inkrementell aufbaut und zu jedem Zeitpunkt die Möglichkeit hat, sich auf die aktuelle Zwischenstruktur als this zu beziehen. Hier ist der Code für meine aktuelle Implementierung:

%Vor%

Die Funktion append hängt ein Element an eine Sammlung an und gibt denselben Sammlungs-Typ zurück. Die Funktion self-indulge hat einen standardmäßigen reduce-artigen Akkumulator, der nur Elemente der Form aufbaut. Es hat auch einen Akkumulatorstapel, der jedes Mal länger wird, wenn self-indulge auf sich selbst zurückkehrt. Der Sinn dessen ist es, andere "höhere" Akkumulatoren im Auge zu behalten, so dass this die gesamte Struktur ist, nicht nur ein lokales Stück. Das Makro self-ish schließt nur self-indulge (das sich selbst mit partial aufruft, also kann es die Makrohosen nicht tragen).

Bearbeiten: Beispiel Anwendungsfall Bei mir geht es bei diesem Makro darum, die Lesbarkeit von Code zu erhöhen, nicht wirklich die Funktionalität zu erweitern. Wo finde ich das nützlich in Fällen, wo ich handgeschriebene Strukturen mit teilweise redundanten Daten habe - oder vielleicht "abhängig" ist ein besseres Wort. Es kann einfacher sein, den Code zu lesen und zu sehen, welche verschiedenen Teile der Datenstruktur vorhanden sind, und es kann auch nützlich sein, wenn ich Datenwerte in einem Teil einer Struktur ändere und möchte, dass diese Änderung in anderen Teilen widergespiegelt wird. Zum Beispiel:

%Vor%

Es könnte auch in Zeiten nützlich sein, in denen man gerne etwas in die Daten einbacken möchte, im Gegensatz zu etwas, das mit Hilfe einer Funktion spontan erzeugt wird. Diese Fälle sind wahrscheinlich viel seltener, und ich denke, es wäre eine schlechte Idee, die Daten unnötigerweise zu verwirren, wenn Sie nur schöne, saubere Funktionen haben könnten, die sie manipulieren.

Meine Hauptfragen:

  1. Ist das wirklich nützlich oder wäre die Mehrdeutigkeit / Komplexität zu groß? Ich stelle mir vor, ich bin nicht allein in dieser Art von Makro wollen / verwenden. Was sind die Erfahrungen anderer hier? Benutzt du so etwas? Haben Sie bessere Workarounds gefunden? Gibt es Gründe, warum so etwas in keiner Clojure-Bibliothek ist? Oder gibt es etwas, das ich noch nicht gesehen habe?
  2. Gibt es bessere Namenskonventionen, die ich verwenden könnte - im Gegensatz zu self-ish und this ? Zum Beispiel, this ist zu sehr mit OOP geladen, was bedeutet, dass ich mir nicht sicher bin, dass ich im Grunde nur mit Clojure vertraut bin.
  3. Ich bin ziemlich neu in der Informatik, gibt es zugängliche und informative Ressourcen im Zusammenhang mit dieser Art von Dingen - ich würde sagen, ich würde es anonyme selbstreferentielle (vielleicht reflexive ist ein besseres Wort?) Datenstrukturen nennen? Ich habe noch nichts zugängliches und informatives gefunden.
  4. Gibt es eine bessere Möglichkeit, das Makro self-ish zu schreiben? Oben habe ich meine aktuelle Version davon aufgenommen, aber ich kann das Gefühl nicht loswerden, dass es einen einfacheren Weg gibt.
  5. Ich habe verschiedene Fragen zu den "weisesten" Implementierungsdetails.

    • Traversal : Sollte es zuerst die Breite oder die Tiefe sein? Wenn die Tiefe zuerst, Vorbestellung, Postorder oder Inorder? Im Moment glaube ich, dass es die erste Vorbestellung der Tiefe ist, die für mich Sinn macht, aber vielleicht hat sie einige Nachteile, die ich nicht bemerkt habe.
    • Ordnungsprobleme : ( Siehe hier für eine verwandte vorherige Frage von mir ) Innerhalb von {} (dh von Hand geschriebene Karten) ist es unmöglich, die Reihenfolge korrekt zu halten (über 8 Karteneinträge), ohne array-map oder sorted-map zu verwenden - mit anderen Worten, Oberhalb von 8 Karteneinträgen ist {} Usage unsicher. Vielleicht könnte das Makro anstelle von handgeschriebener Reihenfolge einige ausgefallene Magie verwenden, um Gegenstände in einer "idealen" Reihenfolge zu bearbeiten? Oder vielleicht wäre es besser, alle Karten innerhalb von (array-map ...) anstatt des augenfälligen {} ? Zu verpacken?

      %Vor%
    • Serial : Wie ich es geschrieben habe, vermeidet das Makro unendliche Rekursion, indem es mit seinen Elementen seriell umgeht, ähnlich wie let , aber das erzeugt möglicherweise seltsames Verhalten. In meinem obigen schnellen Beispiel gibt (reduce str this) beispielsweise "ab" zurück, weil this in diesem Schritt ["a" "b"] ist. Vielleicht wäre es manchmal nützlich, stattdessen eine Art unendliche Lazy-Sequenz zu erstellen? Wenn ja, wie könnte das implementiert werden?

    • Zuordnungseinträge : Derzeit werden Zuordnungseinträge wie Vektoren behandelt, aber da this in jedem Zwischenschritt aufgerufen werden kann, ist es absolut möglich, einen nil -Wert von einem Schlüssel zu erhalten hat "noch nicht" einen Wert zugewiesen bekommen.Deshalb wurde :c in meinem ersten schnellen Beispiel auf 3 abgebildet - weil intermediär ein nil entsprechend :c vorhanden war, und das wurde auch gezählt. Denken Sie, dass dies eine Korrektur erfordert?
    • Nicht-Makro-Dienstprogramm : Es wäre trivial, nur self-indulge außerhalb des Makrokontextes zu verwenden, aber könnte das jemals nützlich sein?

Danke fürs Lesen, jede Hilfe wird geschätzt:)

    
Omri Bernstein 25.07.2012, 13:57
quelle

2 Antworten

2

Dieser Ansatz "fühlt" sich ein bisschen falsch an, obwohl ich mir nicht ganz sicher bin, warum. Vielleicht mag ich die Idee der Kartenkonstruktion nicht, die von der Ordnung abhängt ....

Nachdem Sie gesagt haben, dass es ein ziemlich einfaches Makro zum Schreiben ist, wollen Sie effektiv etwas, das sich zu:

erweitert %Vor%

Daher wäre ein passendes Makro etwas (für den Kartenfall):

%Vor%

Beachten Sie, dass die Bindungsform ein Vektor ist, da eine Kartenbindungsform ungeordnet ist.

Immer noch nicht sicher, wie sehr ich dieses Idiom mag. Meine bevorzugte Vorgehensweise besteht normalerweise darin, eine Struktur mit einer Let-Form zu definieren und Zwischenberechnungen sinnvolle Namen zu geben, z. B .:

%Vor%     
mikera 26.07.2012, 03:34
quelle
2

im Schema geschieht dies mit (letrec ...) , womit Sie auf den Namen der Datenstruktur innerhalb der Struktur selbst verweisen können. Wenn Sie also Ihre eigene Vorgehensweise definieren möchten, ist es möglicherweise sinnvoller, dies zu implementieren. Sie könnten dies mit den Tricks tun, die in den Antworten zu beschrieben sind Ist es möglich, zirkuläre Referenzen in Clojure zu erstellen?

Ein Vorteil von letrec ist, dass es einen benutzerdefinierten Namen hat (wenn Ihr Makro verschachtelt ist, dann ist this schattiert).

[bearbeitet, um Kommentare zu Typen zu entfernen, da ich Ihr Makro nicht verstehe.]

[update] auch, Sie können sich für die Diskussion von Anaphora in Freude der clojure Abschnitt 8.5.1 interessieren

    
andrew cooke 25.07.2012 23:47
quelle

Tags und Links