2016-06-30 7 views

Antwort

2

Der naive Ansatz wäre, nur die Bindungsform als eine verschachtelte Sammlung zu behandeln, alle Symbole in dieser Sammlung zu finden, und gibt die Reihenfolge dieser Symbole:

(defn symbols [x] 
    (filter symbol? (tree-seq coll? seq x))) 

(symbols '[{a :a} {b :b}]) 
;;=> (a b) 

jedoch als @amalloy noted, diese funktioniert nicht in allen Fällen. Hier sind einige Beispiele, bei denen die obige Implementierung von symbols ein unerwünschtes Ergebnis gibt:

;; & isn't actually bound to anything 
(symbols '[foo & bar]) 
;;=> (foo & bar) 

;; duplicates 
(symbols '{x :foo :or {x :bar}}) 
;;=> (x x) 

;; keys and default values are evaluated, not bound 
(symbols '{x (keyword "foo") :or {x (keyword 'bar)}}) 
;;=> (x keyword x keyword quote bar) 

;; namespaced keywords and symbols don't work 
(symbols '{:keys [::foo :bar/baz qux/quux]}) 
;;=> (qux/quux) 

Er schlägt vor, mit dem eingebauten in destructure Funktion statt, sondern wie er in seiner Antwort zeigte, dies einigen Müll verursacht in der zeigen, Ergebnis:

(take-nth 2 (destructure '[{:keys [x]} (last y)])) 
;;=> (map__10938 map__10938 x) 

Während dieser technisch der Liste der Symbole gibt, die Clojure binden werden, dass map__10938 nur eine Implementierung Artefakt ist, und hat nichts mit der Destrukturierung Sprache selbst zu tun.

Zum Glück ist es nicht zu schwierig, die Bindungsform manuell und montiert eine Reihe von Symbolen zu analysieren, von der ursprünglichen Bindungsform genommen, das gebunden werden würde:

(require '[clojure.set :as set]) 

(defn symbols [binding] 
    (cond 
    (symbol? binding) 
    #{binding} 

    (vector? binding) 
    (apply set/union (map symbols (remove #{'& :as} binding))) 

    (map? binding) 
    (apply set/union 
      (for [[k v] binding] 
      (case k 
       :or #{} 
       :as #{v} 
       (:keys :strs :syms) (set (map (comp symbol name) v)) 
       (symbols k)))))) 
+0

genial, danke! –

+0

Das sieht mir ziemlich gut. Sie können Ihren 'cond' ziemlich viel vereinfachen, um' (case k: oder # {},: as # {v}, (: keys: strs: syms) (setzen ...), (symbols k)) ' – amalloy

+0

@amalloy Cool, danke! :) Ich wusste nicht, dass du das mit 'case' machen kannst. –

1

Viel besser clojure.core/destructure zu bedienen ist, welches versteht, welche Symbole Namen sind, die gebunden werden, anstatt Werte, die auseinander genommen werden. Betrachten wir zum Beispiel:

(let [{:keys [x]} (last y)] 
    x) 

In diesem Zusammenhang Sie mit ziemlicher Sicherheit nicht wollen last in der Liste der Symbole enthalten, vorausgesetzt, dass Sie diese verwenden, um besser eine Destrukturierung spec zu verstehen. Und wenn Sie destructure nennen, es sagt Ihnen genau, welche Namen zu gebunden werden, welche Werte:

user> (destructure '[{:keys [x]} (last y)]) 
[map__10938 (last y) 
map__10938 (if (clojure.core/seq? map__10938) 
       (clojure.lang.PersistentHashMap/create (clojure.core/seq map__10938)) 
       map__10938) 
x (clojure.core/get map__10938 :x)] 

Jetzt auf der einen Seite, Sie werden immer ein Symbol, das nicht tatsächlich wurde durch den Anrufer eingegeben, aber das ist wahrscheinlich immer noch nützlich, weil es Ihnen sagt, was Clojure tatsächlich tun wird, um diesen Ausdruck zu handhaben. Um nur die linke Seite zu erhalten, dh die Namen, die gebunden werden, können Sie

(take-nth 2 (destructure '[{:keys [x]} (last y)])) 
+0

Er fragt nicht nach beiden Hälften einer Bindung (z. B. '{{: keys [x]} (last y)]'); er möchte nur die Symbole auf der * linken * Seite der Bindung finden. Zum Beispiel könnte ein Ausdruck wie '([[{a: a} {b: b}] [{: a: foo} {: b: bar}]] [ab])' aussehen, aber wie er in seine Frage, er will nur nach Symbolen im '[{a: a} {b: b}]' Teil suchen. –

+0

Auch wenn du nur die linke Hälfte hast, können sich einige Symbole hineinschleichen, die keine Namen sind, die gebunden werden. Zum Beispiel '{: keys [x]: oder {x (range 10)}}' - wollen Sie wirklich 'range' von dieser Funktion zurückgeben? – amalloy

+0

Ah, cool! Ich ging zurück über den [Clojure Destrukturierungsleitfaden] (http://clojure.org/guides/destructuring), und es sieht so aus, als ob es eine Menge Dinge gibt, die man mit der Destrukturierung machen kann, von denen ich nichts wusste.Ich habe meine Antwort bearbeitet, um diese Komplexitäten wiederzugeben. –

Verwandte Themen