3

I am new to Clojure and I am currently stuck with below code which throws a NullPointerException when I run it like this:

(mapset inc [1 1 2 2])

(defn mapset
    [fn v]
    (loop [[head & tail] v result-set (hash-set)]
      (if (nil? head)
        result-set)
      (conj result-set (fn head))
      (recur tail result-set)))

When I print the result-set in the if block it prints an empty set whereas I expect a set like this: #{2 3}

After trying to interpret the stacktrace I guess that the NullPointerException has something to do with the following line: (conj result-set (fn head)). The stacktrace and the fact that the resulting set is empty leads me to believe that the inc operation somehow gets called with nil as input.

I am glad about any explanation of why this error happens

The mentioned (shortend) stacktrace looks like this:

java.lang.NullPointerException

Numbers.java: 1013  clojure.lang.Numbers/ops
Numbers.java:  112  clojure.lang.Numbers/inc
core.clj:  908  clojure.core/inc
core.clj:  903  clojure.core/inc
REPL:    6  user/mapset
REPL:    1  user/mapset 

1 Answer 1

3

I made some small changes:

(defn mapset [f v]
  (loop [[head & tail] v
         result-set (hash-set)]
    (if (nil? head)
      result-set
      (let [res (f head)]
        (recur tail (conj result-set res))))))

(defn x-1 []
  (mapset inc [1 1 2 2]))

(x-1)
;;=> #{3 2}

So now mapset will call the function f on each of your inputs from v, then put the result of that call into the hash-set that was created at the outset.

The problem was in the control flow logic of your if statement. The flow of execution was continuing on after the if. Thus the function fn (which I renamed to f, rather than leave it as the name of a macro) was being called even when head was nil, which was not what you intended.

As originally coded the if (which would more clearly have been a when) was doing nothing useful. But once I realised you meant to have an if, but closed the paren off too early, then the answer slotted into place. Hence minor changes fixed the problem - your underlying logic was sound - and the amended function just worked.

Sign up to request clarification or add additional context in comments.

2 Comments

Thank you very much. How could I not get that... You also have reminded me to use let for better clarity
np. I used the let to help with debugging - to have less going on on the one line. You could certainly get rid of it and I probably would - as res is only used once and is a silly name.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.