I am trying to get ONLY the docstring of a function in Clojure, nevertheless I have encountered several problems as all the functions that I find actually print the function signature + docstring.
So for example (doc map) will actually print something like.
clojure.core/map
([f coll] [f c1 c2] [f c1 c2 c3] [f c1 c2 c3 & colls])
Returns a lazy sequence consisting of the result of applying f to the ...
I am only interested in getting the docstring not printing it nor having its namespace or arity. What I am looking for is something like
(get-doc function-name) which would return a string with
"Returns a lazy sequence consisting of the result of applying f to the ..."
Is this possible in Clojure?
You can do this:
(:doc (meta #'map))
map itself is just a symbol, that is, a name. This symbol resolves to a var, which is accessed by the special form #'map. The value of this var is the actual function, and the docstring for the function is stored as metadata on the var.
Therefore, #'map gives you the var (this can also be done using (var map)), meta gives you the metadata for that var, and :doc extracts the docstring.
For more information, have a look at var, metadata, and special forms.
Based bsvingen's answer we can define a macro which returns the docstring like:
(defmacro docstring [symbol]
`(:doc (meta (var ~symbol))))
If we specifically want it to be a function, e.g. for use with map, you can write it as
(defn docstring [symbol]
(:doc (meta (resolve symbol))))
Related
What I am trying to achieve is to implement an abstract class with reify inside a macro, but the expressions that should return on expansion time would be supplied to the macro quoted:
(defmacro a-printable
[body]
`(reify Printable
(print [this g# pf# page#]
(if (= page# 0)
(do
~body ;; the supplied part
(Printable/PAGE_EXISTS))
(Printable/NO_SUCH_PAGE)))
(def exp '(do (.translate g (.getImageableX pf) (.getImageableY pf))
(.drawString g "foo" 10 10))) ;; the form to pass
(a-printable exp)
The proplem is that in the expression I pass, I want to use the automatic generated vars defined inside the macro and inside reify g#, pf#.
I tried to add the quoted expression with (ns-resolve *ns* g) (ns-resolve *ns* pf) but with no lack, I am not sure that is being resolved inside the macro.
The g is java.awt.Graphics which is an abstract class and the pf is java.awt.print.PageFormat, which is normal class with constructor.
Does anyone has any idea how to achieve that, or turn me to the correct direction?
I believe the trick is that if you don't want namespaced symbols in a macro, you can prefix them with ~', e.g. ~'g. Then I did the following other modifications to your macro:
Prefix the body parameter with & to make it variable length.
Splice the body into the macro
Remove the parenthesis around (Printable/PAGE_EXISTS) and (Printable/NO_SUCH_PAGE): Those are static variable values that you want to return, not function calls.
This is what the fixed macro looks like:
(defmacro a-printable
[& body]
`(reify Printable
(print [~'this ~'g ~'pf ~'page]
(if (= ~'page 0)
(do
~#body ;; Splice it!
Printable/PAGE_EXISTS)
Printable/NO_SUCH_PAGE))))
And this is how you create an instance. Note that I do not need to wrap the argument to the macro with do:
(def p (a-printable
(.translate g (.getImageableX pf) (.getImageableY pf))
(.drawString g "foo" 10 10)))
A note however: I am not sure it is a good practice to introduce new symbols, such as pf and g, but I cannot find the reference mentioning why that would be a bad practice. There are ways of achieving similar things to what is being asked in this question without resorting to macros. The version that does not use macros is not much longer:
(defn a-printable-fn [body-fn]
(reify Printable
(print [this g pf page]
(if (= ~'page 0)
(do
(body-fn this g pf page)
Printable/PAGE_EXISTS)
Printable/NO_SUCH_PAGE))))
(def p (a-printable-fn
(fn [this g pf page]
(.translate g (.getImageableX pf) (.getImageableY pf))
(.drawString g "foo" 10 10))))
How do you write a function to extract a docstring from a function?
I have been able to make the following work in a repl:
(:doc (meta (var identity)))
user=> "Returns its argument."
But when I wrap this in a function such as below:
(defn get-doc-string [f]
(:doc (meta (var f))))
The compiler says the following:
Unable to resolve var: f in this context
Is there another way to do this?
You have to quote, or better, syntax quote the symbol and use find-var:
(defn get-doc-string [f]
(:doc (meta (find-var f))))
Then you can do:
(get-doc-string `identity)
var is a special form which takes a symbol argument - you are passing f which cannot be resolved. You can create a macro:
(defmacro get-doc-string [sym]
`(:doc (meta (var ~sym))))
although clojure already implements this functionality in clojure.repl/doc.
I am trying to print the documentation for all functions in a given namespace by invoking the following expression in a REPL:
(doseq
[f (dir-fn 'clojure.repl)]
(doc f))
However the invocation of this expression returns nil without printing the documentation to the REPL. I know this might have to do with doc being a macro, but I'm a Clojure novice and am not entirely sure how to understand the problem.
Why does this expression return nil without printing the documentation?
How can this expression be modified so that it prints the documentation for each function in a given namespace?
Thanks!
Update: Combined both provided answers:
(defn ns-docs [ns']
(doseq [[symbol var] (ns-interns ns')]
(newline)
(println symbol)
(print " ")
(println (:doc (meta var)))))
(ns-docs 'clojure.repl)
I would, instead, start here:
The Clojure CheatSheet
ClojureDocs.org
Clojure-Doc.org (similar name, but different)
The API & Reference sections at Clojure.org
Note that doc is in the namespace clojure.repl, which reflects its intended usage (by a human in a repl). Here is some code that will also iterate on a namespace & print doc strings (using a different technique):
(doseq [[fn-symbol fn-var] (ns-interns 'demo.core)]
(newline)
(println fn-symbol)
(println (:doc (meta fn-var))))
where demo.core is the namespace of interest.
Note that ns-interns gives you both a symbol and var like:
fn-symbol => <#clojure.lang.Symbol -main>
fn-var => <#clojure.lang.Var #'demo.core/-main>
The meta function has lots of other info you may want to use someday:
(meta fn-var) =>
<#clojure.lang.PersistentArrayMap
{ :arglists ([& args]),
:doc "The Main Man!",
:line 9, :column 1,
:file "demo/core.clj",
:name -main,
:ns #object[clojure.lang.Namespace 0x14c35a06 "demo.core"]}>
While this probably won't help you with answering your question, the problem of evaluating macro's comes up a lot when you are learning Clojure.
Macros are responsible for the evaluation of their arguments. In this case clojure.repl/doc will ignore the current lexical context and assume that the symbol f that you're giving it is the name of a function you want to see the documentation for. It does this because it's intended to be used at the REPL, and is assuming you wouldn't want to type quotes all the time.
As f doesn't exist, it prints nothing. Then doseq returns nil, since it exists to do something for side effects only - hence starting in do. In order to pass an argument to a macro that refuses to respect the lexical context like this, you need to write the code for each element in the list.
You can do this by hand, or by constructing the code as data, and passing it to eval to execute. You can do this in an imperative style, using doseq:
(doseq [f (ns-interns 'clojure.repl)]
(eval `(doc ~(symbol "clojure.repl" (str (first f))))))
or in a slightly more Clojurey way (which will allow you to see the code that it would execute by removing eval from the end and running it at the REPL):
(->> (ns-interns 'clojure.repl)
(map #(list 'clojure.repl/doc (symbol "clojure.repl" (str (first %)))))
(cons `do)
eval)
In both of these we use quote and syntax-quote to construct some code from the list of symbols reflected from the namespace, and pass it to eval to actually execute it. This page on Clojure's weird characters should point you in the right direction for understanding what's going on here.
This an example of why you shouldn't write macro's, unless you've got no other options. Macro's do not compose, and are often difficult to work with. For a more in depth discussion, Fogus's talk and Christophe Grand's talk are both good talks.
Why does this expression return nil without printing the documentation?
Because the doc macro is receiving the symbol f from your loop, instead of a function symbol directly.
How can this expression be modified so that it prints the documentation for each function in a given namespace?
(defn ns-docs [ns']
(let [metas (->> (ns-interns ns') (vals) (map meta) (sort-by :name))]
(for [m metas :when (:doc m)] ;; you could filter here if you want fns only
(select-keys m [:name :doc]))))
(ns-docs 'clojure.repl)
=>
({:name apropos,
:doc "Given a regular expression or stringable thing, return a seq of all
public definitions in all currently-loaded namespaces that match the
str-or-pattern."}
...
)
Then you can print those maps/strings if you want.
Is there a way to generically get metadata for arguments to a function in clojure? The answer posted in this question does not, actually, work in general:
user> (defn foo "informative dox!" [] 1)
#'user/foo
user> (defmacro get-docs [func] `(:doc (meta (var ~func))))
#'user/get-docs
user> (get-docs foo)
"informative dox!"
user> (get-docs (identity foo))
; Evaluation aborted.
user> (defn process-docs [f] (let [docs (get-docs f)] (reverse docs)))
; Evaluation aborted.
The second-to-last line doesn't work because you can't call var on the list (identity foo), and the last line doesn't even compile because the compiler complains about being unable to resolve f.
Most of the solutions for this problem I've found rely on the idea that you have access to the symbol in the function's definition, or something like that, so that you can do something like (resolve 'f) or (var f). But I want something that I can use on the argument to a function, where you don't know that information.
Essentially, I'd like an expression I can put in place of the question marks below to get the metadata of #'map:
(let [x map] (??? x))
its a mouthful though possible:
(let [x map]
(:doc (meta (second (first (filter #(and (var? (second %))
(= x (var-get (second %))))
(ns-map *ns*)))))))
produces the desired result:
"Returns a lazy sequence consisting of the result of applying f to the
set of first items of each coll, followed by applying f to the set
of second items in each coll, until any one of the colls is\n exhausted. Any remaining items in other colls are ignored. Function
f should accept number-of-colls arguments."
under the hood Namespaces are essentially maps of names to vars and the vars contain functions. you can search the contents of these vars for the one that matches the function you are seeking and then look at it's associated var and get the metadata from that var.
I have a symbol "a" bound to a function:
(defn a []
(println "Hello, World"))
user=> a
#<user$a__292 user$a__292#97eded>
user=> (a)
Hello, World
nil
Then I use syntax-quote, it "resolves the symbol in the current context, yielding a fully-qualified symbol", according to Clojure documentation. But why can't I use it the same way as unqualified symbol?
user=> `a
user/a
user=> (`a)
java.lang.IllegalArgumentException: Wrong number of args passed to: Symbol (NO_SOURCE_FILE:0)
Second question: if I have a symbol in a list, why can't I evaluate it the same way as if I would evaluate the symbol directly?
user=> (def l '(a 1 2))
#'user/l
user=> 'l
l
user=> (first l)
a
user=> ((first l))
java.lang.IllegalArgumentException: Wrong number of args passed to: Symbol (NO_SOURCE_FILE:0)
I have a suspicion I have a fatal flaw somewhere in the fundamental understanding of how symbols work here. What is wrong with above code?
REPL = read eval print loop. Step through the read-eval process.
READ: Clojure sees the string "(`a)", parses it and ends up with a data structure. At read time, reader macros are expanded and not much else happens. In this case, the reader expands the backquote and ends up with this:
user> (read-string "(`a)")
((quote user/a))
EVAL: Clojure tries to evaluate this object. Evaluation rules vary depending on what kind of object you're looking at.
Some objects evaluate as themselves (numbers, strings, keywords etc.).
A Symbol is evaluated by resolving it in some namespace to obtain some value (usually).
A List is evaluated by macro-expanding the list until there are no macros left, then recursively evaluating the first item in the list to obtain some resulting value, then using the value of the first item in the list to decide what to do. If the first value is a special form, special stuff happens. Otherwise the first value is treated as a function and called with the values of the rest of the list (obtained by recursively evaluating all of the list's items) as parameters.
etc.
Refer to clojure.lang.Compiler/analyzeSeq in the Clojure source to see the evaluation rules for lists, or clojure.lang.Compiler/analyzeSymbol for symbols. There are lots of other evaluation rules there.
Example
Suppose you do this:
user> (user/a)
The REPL ends up doing this internally:
user> (eval '(user/a))
Clojure sees that you're evaluating a list, so it evaluates all items in the list. The first (and only) item:
user> (eval 'user/a)
#<user$a__1811 user$a__1811#82c23d>
a is not a special form and this list doesn't need to be macroexpanded, so the symbol a is looked up in the namespace user and the resulting value here is an fn. So this fn is called.
Your code
But instead you have this:
user> (eval '((quote user/a)))
Clojure evaluates the first item in the list, which is itself a list.
user> (eval '(quote user/a))
user/a
It evaluated the first item in this sub-list, quote, which is a special form, so special rules apply and it returns its argument (the Symbol a) un-evaluated.
The symbol a is the value in this case as the fn was the value up above. So Clojure treats the Symbol itself as a function and calls it. In Clojure, anything that implements the Ifn interface is callable like an fn. It so happens that clojure.lang.Symbol implements Ifn. A Symbol called as a function expects one parameter, a collection, and it looks itself up in that collection. It's meant to be used like this:
user> ('a {'a :foo})
:foo
This is what it tries to do here. But you aren't passing any parameters, so you get the error "Wrong number of args passed to: Symbol" (it expects a collection).
For your code to work you'd need two levels of eval. This works, hopefully you can see why:
user> (eval '((eval (quote user/a))))
Hello, world
user> ((eval (first l)))
Hello, world
Note that in real code, using eval directly is usually a really bad idea. Macros are a better idea by far. I'm only using it here for demonstration.
Look in Compiler.java in the Clojure source to see how this all plays out. It's not too hard to follow.
Using a Symbol as a function is not the same thing as evaluating it. Symbols-as-functions work the same way as keywords-as-functions. Like this:
user=> (declare a)
#'user/a
user=> (def a-map {'a "value"})
#'user/a-map
user=> ('a a-map)
"value"
user=>
This is not how you would normally use a symbol. They are more commonly used for looking up vars in a namespace, and when generating code in a macro.
To break down the layers of indirection, let's define "x" as 1 and see what happens:
user=> (def x 1)
#'user/x
Using def, we have created a "var." The name of the var is the symbol user/x. The def special form returns the var itself to the repl, and this is what we can see printed. Let's try and get a hold of that var:
user=> #'x
#'user/x
The #' syntax is a reader macro that says "give me the var referred to by the following symbol." And in our case, that symbol is "x". We got the same var back as before. Vars are pointers to values, and can be dereferenced:
user=> (deref #'x)
1
But the var needs to be found before it can be dereferenced. This is where the callability of symbols come into play. A namespace is like a map, where the symbols are keys and vars are the values, and when we plainly name a symbol, we implicitly look up its var in our namespace. Like this:
user=> ('x (.getMappings *ns*))
#'user/x
Although, in reality, it is probably more like this:
user=> (.findInternedVar *ns* 'x)
#'user/x
And now we have come full circle on the journey of the unquoted symbol:
user=> (deref (.findInternedVar *ns* 'x))
1
user=> x
1
The two are not entirely equal, though. Because the evaluator does this for all symbols, including deref and *ns*.
The thing about quoting is that you essentially bypass this whole mechanism, and just get the plain symbol back. Like the #' reader macro get plain vars back, the ` and ' reader macros will get plain symbols back, with or without a namespace qualification respectively:
user=> 'x
x
user=> `x
user/x
user=> (def l '(a 1 2))
user=> ((first l))
Turn this into:
user=> (def l `(~a 1 2))
The ~ here resolves the symbol a to its corresponding var, and the backtick makes unquoting work.
In general, you must understand the difference between vars (which are bound to something) and symbols (which are never bound to anything).
I'll try to explain it (in the hope that my exaplanation does not confuse you further):
user=> (def v "content")
#'user/content
-> defines a var in the current namespace under the symbol 'v (fully qualified 'user/v, assuming this is the current namespace), and binds it (the var, not the symbol) to the object "content".
user=> v
"content"
-> resolves v to the var, and gets the bound value
user=> #'v
#'user/v
-> resolves to the var itself
user=> 'v
v
-> does not resolve anything, just a plain symbol (unfortunately, the REPL does not indicate this, printing 'v as v)
user=> `v
user/v
-> as you already quoted, resolves to the symbol in the current context (namespace), but the result is still a symbol (fully qualified), not the var user/v
user=> '(v)
(v)
-> plain quoting, does not resolve anything
user=> `(v)
(user/v)
-> syntax-quote, same as quoting, but resolves symbols to namespace-qualified symbols
user=> `(~v)
("content")
-> resolve the symbol to its var (which is implicitely dereferenced), yielding its bound object