我想为某些命名空间显示随机(doc)页面.
我可以得到的随机函数名称:
user=> (rand-nth (keys (ns-publics 'clojure.core)))
unchecked-char
Run Code Online (Sandbox Code Playgroud)
当我尝试将其传递给(doc)时,我得到了这个:
user=> (doc (rand-nth (keys (ns-publics 'clojure.core))))
ClassCastException clojure.lang.PersistentList cannot be cast to clojure.lang.Symbol clojure.core/ns-resolve (core.clj:3883)
Run Code Online (Sandbox Code Playgroud)
我是Clojure的新手,我不知道如何处理这个...我试图将其转换为regexp并使用(find-doc)但是也许有更好的方法来做到这一点......
说明
这里的问题是doc
宏,而不是函数.您可以使用source
repl中的宏来验证这一点.
(source doc)
; (defmacro doc
; "Prints documentation for a var or special form given its name"
; {:added "1.0"}
; [name]
; (if-let [special-name ('{& fn catch try finally try} name)]
; (#'print-doc (#'special-doc special-name))
; (cond
; (special-doc-map name) `(#'print-doc (#'special-doc '~name))
; (resolve name) `(#'print-doc (meta (var ~name)))
; (find-ns name) `(#'print-doc (namespace-doc (find-ns '~name))))))
Run Code Online (Sandbox Code Playgroud)
如果您是Clojure(和lisps)的新手,您可能还没有遇到过宏.作为一个毁灭性的简要解释,函数在评估代码上运行,宏对未评估的代码进行操作- 即源代码本身.
这意味着当你输入
(doc (rand-nth (keys (ns-publics 'clojure.core))))
Run Code Online (Sandbox Code Playgroud)
doc
尝试操作实际的代码行(rand-nth (keys (ns-publics 'clojure.core)))
- 而不是评估结果(返回的符号).代码只不过是Clojure中的列表,这就是错误告诉您列表无法转换为符号的原因.
解
所以,你真正想做的是评估代码,然后调用doc
结果.我们可以通过编写另一个宏来做到这一点,该宏首先评估你给它的代码,然后传递给它doc
.
(defmacro eval-doc
[form]
(let [resulting-symbol (eval form)]
`(doc ~resulting-symbol)))
Run Code Online (Sandbox Code Playgroud)
您可以传递eval-doc
任意形式,它会在传递给它们之前对它们进行评估doc
.现在我们很高兴.
(eval-doc (rand-nth (keys (ns-publics 'clojure.core))))
Run Code Online (Sandbox Code Playgroud)
编辑:
虽然上面的代码在repl中工作得很好,但如果你提前使用编译,你会发现每次都会产生相同的结果.这是因为语句resulting-symbol
中的let
语句是在编译阶段产生的.提前编译一次意味着将该值烘焙到.jar中.我们真正想做的是将评估推doc
送到运行时.所以,让我们重写eval-doc
为一个函数.
(defn eval-doc
[sym]
(eval `(doc ~sym)))
Run Code Online (Sandbox Code Playgroud)
就那么简单.
归档时间: |
|
查看次数: |
176 次 |
最近记录: |