Caroline Xu
Caroline Xu

Reputation: 31

ArityException Wrong number of args (0) passed to: core/max

If I run this code, I will get an error "ArityException Wrong number of args (0) passed to: core/max"

(apply max (filter #(zero? (mod % 7)) (range 1 3)))

However, if I run this code

(apply max (filter #(zero? (mod % 7)) (range 1 10)))

then I get the result 7.

Is there anyone who can help me to figure out this problem?

Upvotes: 3

Views: 1819

Answers (3)

Anton Harald
Anton Harald

Reputation: 5924

(filter #(zero? (mod % 7)) (range 1 3))

this, produces an empty sequence.

However, max must be called with at least one argument. When you apply an empty sequence to it, it's called with zero arguments, and this produces the arity exception.

You could do something like this:

(defn my [a b]
  (let [result (filter #(zero? (mod % 7)) (range a b))]
    (if (zero? (count result))
        nil ; or 0 or.. whatever
        (apply max result))))

apply and reduce

Because the question came up, here's a short explanation of the difference between apply and reduce.

They are two totally different concepts, however, in the following case both do the same job when combined with max.

let xs be any collection of numbers.

(apply max xs) equals (reduce max xs)

apply

Usually functions are called with a number of arguments, so one can call max like so: (max 3), or (max 5 9), or (max 4 1 3) ... As noticed before: just (max) would be an arity exception.

Apply however, lets someone call a function passing the arguments in the form of a collection. So in correspondence to the last example, the following is possible: (apply max [3]), or (apply max [5 9]), or (apply max [4 1 3]) ... Just (apply max []) or even (apply max) would lead to the same arity exception as above. This is useful in many cases.

reduce

Reduce in contrast is a bit trickier. Along with map and filter it's absolutely essential for functional programming languages like Clojure.

The main idea of reduce is to walk through a collection, in each step desired information from the current item is processed and added to a memo or accumulator.

Say, one wants to find out the sum of all numbers in a collection. Let xs be [3 4 5 23 9 4].

(reduce + xs) would do the job.

more explicitly one could write: (reduce (fn [memo value] (+ memo value)) xs) The function which is passed as the first argument to reduce expects two parameters: The first one is the memo, the second one the value of the current item in the collection. The function is now called for each item in the collection. The return value of the function is saved as the memo.
Note: that the first value of the collection is used as an initial value of the memo, hence the iteration starts with the second value of the collection. Here's what it is doing:

(+ 3 4)    ; memo is 7 now
(+ 7 5)    ; memo is 12 now
(+ 12 23)  ; memo is 35 now
(+ 35 9)   ; memo is 44 now
(+ 44 4)   ; memo is 48 now

(There's also a way to specify the start value of the memo, see clojuredocs.org for more details)

This works equally with max. In each iteration the value of the current item is compared with the memo. Each time the highest value is saved to the memo: Hence the memo in this case represents the "maximum value until now".

So (reduce max [4 1 3 5 2]) is calculated like this:

(max 4 1) ; memo is 4
(max 4 3) ; memo is 4
(max 4 5) ; memo is 5
(max 5 2) ; memo is 5

so?

Which one to use now? It showed that there's not really a notable difference in the time that (reduce max (range 100000000)) and (apply max (range 100000000)) take. Anyways, the apply solution looks easier to me, but that's just my opinion.

Upvotes: 3

DanLebrero
DanLebrero

Reputation: 8593

There are no numbers divisible by 7 between 1 and 3, the result of filter in your first example returns an empty sequence, which means that the first example if calling (apply max []) which is the same as calling (max). max requires at least one parameter, hence the ArityException.

A couple of options to fix it:

(last (filter #(zero? (mod % 7)) (range 1 3))

or

(if-let [by-7 (seq (filter #(zero? (mod % 7)) (range 1 3)))]
  (apply max by-7)
  nil ;; or whatever value in case the collection is empty
  )

Upvotes: 2

Joni
Joni

Reputation: 111219

According to the error message, the number of arguments that are passed to max is 0, and that is wrong. I guess it makes sense because it's impossible to compute the maximum for an empty list.

The reason why max gets no arguments is that there are no numbers divisible by 7 between 1 and 3.

Upvotes: 0

Related Questions