Ответ 1
Если у вас есть доступ к var, который содержит эту функцию, вы можете получить счетчик аргументов, обратившись к его метаданным следующим образом:
(defn arities [v]
(->> v meta :arglists (map count)))
(defn a [])
(defn b [_ _])
(map arities [#'a #'b])
;= ((0) (2))
arities
вернет seq со всеми arities для функции. Это имеет тот недостаток, что для вектора вариационных аргументов ([_ _ & _]
) он вернется (4).
(defn c [_ _ & _])
(arities #'c)
;= (4)
Это можно устранить, удалив символ &
из всех списков аргументов.
(defn arities [v]
(->> v
meta
:arglists
(map #(remove #{'&} %))
(map count)))
(arities #'c)
;= (3)
Если у вас нет доступа к var, следующая функция - это небольшая функция, которую я использовал для определения количества аргументов функции. Он использует отражение, поэтому не тот подход, который вы можете предпринять, если вам нужна хорошая производительность. Также учтите, что он опирается на детали реализации.
(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)
ИЗМЕНИТЬ
После того, как вы ответили другим, я понял, что результат 3 для вариационной функции, определяемой как (defn x [_ _ & _] ,,,)
, на самом деле довольно вводит в заблуждение, так как тот же результат вы получите для функции с тремя аргументами. Следующая версия вернет :variadic
вместо определенного числа для векторов аргументов, содержащих символ &
(за исключением случая [&]
, где &
это имя фактического аргумента). Как упоминалось в комментарии Джереми Хейлера, подсчет аргументов из метаданных работает только в том случае, если значение для :arglists
не изменено вручную.
(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))
Вариант отражения для этого немного сложнее, и он опирается на более подробные сведения о реализации (т.е. "Объявлена ли та или иная функция?" или "Разве функция расширяет класс X?" ), поэтому я бы не рекомендовал используя этот подход.