应用var或#'到Clojure中的函数列表

时间:2014-04-17 05:23:43

标签: clojure functional-programming

我正在尝试在Clojure中读取函数集合的元数据,但var或reader特殊表单不起作用,除非它们直接处理符号。

; this works
(var my-fn)

; this doesn't
(defn val-it [x] (var x))
(val-it my-fn)

有没有办法让它在另一个函数的范围内工作?

2 个答案:

答案 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}}}