Jak sprawić, by funkcja Clojure przyjmowała zmienną liczbę parametrów?

81

Uczę się Clojure i próbuję zdefiniować funkcję, która pobiera zmienną liczbę parametrów ( funkcja wariadyczna ) i podsumowuje je (tak, podobnie jak procedura +). Jednak nie wiem, jak zaimplementować taką funkcję

Wszystko, co mogę zrobić, to:

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

Oczywiście ta funkcja przyjmuje tylko dwa parametry i tylko dwa parametry. Naucz mnie, jak sprawić, by akceptował (i przetwarzał) niezdefiniowaną liczbę parametrów.

rodrigoalvesvieira
źródło

Odpowiedzi:

108

Ogólnie rzecz biorąc, nie przemiennej przypadku można użyć zastosowanie :

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

Ponieważ dodawanie jest przemienne, powinno też działać coś takiego:

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

& powoduje argszwiązanie się z pozostałą częścią listy argumentów (w tym przypadku całą listą, ponieważ nie ma nic po lewej stronie &).

Oczywiście definiowanie takiej sumy nie ma sensu, ponieważ zamiast:

(sum a b c d e ...)

możesz po prostu napisać:

(+ a b c d e ....)
soulcheck
źródło
3
Tak, nie ma sensu, ale to dobra ilustracja twojej odpowiedzi. Dzięki.
rodrigoalvesvieira
@soulcheck: czy istnieje sposób na przekazanie a seqdo funkcji sumującej . Na przykład: (sum '(1 2 3)) a wynik to 6?
avichalp
@avichalp to byłaby inna funkcja. po prostu usuń &z dowolnej wersji
soulcheck
1
@soulcheck: Nie. Mam na myśli używanie tego samego podpisu funkcji. Jestem nowicjuszem w ubraniu, więc jestem w stanie jasno przedstawić tutaj mój punkt widzenia. To, co chciałbym wiedzieć, jest w Pythonie. Mogę używać * args i jeśli funkcja jest zdefiniowana tak, że przyjmuje * args (np. def fn(*args): pass), Mogę ją wywołać, podając listę taką jak fn (* list_of_args). Czy mogę zrobić to samo w ubraniu?
avichalp
@avichalp wezwanie do def fn(*args): passnie byłoby, fn([1,2,3])ale fn(1,2,3)(oczywiście w zależności od tego, co dokładnie chcesz zrobić, ale staram się tu podążać za duchem)
soulcheck
31

Yehoanathan wspomina o przeciążaniu arity, ale nie podaje bezpośredniego przykładu. Oto, o czym on mówi:

(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
źródło
Działa również z lambdami:(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
źródło
10

defnto makro, które sprawia, że ​​definiowanie funkcji jest trochę prostsze. Clojure obsługuje przeciążanie macierzy w pojedynczym obiekcie funkcji, samoodniesienie i funkcje o zmiennej wartości przy użyciu&

Z http://clojure.org/functional_programming

viebel
źródło