Why am I getting NPE in the following code?

The following code executes as expected, but gives a NullPointerException at the end. What am I doing wrong here?

 (ns my-first-macro) (defmacro exec-all [& commands] (map (fn [c] `(println "Code: " '~c "\t=>\tResult: " ~c)) commands)) (exec-all (cons 2 [4 5 6]) ({:k 3 :m 8} :k) (conj [4 5 \d] \e \f)) ; Output: ; Clojure 1.2.0-master-SNAPSHOT ; Code: (cons 2 [4 5 6]) => Result: (2 4 5 6) ; Code: ({:k 3, :m 8} :k) => Result: 3 ; Code: (conj [4 5 d] ef) => Result: [4 5 def] ; java.lang.NullPointerException (MyFirstMacro.clj:0) ; 1:1 user=> #<Namespace my-first-macro> ; 1:2 my-first-macro=> 

(For the correct syntax for the highlighted code, go here .)

+7
macros lisp clojure
source share
2 answers

Take a look at the extension that happens:

 (macroexpand '(exec-all (cons 2 [4 5 6]))) => ((clojure.core/println "Code: " (quote (cons 2 [4 5 6])) "\t=>\tResult: " (cons 2 [4 5 6]))) 

As you can see, your extension has an extra pair of parentheses, which means that Clojure is trying to execute the result of the println function, which is zero.

To fix this, I suggest changing the macro to include a β€œdo” on the front panel, for example

 (defmacro exec-all [& commands] (cons 'do (map (fn [c] `(println "Code: " '~c "\t=>\tResult: " ~c)) commands))) 
+11
source share

Since the OP has requested other possible ways of writing this macro (see comments on the accepted answer), here it is:

 (defmacro exec-all [& commands] `(doseq [c# ~(vec (map (fn [c] `(fn [] (println "Code: " '~c "=> Result: " ~c))) commands))] (c#))) 

It will expand to about

 (doseq [c [(fn [] (println "Code: " '(conj [2 3 4] 5) "=> Result: " (conj [2 3 4] 5))) (fn [] (println "Code: " '(+ 1 2) "=> Result: " (+ 1 2)))]] (c)) 

Note that the forms fn , whose values ​​will be attached to c , are collected in the vector at the macro expansion time.

Needless to say, the original version is simpler, so I think (do ...) is the perfect solution. :-)

Interaction Example:

 user=> (exec-all (conj [2 3 4] 5) (+ 1 2)) Code: (conj [2 3 4] 5) => Result: [2 3 4 5] Code: (+ 1 2) => Result: 3 nil 
+6
source share

All Articles