3

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?

2
  • 2
    Since your assignment does not state the return value, this could as well be just sideeffects, so you could also do (defn triplicate [f] (f) (f) (f)), which then returns the last result. Or add a nil at the end to even prevent that. A defn has an impliciy do around the body. Commented Dec 26, 2017 at 13:30
  • @cfrick Makes a lot of sense, thanks! Commented Dec 26, 2017 at 15:29

3 Answers 3

5

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.

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

3 Comments

(def triplicate #(dotimes [i 3] (%))) seems very readable and succinct. Thanks!
wait! but it doesn't return the result of the function call.. so it is worthy only for side effects.. (triplicate #(inc 10)) => nil. Also i would argue about juxt: since clojure is the functional language, such things as juxt, comp, partial, apply etc is the natural way of programming for it, while side effecting and imperative things (like dotimes, while...) although being totally understandable for FP beginner coming from other languages, are there for the narrow range of special occasions, and should be avoided otherwise. This answer seems counter-educating to me
I don't often use dotimes, since it only makes sense with side-effecting code. However, calling (f) 3 times in a row in a (do ...) form implies that (f) is side-effecting (since the results of the first 2 calls to (f) are discarded).
4
(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.

1 Comment

Thank you so much for the help, I decided to mark @leetwinski's answer as accepted because of the extra information, but your answer is just as valid.
4

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]

Comments

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.