Мне скорее понравились элементы и от Stu и от samjudson решения и работавший их вместе в то, что я думаю, применимая комбинация:
public static string Ordinal(this int number)
{
const string TH = "th";
var s = number.ToString();
number %= 100;
if ((number >= 11) && (number <= 13))
{
return s + TH;
}
switch (number % 10)
{
case 1:
return s + "st";
case 2:
return s + "nd";
case 3:
return s + "rd";
default:
return s + TH;
}
}
Арность функции хранится в метаданных переменной.
(:arglists (meta #'str))
;([] [x] [x & ys])
Для этого требуется, чтобы функция была либо определена с использованием defn
, либо метаданных : arglists
, предоставленных явно.
user=> (defn test-func
([p1] "Arity was 1.")
([p1 p2] "Arity was 2.")
([p1 p2 & more-args] (str "Arity was " (+ 2 (count more-args)))))
#'user/test-func
user=> (test-func 1)
"Arity was 1."
user=> (test-func 1 2)
"Arity was 2."
user=> (test-func 1 2 3)
"Arity was 3"
user=> (test-func 1 2 3 4)
"Arity was 4"
user=> (test-func 1 2 3 4 5) ;...
"Arity was 5"
Скрытое отражение:
(defn arg-count [f]
(let [m (first (.getDeclaredMethods (class f)))
p (.getParameterTypes m)]
(alength p)))
Или:
(defn arg-count [f]
{:pre [(instance? clojure.lang.AFunction f)]}
(-> f class .getDeclaredMethods first .getParameterTypes alength))