3

名前空間のランダム (doc) ページを表示したい。

私が得ることができるランダムな関数名:

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)を使用しようとしましたが、これを行うためのより良い方法があるかもしれません...

4

1 に答える 1

5

説明

ここでの問題は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)))

そのような単純な。

于 2012-11-25T19:42:50.723 に答える