Wie kann eine Clojure-Funktion eine variable Anzahl von Parametern annehmen?

79

Ich lerne Clojure und versuche, eine Funktion zu definieren, die eine variable Anzahl von Parametern (eine variable Funktion) akzeptiert und zusammenfasst (yep, genau wie die + -Prozedur). Ich weiß jedoch nicht, wie ich eine solche Funktion implementieren soll

Alles was ich tun kann ist:

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

Natürlich akzeptiert diese Funktion nur zwei Parameter und zwei Parameter. Bitte bringen Sie mir bei, wie es eine undefinierte Anzahl von Parametern akzeptiert (und verarbeitet).

rodrigoalvesvieira
quelle

Antworten:

106

Im Allgemeinen nichtkommutative Fall können Sie verwenden , gelten :

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

Da Addition kommutativ ist, sollte so etwas auch funktionieren:

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

& bewirkt args, dass an den Rest der Argumentliste gebunden wird (in diesem Fall die gesamte Liste, da links davon nichts steht &).

Offensichtlich macht es keinen Sinn, eine solche Summe zu definieren, da anstelle von:

(sum a b c d e ...)

Sie können einfach schreiben:

(+ a b c d e ....)
Soulcheck
quelle
3
Ja, macht keinen Sinn, aber es ist ein gutes Beispiel für Ihre Antwort. Vielen Dank.
Rodrigoalvesvieira
@soulcheck: Gibt es eine Möglichkeit, a seqan Ihre Summenfunktion zu übergeben? Zum Beispiel: (Summe '(1 2 3)) und das Ergebnis ist 6?
Avichalp
@avichalp das wäre eine andere Funktion. einfach &aus jeder Version entfernen
Soulcheck
1
@soulcheck: Nein. Ich meine mit der gleichen Funktionssignatur. Ich bin ein Neuling in Clojure, daher kann ich hier meinen Standpunkt klar zum Ausdruck bringen. Was ich wissen möchte, ist, dass ich in Python * args verwenden kann. Wenn eine Funktion so definiert ist, dass sie * args benötigt (z. B. def fn(*args): pass), kann ich sie aufrufen, indem ich eine Liste wie fn (* list_of_args) gebe. Kann ich das Gleiche in Clojure tun?
Avichalp
@avichalp der Anruf def fn(*args): passwäre nicht fn([1,2,3])aber fn(1,2,3)(offensichtlich abhängig davon, was Sie genau tun möchten, aber ich versuche, dem Geist hier zu folgen)
Soulcheck
30

Yehoanathan erwähnt die Überlastung der Arität, liefert jedoch kein direktes Beispiel. Hier ist, wovon er spricht:

(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
quelle
Funktioniert auch mit 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
quelle
10

defnist ein Makro, das das Definieren von Funktionen etwas vereinfacht. Clojure unterstützt die Arity-Überladung in einem einzelnen Funktionsobjekt, Selbstreferenz- und Variable-Arity-Funktionen mithilfe von&

Von http://clojure.org/functional_programming

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

Dies nimmt eine beliebige Anzahl von Argumenten und addiert sie.

aristotll
quelle
Duplikat von @soulcheck Antwort stackoverflow.com/a/9242671/1327651
nha