Ich versuche ein Makro zu schreiben, das n Funktionen erzeugt. Folgendes habe ich bisher:
%Vor%Der Fehler, den ich bekomme, ist:
%Vor%Und ich bin nicht wirklich sicher, was das bedeutet, aber ich habe diese vage Vorstellung, dass (für ...) nicht so funktioniert, wie ich denke, dass es in einem Makro ist.
Sie sind verwirrt über die Unterscheidung zwischen Laufzeit und Kompilierzeit sowie zwischen Makros und Funktionen. Das Lösen eines Makroproblems mit eval
ist niemals die richtige Antwort: Stellen Sie stattdessen sicher, dass Sie Code zurückgeben, der das tut, was Sie tun möchten. Hier ist eine minimale Änderung, damit Ihre ursprüngliche Version funktioniert.
Die wichtigsten Änderungen sind:
defn-from
ist eine Funktion, kein Makro - Sie möchten nur eine einfache Möglichkeit zum Erstellen von Listen, die das Hauptmakro für das Einfügen in das Ergebnisformular verantwortlich ist. Sie möchten nicht ein Makro hier haben, weil es nicht in den Körper von make-placeholders
expandiert werden soll.
make-placeholders
beginnt mit einem do
, und seine for
außerhalb eines Syntax-Zitats. Dies ist der wichtigste Teil: Sie möchten, dass der an den Benutzer zurückgegebene Code wie (do (defn ...))
aussieht, als ob sie alles manuell eingegeben hätten - nicht (for ...)
, was immer möglich war Definieren Sie eine einzelne Funktion.
1 Sehr, sehr selten
Sie können dies auch komplett ohne Makros tun, indem Sie eine Funktion zum Erstellen von Funktionen verwenden und die untergeordnete Operation intern
anstelle von def
verwenden. Es erweist sich tatsächlich als viel einfacher:
Macroexpanding sobald die (make-placeholders 9)
Ausdruck ich bekomme dies:
Also defn-from
erwartet eine Zeichenkette als erstes Argument, aber weil es ein Makro ist, wird (str "_" i__1862__auto__)
nicht ausgewertet und ist daher als Liste hinterher.
Ich habe eine Weile mit dem herumgespielt und kam dabei auf:
%Vor% Macroexpanding (make-placeholders 3)
gibt
was ich beabsichtigt habe und dies evaluiere definiert die Funktionen _0
, _1
und _2
:
Ok, das funktioniert, aber ich bin mir immer noch nicht sicher, ob das eine gute Idee ist.
Zuerst eval ist böse . Ok, es könnte auch ohne eval
gemacht werden, aber stattdessen mit do
(ersetze map eval
in meiner Lösung mit do
). Möglicherweise machen Sie Ihren Code jedoch schwer verständlich, weil Sie Funktionen erstellen, die nirgendwo in Ihrem Code definiert sind. Ich erinnere mich, dass ich, als ich gerade Clojure benutzt habe, eine Bibliothek nach einer Funktion durchsucht habe und sie nicht finden konnte. Ich fing an, yikes zu denken, dieser Typ muss irgendwo ein Makro definiert haben, das die Funktion definiert, nach der ich suche, wie werde ich jemals verstehen, was vor sich geht? Wenn die Leute Clojure benutzen, dann wird es eine höllische Sauerei sein und alles, was die Leute über Perl gesagt haben, in den Schatten stellen ... Es stellte sich heraus, dass ich nur die falsche Version anschaute - aber Sie könnten es sein sich selbst und andere für etwas Elend aufstellen.
Nachdem dies gesagt wurde, könnte es geeignete Anwendungen dafür geben. Oder Sie könnten etwas Ähnliches verwenden, um Code zu generieren und in eine Datei zu schreiben (dann wäre der Quellcode für die Überprüfung verfügbar). Vielleicht kann jemand erfahrener hereinspielen?
Tags und Links clojure