2012-09-19 10 views
6

supone lo siguiente,Expresión que devuelve todos los símbolos del ámbito actual en Clojure?

(in-ns silly.fun) 

(def a 1) 

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

Me preguntaba si es posible tener una función de retorno de todos los símbolos que devolvería el mapa de símbolos/valores actualmente scoped en su invocación. Entonces, suponiendo que lo anterior fuera compilado y estuviéramos en el espacio de nombres "tonto.fun", podríamos ejecutar algo como lo siguiente.

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

Me gustaría utilizar return-all-symbols para la depuración. ¿Es posible devolver todos los símbolos? Si es así, ¿cuál es su implementación?

Respuesta

8

Es posible, pero como lo has definido estarías muy triste: no quieres un mapa con cientos de entradas que hagan referencia a todas las funciones de clojure.core. E incluso si solo mira en el espacio de nombres actual, olvidó incluir fx, que es un símbolo cuyo valor es una función. Además, a menudo habrá símbolos léxicos que no desea, introducidos por las macros. por ejemplo, (let [[x y] foo]) mostraría cuatro símbolos disponibles: foo, x, y, y algo así como vec__auto__4863.

De todos modos, probablemente tenga que vivir con algún compromiso sobre esos problemas, o bien (y realmente creo que esto es mejor) especifique de qué símbolos realmente quiere un mapa. Pero para obtener automáticamente los valores de los símbolos que son o bien (a) léxico o (b) definido en el espacio de nombres actual, y también (c) no mapear a una función, que puede usar:

(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

que va a tomar algún tiempo para analizar realmente a través de lo que hizo, pero he probado y parece que funciona. Coloréme impresionado. –

2

Los espacios de nombre contienen un mapa con todos los vars de ámbito actual, que le proporciona parte de lo que desea. Sería pierda símbolos léxicamente con ámbito de expresiones como (let [x 4] (return-all-symbols)) aunque todavía puede ser útil para la depuración:

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

si necesita más que esto, entonces es posible que tenga un depurador real que utiliza la depuración de Java interfaz. echa un vistazo a the clojure debugging toolkit

2

(ns-interns) podría ser lo que quiere, pero usar (ns-map) envuelto en (lazy-seq) funciona bien para un gran espacio de nombres.

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...} 


Cuestiones relacionadas