【问题标题】:Unable to get random (doc) from a namespace无法从命名空间中获取随机(文档)
【发布时间】:2012-11-25 18:34:57
【问题描述】:

我想为某个命名空间显示随机(文档)页面。

我可以得到的随机函数名:

user=> (rand-nth (keys (ns-publics 'clojure.core)))
unchecked-char

当我尝试将其传递给(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)

我是 Clojure 的新手,我不知道如何处理这个...我尝试将其转换为正则表达式并使用 (find-doc) 但也许有更好的方法来做到这一点...

【问题讨论】:

标签: clojure


【解决方案1】:

说明

这里的问题是doc 是一个宏,而不是一个函数。您可以使用 repl 中的 source 宏来验证这一点。

(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))))))

如果您是 Clojure(和 lisps)的新手,您可能还没有遇到过宏。作为一个毁灭性的简短解释,函数在已评估代码上运行,宏在未评估代码上运行 - 即源代码本身。

这意味着当你键入时

(doc (rand-nth (keys (ns-publics 'clojure.core))))

doc 尝试对实际代码行进行操作 - (rand-nth (keys (ns-publics 'clojure.core))) - 而不是评估结果(返回的符号)。代码只不过是 Clojure 中的一个列表,这就是错误告诉您无法将列表转换为符号的原因。

解决方案

所以,您真正想做的是评估代码,然后在结果上调用doc。我们可以通过编写另一个宏来做到这一点,该宏首先评估您提供的代码,然后将其传递给doc

(defmacro eval-doc
 [form]
  (let [resulting-symbol (eval form)]
   `(doc ~resulting-symbol)))

您可以传递eval-doc 任意形式,它会在将它们传递给doc 之前对其进行评估。现在我们可以开始了。

(eval-doc (rand-nth (keys (ns-publics 'clojure.core))))

编辑:

虽然上述方法在 repl 中运行良好,但如果您使用提前编译,您会发现它每次都会产生相同的结果。这是因为let语句中的resulting-symbol是在编译阶段产生的。提前编译一次意味着这个值被烘焙到 .jar 中。我们真正想做的是将doc 的评估推到运行时。所以,让我们将eval-doc 重写为一个函数。

(defn eval-doc
  [sym]
  (eval `(doc ~sym)))

就这么简单。

【讨论】:

  • 谢谢@Beyamor,它可以在 REPL 中使用,但是当我尝试在新的 Leiningen 项目中调用它时,然后 "(rand-nth (keys (ns-publics 'clojure.core))) " 总是产生相同的结果
  • (ns cotd.core (:gen-class) (:use [clojure.repl :only (doc)])) (defmacro eval-doc [form] (let [resulting-symbol (eval form)] `(doc ~resulting-symbol))) (defn- random-function-name [] (rand-nth (keys (ns-publics 'clojure.core))))) (defn -main "显示随机文档页面" [& args] (eval-doc (random-function-name)))
  • 啊。抱歉,我没有考虑到这一点。我已经编辑了上面的答案。如果还有其他问题,请告诉我,感谢您的耐心等待。
猜你喜欢
  • 2013-05-11
  • 2011-03-30
  • 1970-01-01
  • 2020-06-26
  • 2022-01-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多