6

I am learning about pmap and wrote the following function:

(pmap #((println "hello from " (-> (Thread/currentThread) .getName)) 
         (+ %1 %2)) 
   [1 1 1] [-1 -1 -1])

When run, the result is a NullPointerException

(hello from  clojure-agent-send-off-pool-4
hello from  clojure-agent-send-off-pool-3
hello from  clojure-agent-send-off-pool-5
NullPointerException   user/eval55/fn--56 (NO_SOURCE_FILE:11)

Why is this happening? I have understood and observed the body of a fn to be an implicit do.

noahlz
  • 10,202
  • 7
  • 56
  • 75

2 Answers2

8

The anonymous fn literal #() does not have an implicit do.

dnolen
  • 18,496
  • 4
  • 62
  • 71
  • And I see (using `macroexpand`) that `#()` expands to `fn*` not `fn` (the macro). – noahlz Sep 21 '12 at 16:26
  • So you'd replace #() with fn[x]? – octopusgrabbus Sep 21 '12 at 16:29
  • Either use `(fn [] (println ) ...)` or `#((do (println ...)` – noahlz Sep 21 '12 at 16:31
  • 1
    `fn*` vs `fn` is not relevant here. The difference is that `#((x %))` expands to `(fn [%] ((x %)))`, not to `(fn [%] (x %))`. – amalloy Sep 21 '12 at 19:31
  • Not sure why you think "not relevant" - just an observation. See http://stackoverflow.com/questions/12488479/what-is-the-difference-between-fn-and-fn Also, I had an error: it should be `#(do (println ...` – noahlz Sep 22 '12 at 10:43
2

You have println in 2 parens so the result of println is evaluated. println always returns nil hence the NullPointerException.

Try removing the extra parens from the #():

   (pmap #(println "hello from " 
         (-> (Thread/currentThread) .getName) 
         (+ %1 %2)) 
          [1 1 1] [-1 -1 -1] )

EDIT:

Then you will need the do as mentioned in other comments like:

(pmap #(do (println "hello from " 
     (-> (Thread/currentThread) .getName)) 
     (+ %1 %2)) 
      [1 1 1] [-1 -1 -1] )

The reason the do is necessary in the #() reader macro is not that functions don't include an implicit do but has to do with the way the macro expands. Basically, that macro assumes a single form hence the need for the explicit do.

M Smith
  • 1,988
  • 15
  • 28
  • It expands to: `(fn* [p1__13# p2__14#] (println "hello from " (-> (Thread/currentThread) .getName) (+ p1__13# p2__14#)))`. However, now you've broken the intent of my `pmap` function. Check out the return value. – noahlz Sep 21 '12 at 20:17
  • What do you want the result to be? – M Smith Sep 21 '12 at 21:11