6

How do I modify the :arglist attribute for a clojure fn or macro?

(defn tripler ^{:arglists ([b])} [a] (* 3 a))

(defn ^{:arglists ([b])} quadrupler [a] (* 4 a))

% (meta #'tripler) => 
  {:arglists ([a]), :ns #<Namespace silly.testing>, :name tripler, :line 1, :file "NO_SOURCE_PATH"}

% (meta #'quadrupler) => 
  {:arglists ([a]), :ns #<Namespace silly.testing>, :name quadrupler, :line 1, :file "NO_SOURCE_PATH"}

Ok, no luck there, so I tried doing the following.

(def tripler
  (with-meta trippler
    (assoc (meta #'tripler) :arglists '([c]))))

% (with-meta #'tripler) => 
  {:ns #<Namespace silly.testing>, :name tripler, :line 1, :file "NO_SOURCE_PATH"}

Hmm, so now the :arglists key is gone? Well, I give up, how do I do this? I would simply like to modify the value of :arglists. The examples above use defn, but I would also like to know how to set the :arglists using a macro (defmacro).

4 Answers 4

6

You don't need to do anything as ugly as the suggestions so far. If you take a look at defn's own arglists…

user=> (:arglists (meta #'clojure.core/defn))
([name doc-string? attr-map? [params*] prepost-map? body]
 [name doc-string? attr-map? ([params*] prepost-map? body) + attr-map?])

You're looking for attr-map. Here's an example.

user=> (defn foo
         "does many great things"
         {:arglists '([a b c] [d e f g])}
         [arg] arg)
#'user/foo
user=> (doc foo)
-------------------------
user/foo
([a b c] [d e f g])
  does many great things
nil

(In that case, arglists is a total lie. Don't do that!)

Sign up to request clarification or add additional context in comments.

2 Comments

For future finders of this question: this is the correct answer, the others are workarounds or flat out incorrect.
@whereswalden Might be worth downvoting the others….
3

alter-meta! changes the metadata on a var. The metadata on the function is not relevant, only the var.

(alter-meta! #'tripler assoc :arglists '([b]))

1 Comment

While that's true, defn allows you to specify an attr-map, which is a cleaner way to do what Stephen wants. See my answer below.
2

defn does not leave room to mangle the metadata which is OK because it's just a macro that wraps def. You can use def directly instead of defn:

core> (def  ^{:arglists '([b])} tripler (fn [a] (* 3 a)))
#'core/tripler                                                                                 
core> (meta #'tripler)
{:arglists ([b]), :ns #<Namespace autotestbed.core>, :name tripler, :line 1, :file "NO_SOURCE_FILE"}

or you define the var tripler with defn:

core> (defn tripler [a] (* 3 a))
#'autotestbed.core/tripler                                                               

then redefine the var with the same contents and different metadata:

core> (def ^{:arglists '([b])} tripler  tripler)
#'autotestbed.core/tripler                                                                                 
autotestbed.core> (meta #'tripler)
{:arglists ([b]), :ns #<Namespace autotestbed.core>, :name tripler, :line 1, :file "NO_SOURCE_FILE"}

Comments

-1

Expanding on amalloy's answer (please give him credit):

user=> (defn foo "prints bar" [] (println "bar"))
#'user/foo

user=> (doc foo)
-------------------------
user/foo
([])
  prints bar
nil

user=> (meta #'foo)
{:arglists ([]), :ns #<Namespace user>, :name foo, :doc "prints bar", :line 1, :file "NO_SOURCE_PATH"}

user=> (alter-meta! #'foo assoc :arglists '([blah]))
{:arglists ([blah]), :ns #<Namespace user>, :name foo, :doc "prints bar", :line 1, :file "NO_SOURCE_PATH"}

user=> (doc foo)
-------------------------
user/foo
([blah])
  prints bar
nil

user=> (meta #'foo)
{:arglists ([blah]), :ns #<Namespace user>, :name foo, :doc "prints bar", :line 1, :file "NO_SOURCE_PATH"}

user=> (foo)
bar
nil

Sneaky!

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.