2014-05-14 9 views
5

Ich habe versucht, dies mit Zitat, Zitat-Splicing, Eval und was auch immer ich denken kann, zu arbeiten, aber bisher kein Glück. Ich verstehe, warum es nicht funktioniert - es wird als eine Karte gesehen, und es versucht, a, b und c zu evalieren - einfach nicht, wie man es umgehen kann.Speichern einer Destrukturierungskarte für die spätere Verwendung

(def destructor {a :a b :b c :c}) 
; CompilerException java.lang.RuntimeException: Unable to resolve symbol: a in this context, compiling:(:1:15) 

(let [destructor my-map] 
    'etc) 

Ich habe eine ziemlich komplizierte Destrukturierung Karte, die ich verwende mehrmals unter Berücksichtigung, so schien es eine gute Idee, es irgendwo zu verstauen. Vielleicht gibt es bessere Möglichkeiten, das zu tun?

Antwort

3

Gute Idee, aber Sie können es nicht auf diese Art tun, weil die Sache, die Sie speichern möchten, nicht wirklich ein Wert ist, also können Sie es nicht in einem var speichern.

Stattdessen können Sie ein Makro definieren, das in seiner Erweiterung umfasst:

(defmacro with-abc [abc & body] 
    `(let [~'{:keys [a b c]} ~abc] 
    [email protected])) 

(with-abc foo 
    (...use a, b, and c...)) 
+3

Die komisch aussehende '~‘ 'in der Let-Klausel ist so, dass a, b und cd on't Namespace-qualifiziert durch das Syntax-Zitat. Ich denke, es ist notwendig, aber ich bin gerade nicht an einem echten Computer, also wenn jemand sieht, dass es nicht leicht ist, zu editieren. – amalloy

+0

Sehr nett. Ich kann '' keys'' nicht verwenden (gut, um es als Beispiel zu sehen), da ich "eine ziemlich involvierte Destrukturierungskarte" (d. H. Von vielen Ebenen) habe, aber das Tauschen in meiner Karte funktioniert großartig. Ich habe ein bisschen mit einem Makro gespielt, aber - obwohl ich schon viele Male erfolgreich war - habe ich immer noch nicht meinen Kopf dabei, alles zu überliefern und ein komplett neues, komplett verwandtes Ding zurück zu bekommen. Vielen Dank! –

+1

@amalloy: Für die Aufzeichnung hast du recht - das '~ 'ist notwendig. Ich habe es getestet, und es funktioniert so wie es ist, aber das '~ 'herauszunehmen, verursacht eine' java.lang.RuntimeException: Kann keinen qualifizierten Namen geben: user/a'. –

2

So etwas wie @ amalloy Antwort war mein erster Instinkt zu und es ist wahrscheinlich der Weg zu gehen. Das heißt, es könnte eine einfache ol eine Überlegung wert‘Funktion höherer Ordnung:

(defn destruct 
    [{a :a b :b c :c} f] 
    (f a b c)) 

(destruct my-map 
      (fn [a b c] 
      (println a) 
      (println b) 
      (println c))) 

Es ist ein wenig neugieriger und du bist gezwungen, jedes Mal wenn die Bindungen zu nennen, aber Sie mögliche Hygieneprobleme vermeiden und je nach Ihr Komfort mit Metaprogrammierung, es ist ein wenig leichter zusammen zu stellen.

+0

Ja, ich möchte vermeiden, Dinge zu benennen, da meine Karte nicht nur Dutzende von Dingen enthält, sondern sich auch auf verschiedenen Verschachtelungsebenen befindet. Es ist gut, wenn möglich, die funktionelle Route zu finden. Vielen Dank. –

+0

Gefallen. Klingt wie das Makro ist dann der Weg zu gehen. – Beyamor

0

Sie müssen den zerstörenden Muster

(def my-destructor '{a :a b :b c :c}) 

Sie können dies mit Ebenen zu zitieren/unquoting zitieren, aber es ist einfacher, mit einer kleinen Hilfsfunktion zu sehen.

(defn- with-destructor* [binding & body] 
    `(let ~binding [email protected])) 

Diese eval tritt zu einer Zeit "kompiliert" (während der Makroerweiterung)

(defmacro with-destructor [[destructor form] & body] 
    (eval `(with-destructor* [~destructor '~form] '[email protected]))) 

Wie

gezeigt
(macroexpand-1 '(with-destructor [my-destructor {:a 1 :c 3}] (+ a c))) 
;=> (clojure.core/let [{a :a, b :b, c :c} {:a 1, :c 3}] (+ a c)) 

Ergebnis

(with-destructor [my-destructor {:a 1 :c 3}] (+ a c)) 
;=> 4 
+0

Die Definition von 'mit-Destruktor' hat keinen Grund,' eval' zu verwenden. Sein Körper sollte nur '(mit dem Destruktor * [Destruktor Form] Körper anwenden)'.Und natürlich kannst du das vermeiden, wenn du die varargs von 'with-destructor * 'weglegst (wie du es meiner Meinung nach solltest). – amalloy

+0

@amalloy Vielleicht vermisse ich etwas, aber ich glaube, dass Ihr Vorschlag nur mit einem Literal-Destruktor-Ausdruck wie in '(with-destructor [{a: ab: bc: c} {: a 1: c 3}] (+ ac)) ', aber nicht einer in einer var wie in der Frage gespeichert. –

+0

Ich verstehe. Sie versuchen, den 'Destruktor' vom Benutzer liefern zu lassen, nicht für ein bestimmtes Makro. Ich war verwirrt, weil Sie das Makroargument wie das var benannt haben, und ich dachte, das Makro bezog sich auf die Variable. – amalloy