Reputation: 13473
I'm looking for a Clojure function, let's call it anyargs
, that allows its function argument to ignore superfluous arguments. So that, for example,
((anyargs cons) :a [:b :c] :d) ; => (:a :b :c)
If the function argument took several arities, it would be good if the largest fitting one was chosen.
Upvotes: 4
Views: 125
Reputation: 3057
Not cleanly, because Clojure does not expose the arity of its functions through a public API.
Given that you must know the arity of the function that you want to apply, it's easy enough to achieve this in the specific case, where n is the arity
#(apply f (take n %&))
Upvotes: 1
Reputation: 26446
I think you'd have to hack it.
(defn max-arities [f]
(reduce
#(merge-with max % {(.getName %2) (alength (.getParameterTypes %2))})
{}
(seq (.getDeclaredMethods (class +)))))
(defn anyargs [f]
(let [accept (if (instance? clojure.lang.RestFn f)
identity
(partial take ((max-arities f) "invoke")))]
(fn [& args] (apply f (accept args)))))
((anyargs cons) :a [:b :c] :d) ;=> (:a :b :c)
((anyargs +) 1 2 3 4 5 6 7 8 9 10) ;=> 55
Upvotes: 1
Reputation: 2339
One approach would be to examine the function to see how many arguments it takes. This link covers ways to detect just that.
If you modify that answer slightly, you get the maximum number of arguments:
(defn n-args [f]
(-> f class .getDeclaredMethods last .getParameterTypes alength))
This only works if the methods array is organized by the length of arguments, which on my system appears to be the case. If you really want to make sure,
(defn n-args [f]
(apply max
(map #(-> % .getParameterTypes alength)
(-> f class .getDeclaredMethods))))
Then you can write:
(defn anyargs [f]
(let [n (n-args f)]
(fn [& args] (apply f (take n args)))))
This uses reflection, and it breaks down with variadic functions, but presumably you wouldn't use it with variadic functions. It's the best I can think of at the moment, aside from providing a wrapper that catches ArityExceptions and keeps retrying with fewer and fewer arguments until it works.
Upvotes: 4