¿Cómo hacer que una función de Clojure tome un número variable de parámetros?

80

Estoy aprendiendo Clojure y estoy tratando de definir una función que tome un número variable de parámetros (una función variada ) y los resuma (sí, como el procedimiento +). Sin embargo, no sé cómo implementar dicha función.

Todo lo que puedo hacer es:

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

Por supuesto, esta función toma dos parámetros y solo dos parámetros. Enséñame cómo hacer que acepte (y procese) un número indefinido de parámetros.

rodrigoalvesvieira
fuente

Respuestas:

107

En general, el caso no conmutativo que puede utilizar aplica :

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

Dado que la suma es conmutativa, algo como esto también debería funcionar:

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

& hace argsque se vincule al resto de la lista de argumentos (en este caso, la lista completa, ya que no hay nada a la izquierda de &).

Obviamente, definir una suma así no tiene sentido, ya que en lugar de:

(sum a b c d e ...)

puedes simplemente escribir:

(+ a b c d e ....)
control de alma
fuente
3
Sí, no tiene sentido, pero es una buena ilustración para tu respuesta. Gracias.
rodrigoalvesvieira
@soulcheck: ¿hay alguna manera de pasar un seqa su función de suma? Por ejemplo: (sum '(1 2 3)) y el resultado es 6?
avichalp
@avichalp esa sería otra función. basta con retirar &de cualquiera de las versiones
soulcheck
1
@soulcheck: No. Me refiero a usar la misma firma de función. Soy un novato en clojure, por lo tanto, puedo expresar mi punto claramente aquí. Lo que me gustaría saber es que en Python puedo usar * args y si una función está definida de manera que tome * args (por ejemplo def fn(*args): pass), puedo llamarla dando una lista como fn (* list_of_args). ¿Puedo hacer lo mismo en clojure?
avichalp
@avichalp, la llamada a def fn(*args): passno sería, fn([1,2,3])pero fn(1,2,3)(obviamente, dependiendo de lo que quieras hacer exactamente, pero estoy tratando de seguir el espíritu aquí)
soulcheck
31

Yehoanathan menciona la sobrecarga de aridad pero no proporciona un ejemplo directo. Esto es de lo que está hablando:

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

(special-sum) => 20

(special-sum 50) => 60

(special-sum 50 25) => 75

Devin Walters
fuente
También funciona con lambdas:(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
fuente
10

defnes una macro que simplifica un poco la definición de funciones. Clojure admite la sobrecarga de arity en un objeto de función única, autorreferencia y funciones de arity variable usando&

De http://clojure.org/functional_programming

viebel
fuente
3
(defn sum [& args]
  (print "sum of" args ":" (apply + args)))

Esto toma cualquier número de argumentos y los suma.

aristotll
fuente
Duplicado de @soulcheck respuesta stackoverflow.com/a/9242671/1327651
nha