説明
ここでの問題は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))))))
Clojure (および Lisp) を初めて使用する場合は、まだマクロに遭遇していない可能性があります。壊滅的に簡単な説明として、関数が評価されたコードで動作する場合、マクロは評価されていないコード、つまりソースコード自体で動作します。
つまり、入力すると
(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で十分に機能しますが、事前コンパイルを使用している場合は、毎回同じ結果が生成されることがわかります。これはresulting-symbol
、ステートメントの in がlet
コンパイル フェーズで生成されるためです。事前に一度コンパイルすると、この値が .jar に焼き付けられます。本当にやりたいことは、 の評価doc
を実行時にプッシュすることです。eval-doc
では、関数として書き直してみましょう。
(defn eval-doc
[sym]
(eval `(doc ~sym)))
そのような単純な。