2013-01-07 11 views
6

Próbuję przekonwertować następujący przykład do nowych Clojure 1,5 reduktorów Biblioteka:Clojure reduktory biblioteka - składany z max

(reduce max (map inc (range 10))) 
;=> 10 

Kiedy zmienić to- pojawia się następujący błąd:

(r/fold max (r/map inc (range 10))) 
;ArityException Wrong number of args (0) passed to: core$max clojure.lang.AFn.throwArity (AFn.java:437) 

Czy ktoś może dać mi prawidłowe rozwiązanie?

Odpowiedz

10

Należy zauważyć, że działa on po zastąpieniu max przez +.

(r/fold + (r/map inc (range 10))) 
; => 55 

Różnica jest fakt, że unlike +maxdoes not have podstawy do inwokacji bez argumentów. r/fold wymaga funkcji łączącej - tj. max -do podania wartości tożsamości po wywołaniu bez argumentów. Dla * jest to 1, dla + jest to 0.

Potencjalnym rozwiązaniem byłoby zdefiniowanie max' pełniące max ale gdy wywołana bez argumentów zwraca ona ujemny infinity- an identity element dla funkcji max.

(defn max' 
    ([] Double/NEGATIVE_INFINITY) 
    ([& args] (apply max args))) 
(r/fold max' (r/map inc (range 10))) 
; => 10 

Ten sam rezultat można osiągnąć stosując funkcję r/monoid.

(r/fold (r/monoid max #(Double/NEGATIVE_INFINITY)) (r/map inc (range 10))) 

Dla dalszej dyskusji zobaczyć Reducers - A Library and Model for Collection Processing sekcja Prostota jest szansa.

+0

OK - wygląda na to, że omówili to w grupie Google tutaj: https://groups.google.com/forum/?fromgroups=#!searchin/clojure/reduce$20max/clojure/EJ9hOZ8yaos/TULab4pndwoJ – hawkeye

+1

@ Jan Istnieje pomocnik fn o nazwie 'monoid', w tym przypadku twój drugi przykład kodu zmniejsza się do np '(r/fold (r/monoid max # (Double/NEGATIVE_INFINITY)) (r/map inc (zakres 10)))' –

+0

@EugeneBeresovksy, dziękuję, nie wiedziałem o funkcji 'monoid'. Zaktualizowałem odpowiedź. – Jan