我正在尝试在Clojure中读取函数集合的元数据,但var或reader特殊表单不起作用,除非它们直接处理符号。
; this works
(var my-fn)
; this doesn't
(defn val-it [x] (var x))
(val-it my-fn)
有没有办法让它在另一个函数的范围内工作?
答案 0 :(得分:8)
resolve
返回与当前命名空间的上下文中的给定符号对应的Var或类对象。 ns-resolve
允许您指定要在中解析符号的命名空间。
(resolve 'my-fn)
;= #'some.ns/my-fn
如果符号无法解析为Var,则返回nil
。
答案 1 :(得分:2)
(var my-fn)
直接处理该符号,因为它是一种特殊形式(读者收到未评估的表单)。
您要阅读的元数据存储在var
对象中,而不是存储在函数对象中。
因此,只有通过遍历所有现有变量并通过相等比较它们的值,才能实现从函数对象列表中读取元数据的目标。如果函数对象是唯一的启动方式,我只会推荐它。
(defn meta-of
"Returns a hashmap mapping the function objects in fn-objs to
a set of metadata of vars containing it."
[fn-objs]
(let [fn-objs (set fn-objs)]
(reduce (fn [acc ns]
(reduce (fn [acc var]
(let [val (var-get var)]
(cond-> acc
(contains? fn-objs val)
(update-in [val] (fnil conj #{}) (meta var)))))
acc
(vals (ns-interns ns)))) {} (all-ns))))
(def foo inc) ;; Now there are two vars that have the inc function as their value
(meta-of [inc])
{#<core$inc clojure.core$inc@66d7e31d> ;; <- function object
#{{:ns #<Namespace clojure.core>, ;; <- metadata in clojure.core namespace
:name inc,
:file "clojure/core.clj",
:column 1,
:line 881,
:arglists ([x]),
:added "1.2",
:inline #<core$inc__inliner clojure.core$inc__inliner@24f87069>,
:doc
"Returns a number one greater than num. Does not auto-promote\n longs, will throw on overflow. See also: inc'"}
{:ns #<Namespace user>, ;; <- metadata in user namespace
:name foo,
:file "/tmp/form-init1078564431656334911.clj",
:column 1,
:line 1}}}