Unable to get random (doc) from a namespace
clojure
Solution
Explanation
The problem here is that `doc` is a macro, not a function. You can verify this with the `source` macro in the 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))))))
If you're new to Clojure (and lisps), you might not have encountered macros yet. As a devastatingly brief explanation, where functions operate on evaluated code, macros operate on unevaluated code - that is, source code itself.
This means that when you type
(doc (rand-nth (keys (ns-publics 'clojure.core))))
`doc` attempts to operate on the actual line of code - `(rand-nth (keys (ns-publics 'clojure.core)))` - rather than the evaluated result (the symbol this returns). Code being nothing more than a list in Clojure, this is why the error is telling you that a list can't be cast to a symbol.
Solution
So, what you really want to do is evaluate the code, then call `doc` on the result. We can do this by writing another macro which first evaluates the code you give it, then passes that to `doc`.
(defmacro eval-doc
[form]
(let [resulting-symbol (eval form)]
`(doc ~resulting-symbol)))
You can pass `eval-doc` arbitrary forms and it will evaluate them before passing them to `doc`. Now we're good to go.
(eval-doc (rand-nth (keys (ns-publics 'clojure.core))))
Edit:
While the above works well enough in the repl, if you're using ahead ahead-of-time compilation, you'll find that it produces the same result every time. This is because the `resulting-symbol` in the `let` statement is produced during the compilation phase. Compiling once ahead of time means that this value is baked into the .jar. What we really want to do is push the evaluation of `doc` to runtime. So, let's rewrite `eval-doc` as a function.
(defn eval-doc
[sym]
(eval `(doc ~sym)))
Simple as that.
Problem
I want to display random (doc) page for some namespace. The random function name I can get by: ``` user=> (rand-nth (keys (ns-publics 'clojure.core))) unchecked-char ``` When I try to pass this to (doc) I get this: ``` 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) ``` I'm new to Clojure and I'm not sure how to deal with this... I tried to convert this into regexp and use (find-doc) but maybe there is a better way to do this...