6

假设以下,

(in-ns silly.fun)

(def a 1)

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

我想知道是否有可能有一个 return-all-symbols 函数来返回当前在其调用范围内的符号/值的映射。因此,假设上面已经编译并且我们在 'silly.fun 命名空间中,我们可以运行类似下面的内容。

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

我想使用 return-all-symbols 进行调试。是否有可能返回所有符号?如果是这样,它的实现是什么?

4

3 回答 3

8

这是可能的,但正如你定义的那样,你会很伤心:你不想要一个包含数百个条目的映射,这些条目引用了 clojure.core 中的所有函数!即使您只查看当前命名空间,您也忘记了 include fx,它是一个符号,其值是一个函数。另外,通常会有你不想要的词汇符号,由宏引入。例如,(let [[x y] foo])将显示四个可用符号:foo、x、y 和类似vec__auto__4863.

无论如何,您可能必须在这些问题上做出一些妥协,否则(实际上我认为这更好)指定您真正想要地图的符号。但是要自动获取(a)词法或(b)在当前命名空间中定义的那些符号的值,并且(c)不映射到函数,您可以使用:

(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#] [~@entries]
                 :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]}
于 2012-09-19T22:56:34.223 回答
2

(ns-interns)可能是您想要的,但使用(ns-map)包裹在(lazy-seq)中对于大命名空间很有用。

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


于 2012-09-20T00:18:20.330 回答
2

命名空间包含一个包含所有当前作用域变量的映射,它为您提供了您想要的部分内容。它会错过表达式中的词法范围符号,例如(let [x 4] (return-all-symbols))尽管可能仍然对调试有用:

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

如果您需要更多,那么您可能需要一个使用 java 调试接口的真正调试器。查看clojure 调试工具包

于 2012-09-19T22:06:32.553 回答