如何将clojure的doc函数应用于一系列函数

时间:2011-12-01 19:56:24

标签: reflection clojure

我试图做一些我认为很简单的事情,但事实证明并非如此,我认为解决方案可能让我对clojure有了更深入的了解,所以我想我会在这里问。

我希望能够从clojure REPL运行以下内容:

(map #(doc %) v)

其中v是......某事的向量,我不确定是什么。目标是为某些函数序列打印出doc字符串,但我不确定如何表达该向量。我尝试了几件事:(我会随机选择一些功能)

[+ - first set]
['+ '- 'first 'set]
[`+ `- `first `set]
[(var +) (var -) (var first) (var set)]
[`~+ `~- `~first `~set]

没有工作。我还尝试apply doc函数,但这不起作用,因为doc是一个宏,因此不能成为apply的参数。我错过了什么?

3 个答案:

答案 0 :(得分:3)

(doseq [f ['+ '- 'first 'set]] (eval (list 'doc f)))

答案 1 :(得分:1)

在Clojure 1.2中,您可以使用函数print-doc

(print-doc #'fisrt)
像这样

(map print-doc [#'fisrt #'+])

#'fisrt(var first)相同。

请注意,这不适用于特殊表单:(doc def)有效,但(print-doc # def)`给出:

java.lang.Exception: Unable to resolve var: def in this context (NO_SOURCE_FILE:7)

这是因为特殊形式没有在变量中定义。您可以使用macroexpand-1

查看doc如何为他们工作
user=> (macroexpand-1 '(doc def))
(clojure.core/print-special-doc (quote def) "Special Form" (clojure.core/special-form-anchor (quote def)))

在Clojure 1.3 print-doc移动到clojure.repl命名空间并且是私有的,因此您无法直接执行它。您可以输入ns:

user=> (in-ns 'clojure.repl)
clojure.repl=> (print-doc (meta #'first))
clojure.repl=> (map #(print-doc (meta %)) [#'first #'+])

如您所见,Clojure 1.3需要明确获取元数据。

如果需要从不同的命名空间执行此操作,则必须导出该函数。一种方法是定义一个新函数:

clojure.repl=> (defn my-print-doc [m] (print-doc m))
user=> (clojure.repl/my-print-doc (meta #'first))

答案 2 :(得分:1)

(defn my-doc [v] (-> v meta :doc))

此函数获取var的元数据,然后从元数据中获取doc字符串。 您可以将其映射到一系列变量:

(map my-doc [(var +) (var -) (var first) (var set)]) ;=> LazySeq of doc-strings

或更短:

(map my-doc [#'+ #'- #'first #'set]) ;=> LazySeq of doc-strings

这不适用于特殊表单,因为它们不会被vars引用。