Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Clojure constantly and map function

Why does this bit of Clojure code:

user=> (map (constantly (println "Loop it.")) (range 0 3))

Yield this output:

Loop it.
(nil nil nil)

I'd expect it to print "Loop it" three times as a side effect of evaluating the function three times.

like image 991
Mike Avatar asked Jul 23 '12 13:07

Mike


2 Answers

constantly doesn't evaluate its argument multiple times. It's a function, not a macro, so the argument is evaluated exactly once before constantly runs. All constantly does is it takes its (evaluated) argument and returns a function that returns the given value every time it's called (without re-evaluating anything since, as I said, the argument is evaluated already before constantly even runs).

If all you want to do is to call (println "Loop it") for every element in the range, you should pass that in as the function to map instead of constantly. Note that you'll actually have to pass it in as a function, not an evaluated expression.

like image 74
sepp2k Avatar answered Oct 25 '22 23:10

sepp2k


As sepp2k rightly points out constantly is a function, so its argument will only be evaluated once.

The idiomatic way to achieve what you are doing here would be to use doseq:

(doseq [i (range 0 3)]
  (println "Loop it."))

Or alternatively dotimes (which is a little more concise and efficient in this particular case as you aren't actually using the sequence produced by range):

(dotimes [i 3]
  (println "Loop it."))

Both of these solutions are non-lazy, which is probably what you want if you are just running some code for the side effects.

like image 43
mikera Avatar answered Oct 25 '22 22:10

mikera