How do I modify a :arglists to a Clojure fn or macro?
Asked Answered
E

4

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).

Estefanaestel answered 20/9, 2012 at 20:21 Comment(0)
S
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]))
Scholem answered 20/9, 2012 at 21:9 Comment(1)
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.Cakewalk
C
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!)

Cakewalk answered 1/11, 2012 at 20:56 Comment(2)
For future finders of this question: this is the correct answer, the others are workarounds or flat out incorrect.Radmen
@Radmen Might be worth downvoting the others….Sit
S
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]))
Scholem answered 20/9, 2012 at 21:9 Comment(1)
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.Cakewalk
U
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"}
Urogenital answered 20/9, 2012 at 20:49 Comment(0)
L
-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!

Loci answered 20/9, 2012 at 21:39 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.