Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I determine number of arguments to a function in Clojure?

Tags:

clojure

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
like image 797
yazz.com Avatar asked Jun 19 '13 17:06

yazz.com


People also ask

How many arguments we send to a function?

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.

How many arguments does the open function take?

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.

What is the minimum number of arguments that functions can have?

While a function can only have one argument of variable length of each type, we can combine both types of functions in one argument.

Can a function have too many arguments?

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.

What is a function with multiple arguments in Clojure?

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.

Is CL Clojure a functional language?

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.

What is a DEFN function in Clojure?

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:

What is a partial function in Clojure?

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.


1 Answers

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.

like image 85
juan.facorro Avatar answered Sep 27 '22 19:09

juan.facorro