'Learn Clojure: NullPointerException on triplicate

I'm taking the beginner tutorial on the Clojure official site.

One exercise asks you to do the following:

7) Define a function triplicate which takes another function and calls it three times, without any arguments.

Which I solved as follows:

(defn triplicate [f] ((f) (f) (f)))

The problem is that when used, at the very end a NullPointerException is thrown, for which I cannot identify the cause.

user=> (triplicate #(println "hello, world"))
hello, world
hello, world
hello, world
NullPointerException   user/triplicate (NO_SOURCE_FILE:115)

The following is the output of pst, should it be useful:

user=> (pst)
NullPointerException
        user/triplicate (NO_SOURCE_FILE:145)
        user/triplicate (NO_SOURCE_FILE:145)
        user/eval376 (NO_SOURCE_FILE:146)
        user/eval376 (NO_SOURCE_FILE:146)
        clojure.lang.Compiler.eval (Compiler.java:7062)
        clojure.lang.Compiler.eval (Compiler.java:7025)
        clojure.core/eval (core.clj:3206)
        clojure.core/eval (core.clj:3202)
        clojure.main/repl/read-eval-print--8572/fn--8575 (main.clj:243)
        clojure.main/repl/read-eval-print--8572 (main.clj:243)
        clojure.main/repl/fn--8581 (main.clj:261)
        clojure.main/repl (main.clj:261)
nil

What could the cause be?



Solution 1:[1]

IMHO, the clearest solution is:

(do
  (f) 
  (f)
  (f))

Evaluating multiple expressions is the sole purpose of do. If you don't want the cut-and-paste repetition, the best way is:

(dotimes [i 3]
  (f))

Using the vector form slightly obscures the repetition goal and implies you want 3 of the return value of (f).


Footnote: I would never use juxt as it is an obscure function that will leave most people scratching their heads and running to The Clojure CheatSheet to look up its definition.

Solution 2:[2]

(defn triplicate [f] ((f) (f) (f)))

Which returns: (nil nil nil) the thing is nil is not a function. Calling nil causes NullPointerException.

You could write like this:

(defn triplicate [f] [(f) (f) (f)])
;;=> [nil nil nil] which is fine, because you are keeping nils in a vector.

Solution 3:[3]

the problem is in this part: ((f) (f) (f))

this form means: "call function f and then call it's result as function with 2 arguments: result of f call and result of f call"

you can fix it with [(f) (f) (f)]

or just use juxt:

user> (def triplicate #(juxt % % %))
#'user/triplicate

user> ((triplicate #(println "hello")))
;;=> hello
;;=> hello
;;=> hello
[nil nil nil]

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Ertu?rul Çetin
Solution 3 leetwinski