2012-09-19 6 views
6

gelten folgende Voraussetzungen,Ausdruck, der alle aktuell definierten Symbole in Clojure zurückgibt?

(in-ns silly.fun) 

(def a 1) 

(defn fx [b] 
    ((fn [c] (return-all-symbols)) (first b))) 

ich mich gefragt, ob es möglich ist, eine Rückkehr-all-Symbole Funktion zu haben, der die Karte von Symbolen/Werte zur Zeit scoped bei ihrem Aufruf zurückkehren würde. Wenn wir also davon ausgehen, dass das oben Genannte kompiliert wurde und wir im 'silly.fun-Namespace waren, könnten wir etwas wie das Folgende ausführen.

(fx [:hello]) => {"a" 1, "b" [:hello], "c" :hello} 

Ich möchte Return-All-Symbole für Debugging-Zwecke verwenden. Sind Return-All-Symbole überhaupt möglich? Wenn ja, wie ist die Umsetzung?

Antwort

8

Es ist möglich, aber wie Sie es definiert haben, würden Sie ziemlich traurig sein: Sie wollen keine Karte mit Hunderten von Einträgen, die sich auf alle Funktionen in clojure.core beziehen! Und selbst wenn Sie nur im aktuellen Namespace suchen, haben Sie vergessen, fx einzuschließen, was ein Symbol ist, dessen Wert eine Funktion ist. Außerdem wird es oft lexikalische Symbole geben, die nicht von Makros eingeführt werden sollen. zB würde (let [[x y] foo]) vier verfügbare Symbole anzeigen: foo, x, y und so ähnlich wie vec__auto__4863.

Wie auch immer, Sie müssen wahrscheinlich mit einigen Kompromissen über diese Probleme leben, oder sonst (und ich denke wirklich, das ist besser) geben Sie an, welche Symbole Sie eigentlich eine Karte von wollen. Aber um automatisch zu erhalten Werte für die Symbole, die entweder (a) lexikalische oder (b) definiert in den aktuellen Namensraum, und auch (c) nicht die Zuordnung zu einer Funktion, könnten Sie verwenden:

(defmacro return-all-symbols [] 
    (let [globals (remove (comp :macro meta val) (ns-publics *ns*)) 
     syms (mapcat keys [globals, &env]) 
     entries (for [sym syms] 
        [`(quote ~sym) sym])] 
    `(into {} 
      (for [[sym# value#] [[email protected]] 
       :when (not (fn? value#))] 
      [sym# value#])))) 


(def a 1) 

(defn fx [b] 
    ((fn [c] (return-all-symbols)) (first b))) 

(fx [:hello]) 
;=> {a 1, c :hello, b [:hello]} 
+1

Es wird einige Zeit in Anspruch nehmen, um wirklich zu analysieren, durch das, was Sie getan haben, aber ich versuchte es und es scheint zu funktionieren. Färbe mich beeindruckt. –

2

Namespaces enthalten eine Karte mit allen derzeit gültigen Vars, die Ihnen einen Teil dessen geben, was Sie wollen. Es wäre lexicaly scoped Symbole von Ausdrücken wie (let [x 4] (return-all-symbols)) vermissen aber immer noch nützlich sein kann für das Debuggen:

core> (take 2 (ns-map *ns*)) 
([sorted-map #'clojure.core/sorted-map] [read-line #'clojure.core/read-line]) 

wenn Sie mehr als diese benötigen, dann können Sie einen echten Debugger müssen, dass die Java-Debugging -Schnittstelle verwendet. auschecken the clojure debugging toolkit

2

(ns-interns) könnte sein, was Sie wollen, aber (ns-map) in (lazy-seq) verpackt funktioniert gut für einen großen Namespace.

1 (ns-map 'clojure.core) 
2 {sorted-map #'clojure.core/sorted-map, read-line #'clojure.core/read-line, re-pattern #'clojure.core/re-pattern, keyword? #'clojure.core/keyword?, ClassVisitor clojure.asm.ClassVisitor, asm-type #'clojure.core/asm-type, val #'clojure.core/val, ...chop...}