'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 |