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:
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:
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:
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. 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. Ich habe verschiedene Fragen zu den "weisesten" Implementierungsdetails.
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?
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?
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? 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:)
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% 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
Tags und Links macros clojure self-reference