boucekv
boucekv

Reputation: 1230

How to ignore unnecessary arguments?

Is there simple way ho to ignore unnecessary arguments?

For example: (#(+ %1 %2) 1 2) returns 3

I would like to force this code

(#(+ %1 %2) 1 2 3)

to returns 3 too. But it returns

java.lang.IllegalArgumentException: Wrong number of args (3) passed to.

How to change #(+ %1 %2)?

I hope there is some more elegant way than #(+ (nth %& 0) (nth %& 1)).

Upvotes: 13

Views: 3532

Answers (4)

Gert
Gert

Reputation: 3859

This works for any number of arguments, and is readable:

(fn [& args] (apply + args))

If you only want to use the first 2 arguments (as per Alex' comment):

(fn [& args] (apply + (take 2 args)))

You can use it directly:

((fn [& args] (apply + (take 2 args))) 1 2)
; => 3

Or bind the function to a symbol like this:

(let [f (fn [& args] (apply + (take 2 args)))]
  (f 1 2))
; => 3

Or create a var:

(def f (fn [& args] (apply + (take 2 args))))

Or a function:

(defn f [& args] (apply + (take 2 args)))

The best definition depends on your use case.

Upvotes: 6

blueiur
blueiur

Reputation: 1507

how about this?

(#(apply + (take 2 %&)) 1 2 3 4 5)
;; => 3

Upvotes: 4

Omri Bernstein
Omri Bernstein

Reputation: 1933

Here's what I would go with:

=> ((fn [a b & _] (+ a b)) 1 2 3)
=> 3

This creates an anonymous function that takes any number of arguments, but just adds the first two. The _ symbol isn't doing anything special, it's just idiomatic for "I don't care about this thing, but I need it bound somehow". If you think you are going to be doing this a lot, then you would probably want to define it:

(defn add-first-two
  [a b & _]
  (+ a b))

If you are really into the #() syntax, you will have to include %& somewhere in the definition for it to "realize" that it should take any number of arguments. It doesn't mean you would have to index it as you show, it would just have to be present somewhere. Here's an example:

=> (#(do %& (+ %1 %2)) 1 2 3)
=> 3

On the other hand, this solution involves some sort of processing of %&, where you don't need any, and may slow things down slightly (I'm not sure about this, maybe someone else can give me feedback on this). A rather fun solution would be to just stick %& inside a (comment ...) block, which will evaluate to nil.

=> (#(do (comment %&) (+ %1 %2)) 1 2 3)
=> 3

An even more exotic solution would be to use #_..., which is a lot like (comment...) except that the reader actually removes it from evaluation, as though you had simply typed nothing there. This way, maybe we could stick it inside the body of (+ ...) to shorten the code.

=> (#(+ %1 %2 #_%&) 1 2 3)
=> 3

What do you know, it worked. I'd actually never tried this one before, and I am pretty surprised to see it work. Apparently, there is some processing before the #_... section is removed. Strange.

If you don't like any of these weird comment solutions, and the do isn't doing it for you, you could always put it inside an (if nil ...) block:

=> (#(if nil %& (+ %1 %2)) 1 2 3)
=> 3

Well, after all that, I still like the first solution best (using (fn ...)), but some of these others are certainly shorter.

Upvotes: 19

tnoda
tnoda

Reputation: 1524

user> (#(do %& (+ % %2)) 1 2)
3
user> (#(do %& (+ % %2)) 1 2 3)
3

It is not very elegant, but I think it is acceptable.

Upvotes: 1

Related Questions