Given a function x in clojure how can I programatically get a count of the number of arguments?
eg:
(fn a [b c] ...) has has two arguments
(fn a [] ...) has has zero arguments
Except for functions with variable-length argument lists, the number of arguments in a function call must be the same as the number of parameters in the function definition. This number can be zero. The maximum number of arguments (and corresponding parameters) is 253 for a single function.
The open() is used to return a file in either the read or the write mode. The user uses the open() function with two arguments: the file name and the mode (read or write) to return a file object.
While a function can only have one argument of variable length of each type, we can combine both types of functions in one argument.
Many times, we tend to add too many parameters to a function. But that's not the best idea: on the contrary, when a function requires too many arguments, grouping them into coherent objects helps writing simpler code.
Clojure - Functions with Multiple Arguments. Clojure functions can be defined with zero or more parameters. The values you pass to functions are called arguments, and the arguments can be of any type. The number of parameters is the function’s arity. This chapter discusses some function definitions with different arities.
Clojure is a functional language. Functions are first-class and can be passed-to or returned-from other functions. Most Clojure code consists primarily of pure functions (no side effects), so invoking with the same inputs yields the same output.
Most Clojure code consists primarily of pure functions (no side effects), so invoking with the same inputs yields the same output. defn defines a named function:
In Clojure, the partial function is a more general version of this. 13) Define a function two-fns which takes two functions as arguments, f and g. It returns another function which takes one argument, calls g on it, then calls f on the result, and returns that.
If you have access to the var that holds the function you can get the argument count by accessing its metadata in the following way:
(defn arities [v]
(->> v meta :arglists (map count)))
(defn a [])
(defn b [_ _])
(map arities [#'a #'b])
;= ((0) (2))
arities
will return a seq with all the arities for the function. This has the disadvantage that for a variadic argument vector ([_ _ & _]
) it will return (4).
(defn c [_ _ & _])
(arities #'c)
;= (4)
This could be fixed by removing the &
symbol from all the argument lists.
(defn arities [v]
(->> v
meta
:arglists
(map #(remove #{'&} %))
(map count)))
(arities #'c)
;= (3)
If you don't have access to the var, the following is a little function that I've used to detect the argument count of a function. It uses reflection so it's not the approach you might want to take if you need good performance. Also take into account that it relies on implementation details.
(defn n-args [f]
(-> f class .getDeclaredMethods first .getParameterTypes alength))
(defn a [])
(defn b [_ _])
(defn c [_ _ & _])
(map n-args [a b c])
;= (0 2 3)
EDIT
After giving the answer another read, I realized the result 3 for a variadic function defined as (defn x [_ _ & _] ,,,)
, is actually quite misleading since it's the same result you would get for a function with 3 arguments. The following version will return :variadic
, instead of a specific number, for the argument vectors that contain the &
symbol (except for the case [&]
where &
it's the actual argument name). As mentioned in a comment by Jeremy Heiler getting the argument count from the metadata only works if the value for :arglists
is not manually changed.
(defn a [_])
(defn b [_ _])
(defn c [_ _ & _])
(defn d [_ _ _])
(defn e [&])
(defn variadic? [s]
(and (some #{'&} s)
(not (every? #{'&} s))))
(defn arities [v]
(->> v
meta
:arglists
(map #(if (variadic? %) :variadic %))
(map #(if (sequential? %) (count %) %))))
(map arities [#'a #'b #'c #'d #'e])
;= ((1) (2) (:variadic) (3) (:variadic))
The reflection version for this is a little more complicated and it relies on more implementation details (i.e. "Is this or that function declared?" or "Does the function extend the class X?"), so I wouldn't recommend using that approach.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With