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

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

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

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

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

to возвращает 3 тоже. Но он возвращается

java.ленг.IllegalArgumentException: неверное число пройденных args (3) к.

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

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

4 ответов


вот что я бы сказал:

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

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

(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 ...)), но некоторые из них, конечно, другие короче.


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

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

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

(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)))

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


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

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

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

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