Thumbnail
Thumbnail

Reputation: 13473

Is there an adapter that enables a function to ignore superfluous arguments?

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

Answers (3)

Phil Lord
Phil Lord

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

A. Webb
A. Webb

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

galdre
galdre

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

Related Questions