Ich nehme an, Sie definierten Ihren Makro-Körper ohne zu zitieren und Sie sind neugierig, warum es in solch einer seltsamen Fehlermeldung resultiert. Wenn Sie wirklich ein Makro zum Aufruf (constantly :value)
gemeint zu definieren, dann sollten Sie unter Angabe verwenden und es wird funktionieren:
(defmacro produce-constantly-fn []
`(constantly :value))
(defn test-constantly-fn []
((produce-constantly-fn)))
=> #'user/test-constantly-fn
(test-constantly-fn)
=> :value
Nun zu Ihrem Fall gehen zurück, ohne zu zitieren. Es sieht wirklich interessant und geheimnisvoll aus, also habe ich etwas gegraben. Dies sind meine Ergebnisse:
Wenn Sie ein Makro definieren:
(defmacro produce-constantly-fn []
(constantly :value))
es wird nur eine Funktion erstellen namens produce-constantly-fn
und markieren Sie es als Makro (es ist immer noch eine Clojure-Funktion).
Wenn Sie die Umsetzung aussehen in der constantly
werden Sie (docs und Meta weggelassen) finden:
(defn constantly [x]
(fn [& args] x))
Unter der Haube wird es zu einem Verschluss Objekt erstellen, die IFn
implementieren und wird einen einzigen Konstruktor Parameter haben über x
Parameter zu schließen. So etwas wie dies in Java-Code:
public class clojure.core$constantly$fn__4614 {
private final Object x;
public clojure.core$constantly$fn__4614(Object x) {
this.x = x;
}
public Object invoke(...) {
return x;
}
// other invoke arities
}
Nun, wenn Sie folgende sexp haben:
(defn test-constantly-fn []
((produce-constantly-fn)))
Ich bemerkte, dass Clojure Leser evals (produce-constantly-fn)
, die nur ein Funktionsobjekt zurückgeben soll (erzeugt durch den Aufruf (constantly :value)
), aber ich im Debugger gefunden, dass es clojure.core$constantly$fn__4614.
Symbol stattdessen erzeugt (beachten Sie die .
am Ende des Symbols - es ist ein Java-Interop-Formular zum Aufruf eines Konstruktors). Es sieht so aus, als ob ein Funktionsobjekt/Wert irgendwie in ein Symbol umgewandelt wird, das seinen Konstruktoraufruf darstellt. Ich könnte finden, dass der Funktionswert in Compiler$InvokeExpr
Objekt umgewandelt wird, das Verweise auf den kompilierten Klassennamen enthält, der wahrscheinlich irgendwie in das Symbol umgewandelt wird.
Der Leser versucht clojure.core$constantly$fn__4614.
weiter aufzulösen. Es wird vom Leser in einen Aufruf an clojure.core$constantly$fn__4614clojure.core$constantly$fn__4614
Klassenkonstruktor ohne Parameter umgewandelt.
Wie Sie oben den Konstruktor dieser Klasse gesehen haben muss genau ein Konstruktor damit die Kompilierung fehlschlägt (in clojure.lang.Compiler.NewExpr
Konstruktorrumpf) mit:
java.lang.IllegalArgumentException: No matching ctor found for class clojure.core$constantly$fn__4614
Ich bin nicht sicher, warum die Clojure Leser auf den Funktionswert transformiert ein Symbol mit Konstruktor Aufruf Interop Formular und verursacht solches Verhalten, so dass ich nur die direkte Ursache der Fehlermeldung und nicht die Ursache, warum Ihr Code nicht funktioniert. Ich denke, es könnte ein Fehler sein oder eine bewusste Designentscheidung. Von den Makroautoren wäre es besser, schnell zu versagen und zu erfahren, dass der Rückgabewert eines Makros keine gültigen Codedaten ist, aber andererseits kann es sehr schwierig oder unmöglich sein festzustellen, ob die zurückgegebenen Daten ein gültiger Code sind oder nicht . Es lohnt sich, auf der Clojure-Mailingliste nachzusehen.
Ich schätze Ihre Untersuchung sehr. Vielen Dank! Auch bei Ihren Annahmen hatten Sie Recht: Ich verzichtete absichtlich auf Makrodefinition. – OlegTheCat
Gern geschehen. Es sah so interessant aus, dass es sich lohnt zu überprüfen, was vor sich geht. –
BTW, welche Art von Debugger haben Sie für die Untersuchung verwendet? – OlegTheCat