我想详细说明一下 Beyamor的回答 。对于我写的一些代码,我使用的是:
(def ^{:doc "put the-func docstring here" :arglists '([x])} the-func ^{:some-key :some-value} (fn [x] (* x x)))
是的,拥有两个元数据映射有点笨拙。这就是我这样做的原因:
第一个元数据附加到 the-func 变种。所以你可以使用 (doc the-func) 返回:
the-func
(doc the-func)
my-ns.core/the-func ([x]) put the-func docstring here
第二个元数据附加到函数本身。这可以让你使用 (meta the-func) 回来:
(meta the-func)
{:some-key :some-value}
总之,当您需要REPL中的文档字符串以及对函数元数据的动态访问时,此方法会派上用场。
表达方式 #(meta #'%) 是一个扩展为调用的宏 defn (其实 def )其中有一个名为p1__1637#的参数 gensym 并且对meta的调用是尝试将此本地参数用作var,因为不存在具有该名称的var,您会收到此错误。
#(meta #'%)
defn
def
gensym
如果你 从矢量开始 var 而不是函数的向量 那么你可以将元映射到它们上面。您可以在任何使用函数的地方使用var(非常接近),每次调用var时,查找var的内容的运行时成本非常小。
var
user> (def vector-of-functions [+ - *]) #'user/vector-of-functions user> (def vector-of-symbols [#'+ #'- #'*]) #'user/vector-of-symbols user> (map #(% 1 2) vector-of-functions) (3 -1 2) user> (map #(% 1 2) vector-of-symbols) (3 -1 2) user> (map #(:name (meta %)) vector-of-symbols) (+ - *) user>
所以加一对 #' s到您的原始代码并删除额外的尾随:应该做的伎俩:
#'
user> (defn #^{:tau-or-pi :pi} funca "doc for func a" {:ans 42} [x] (* x x)) #'user/funca user> (defn #^{:tau-or-pi :tau} funcb "doc for func b" {:ans 43} [x] (* x x x)) #'user/funcb user> (def funcs [#'funca #'funcb]) #'user/funcs user> (map #(meta %) funcs) ({:arglists ([x]), :ns #<Namespace user>, :name funca, :ans 42, :tau-or-pi :pi, :doc "doc for func a", :line 1, :file "NO_SOURCE_PATH"} {:arglists ([x]), :ns #<Namespace user>, :name funcb, :ans 43, :tau-or-pi :tau, :doc "doc for func b", :line 1, :file "NO_SOURCE_PATH"}) user> (map #(:tau-or-pi (meta %)) funcs) (:pi :tau) user>
最近,我发现将元数据附加到函数本身而不是像vars一样有用 defn 确实。
你可以用好的ol'做到这一点 def :
(def funca ^{:tau-or-pi :pi} (fn [x] (* x x))) (def funcb ^{:tau-or-pi :tau} (fn [x] (* x x x)))
这里,元数据已附加到函数,然后这些元数据负载函数绑定到变量。
关于这一点的好处是,在考虑元数据时,您不再需要担心变量。由于函数包含元数据,因此您可以直接从中提取元数据。
(def funcs [funca funcb]) (map (comp :tau-or-pi meta) funcs) ; [:pi :tau]
显然是语法 def 不是那么精致 defn 对于功能,所以根据您的使用情况,您可能有兴趣重新实现 defn 将元数据附加到函数。