Как заставить функцию Clojure принимать переменное количество параметров?

80

Я изучаю Clojure и пытаюсь определить функцию, которая принимает переменное количество параметров ( вариативная функция) и суммирует их (да, точно так же, как процедура +). Однако я не знаю, как реализовать такую ​​функцию.

Все, что я могу сделать, это:

(defn sum [n1, n2] (+ n1 n2))

Конечно, эта функция принимает два параметра и только два параметра. Пожалуйста, научите меня, как заставить его принимать (и обрабатывать) неопределенное количество параметров.

Rodrigoalvesvieira
источник

Ответы:

107

В общем, в некоммутативном случае вы можете использовать apply :

(defn sum [& args] (apply + args))

Поскольку сложение коммутативно, должно работать что-то вроде этого:

(defn sum [& args] (reduce + args))

& вызывает argsпривязку к оставшейся части списка аргументов (в данном случае ко всему списку, так как слева от него ничего нет &).

Очевидно, такое определение суммы не имеет смысла, поскольку вместо этого:

(sum a b c d e ...)

вы можете просто написать:

(+ a b c d e ....)
проверка души
источник
3
Да, не имеет смысла, но это хорошая иллюстрация к вашему ответу. Благодарю.
rodrigoalvesvieira
@soulcheck: есть ли способ передать seqв вашу функцию суммы. Например: (sum '(1 2 3)) и результат 6?
avichalp
@avichalp, это была бы другая функция. просто удалите &из любой версии
soulcheck
1
@soulcheck: Нет. Я имею в виду использование той же сигнатуры функции. Я новичок в Clojure, поэтому могу четко изложить здесь свою точку зрения. Я хотел бы знать, что в python я могу использовать * args, и если функция определена так, что она принимает * args (например def fn(*args): pass), я могу вызвать ее, указав список, например fn (* list_of_args). Могу ли я сделать то же самое в clojure?
avichalp
@avichalp вызов def fn(*args): passне будет , fn([1,2,3])но fn(1,2,3)(очевидно , в зависимости от того, что вы хотите сделать точно, но я стараюсь следовать духу здесь)
soulcheck
31

Иехоанатан упоминает перегрузку арности, но не приводит прямых примеров. Вот о чем он говорит:

(defn special-sum
  ([] (+ 10 10))
  ([x] (+ 10 x))
  ([x y] (+ x y)))

(special-sum) => 20

(special-sum 50) => 60

(special-sum 50 25) => 75

Девин Уолтерс
источник
Также работает с лямбдами:(fn ([] (+ 10 10)) ([x] (+ 10 x)) ([x y] (+ x y)))
Erik Kaplun
17
 (defn my-sum
  ([]  0)                         ; no parameter
  ([x] x)                         ; one parameter
  ([x y] (+ x y))                 ; two parameters
  ([x y & more]                   ; more than two parameters


    (reduce + (my-sum x y) more))
  )
Hariszaman
источник
10

defnэто макрос, который упрощает определение функций. Clojure поддерживает перегрузку арности в одном функциональном объекте, функции саморегулирования и переменной арности, используя&

С http://clojure.org/functional_programming

Viebel
источник
3
(defn sum [& args]
  (print "sum of" args ":" (apply + args)))

Это берет любое количество аргументов и складывает их.

Аристотль
источник
Дубликат ответа @soulcheck stackoverflow.com/a/9242671/1327651
nha