7

I'm trying to convert the following example to the new Clojure 1.5 reducers library:

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

When I change it- I get the following error:

(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)

Can someone give me a correct solution?

hawkeye
  • 34,745
  • 30
  • 150
  • 304

1 Answers1

12

Notice that it works when you substitute max with +.

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

The difference is the fact that unlike + max does not have a case for an invocation with no arguments. r/fold requires the combining function—i.e. max—to provide an identity value when called without arguments. For * it's 1, for + it's 0.

A potential solution would be to define a max' which acts as max but when called with no arguments it returns the negative infinity—an identity element for the max function.

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

The same result can be achieved using the r/monoid function.

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

For further discussion see Reducers - A Library and Model for Collection Processing, section Simplicity is Opportunity.

Jan
  • 11,636
  • 38
  • 47
  • Ok - it looks like they discussed it in the Google group here: https://groups.google.com/forum/?fromgroups=#!searchin/clojure/reduce$20max/clojure/EJ9hOZ8yaos/TULab4pndwoJ – hawkeye Jan 10 '13 at 04:27
  • 1
    @Jan There's a helper fn called `monoid` for this, using that, your second code example reduces to e.g. `(r/fold (r/monoid max #(Double/NEGATIVE_INFINITY)) (r/map inc (range 10)))` – Evgeniy Berezovsky Apr 01 '13 at 08:37
  • @EugeneBeresovksy, thanks, I didn't know about the `monoid` function. I've updated the answer. – Jan Apr 01 '13 at 18:10