4

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))
Community
  • 1
  • 1
ben w
  • 2,490
  • 14
  • 19

1 Answers1

5

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.

Arthur Ulfeldt
  • 90,827
  • 27
  • 201
  • 284
  • Wonderful answer. Might I recommend a threading macro for readability? – Omri Bernstein Sep 15 '12 at 01:44
  • Wow, that is a mouthful, even with a threading macro: `(defn get-meta [o] (->> *ns* ns-map (filter (fn [[_ v]] (and (var? v) (= o (var-get v))))) first second meta))`. Thanks! – ben w Sep 15 '12 at 04:21
  • Hm, it's still not really totally general, though, because the function has to be able to find the argument in `*ns*`. So there are arguments/uses of the function for which it will fail and the only way I can see to avoid that is to look in *all* namespaces, which seems ... inelegant. – ben w Sep 15 '12 at 05:54