Umgebung: Clojure 1.4
Ich versuche Funktion Metadaten dynamisch aus einem Vektor von Funktionen zu ziehen.
%Vor%Nun ist das Abrufen der Metadaten in der REPL (etwas) unkompliziert:
%Vor% Wenn ich jedoch versuche, eine Map zu erstellen, um die :ans
, :tau-or-pi
oder basic :name
aus den Metadaten zu erhalten, bekomme ich die Ausnahme:
Nachdem ich ein wenig mehr gesucht habe, habe ich die folgende Idee von einem Beitrag aus dem Jahr 2009 ( Ссылка ):
%Vor% Ich weiß, dass das defn
-Makro (in Clojure 1.4) die Metadaten auf den Var
im def
-Teil des defn
-Makros setzt, weshalb das einfache (meta #'funca)
funktioniert, aber es ist gibt es eine Möglichkeit, die Funktions-Metadaten dynamisch zu erhalten (wie im obigen Beispiel map
)?
Vielleicht vermisse ich etwas syntaktisch, aber wenn mir jemand in die richtige Richtung oder den richtigen Ansatz zeigen könnte, wäre das großartig.
Danke.
Vor kurzem fand ich es nützlich, Metadaten an die Funktionen selbst anzuhängen, anstatt an die vars, wie defn
es tut.
Sie können dies mit gutem alten ' def
:
Hier wurden die Metadaten an die Funktionen angehängt und dann werden diese Metadaten-geladenen Funktionen an die vars gebunden.
Das Schöne daran ist, dass Sie sich bei der Betrachtung der Metadaten keine Gedanken mehr um Vars machen müssen. Da die Funktionen stattdessen Metadaten enthalten, können Sie sie direkt von ihnen abrufen.
%Vor% Offensichtlich ist die Syntax von def
für Funktionen nicht ganz so raffiniert wie defn
. Je nach Ihrer Verwendung könnten Sie defn
erneut implementieren, um Metadaten an die Funktionen anzuhängen.
Der Ausdruck #(meta #'%)
ist ein Makro, das zu einem Aufruf von defn
(tatsächlich def
) erweitert wird, der einen Parameter namens p1__1637 # hat, der mit gensym
erzeugt wurde, und der Aufruf von meta.on, der versucht Verwenden Sie diesen lokalen Parameter als Var, da bei diesem Namen keine Variable vorhanden ist, erhalten Sie diesen Fehler.
Wenn Sie mit einem Vektor von var
s statt mit einem Vektor von Funktionen beginnen, dann können Sie einfach Meta auf sie abbilden. Sie können eine var (fast) überall dort verwenden, wo Sie eine Funktion mit sehr geringen Laufzeitkosten verwenden würden, um den Inhalt der Variablen bei jedem Aufruf nachzuschlagen.
Also fügen Sie Ihrem ursprünglichen Code ein paar #'
s hinzu und entfernen Sie ein extra trailing: sollten Sie den Trick machen:
Ich möchte auf Beyamors Antwort eingehen. Für etwas Code, den ich schreibe, verwende ich das:
%Vor%Ja, es ist ein wenig unhandlich, zwei Metadatenkarten zu haben. Hier ist warum ich es mache:
Die ersten Metadaten werden an die the-func
var angehängt. Sie können also (doc the-func)
verwenden, das zurückgibt:
Die zweiten Metadaten werden an die Funktion selbst angehängt. Auf diese Weise können Sie (meta the-func)
zum Zurückgeben verwenden:
Zusammenfassend ist dieser Ansatz praktisch, wenn Sie sowohl Docstrings in der REPL als auch dynamischen Zugriff auf die Metadaten der Funktion wünschen.