Как игнорировать ненужные аргументы?

Есть ли простой способ ho игнорировать ненужные аргументы?

Например: (#(+ %1 %2) 1 2) возвращает 3

Я хотел бы заставить этот код

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

также возвращает 3. Но он возвращает

java.lang.IllegalArgumentException: Неверное количество аргументов (3) прошло к.

Как изменить #(+ %1 %2)?

Я надеюсь, что есть более элегантный способ, чем #(+ (nth %& 0) (nth %& 1)).

Ответ 1

Вот что мне нужно:

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

Это создает анонимную функцию, которая принимает любое количество аргументов, но просто добавляет первые два. Символ _ не делает ничего особенного, это просто идиоматично для "Меня это не волнует, но мне нужно как-то связать". Если вы думаете, что собираетесь делать это много, то вы, вероятно, захотите определить его:

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

Если вы действительно используете синтаксис #(), вам нужно будет включить %& где-нибудь в определении, чтобы он "понял", что он должен принимать любое количество аргументов. Это не значит, что вам придется индексировать его, как вы показываете, он просто должен быть где-то присутствовать. Вот пример:

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

С другой стороны, это решение включает в себя некоторую обработку %&, где вам не нужны, и может немного замедлить работу (я не уверен в этом, может быть, кто-то может дать мне обратную связь на этом). Довольно забавным решением было бы просто вставить %& внутри блока (comment ...), который будет оцениваться до nil.

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

Еще более экзотическим решением было бы использовать #_..., что очень похоже на (comment...), за исключением того, что читатель фактически удаляет его из оценки, как будто вы просто ничего не набрали. Таким образом, возможно, мы могли бы вставить его внутри тела (+ ...), чтобы сократить код.

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

Что ты знаешь, это сработало. Я бы никогда не пробовал это раньше, и я очень удивлен, увидев, что это работает. По-видимому, есть некоторая обработка, прежде чем раздел #_... будет удален. Странно.

Если вам не нравятся какие-либо из этих странных решений для комментариев, а do не делает этого для вас, вы всегда можете поместить его в блок (if nil ...):

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

Ну, в конце концов, мне все равно нравится первое решение лучше всего (используя (fn ...)), но некоторые из них, безусловно, короче.

Ответ 2

Это работает для любого количества аргументов и читается:

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

Если вы хотите использовать только первые 2 аргумента (согласно комментарию Alex):

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

Вы можете использовать его напрямую:

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

Или привяжите функцию к символу, подобному этому:

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

Или создайте var:

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

Или функция:

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

Лучшее определение зависит от вашего варианта использования.

Ответ 3

как насчет этого?

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

Ответ 4

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

Это не очень элегантно, но я думаю, что это приемлемо.