Search code examples
clojure

How this Clojure macro expansion works?


I am in the process of learning Clojure, through "Clojure for the Brave and True".

In macro lessons, I was trying the below macro,

(defmacro report
  [to-try]
  `(let [result# ~to-try]
     (if result#
       (println (quote ~to-try) "was successful:" result#)
       (println (quote ~to-try) "was not successful:" result#))))

And below are couple of my experiments with the macro and the respective outputs.

1

(map #(report %) ['(= 1 2) '(= 1 1)])
; p1__26622# was successful: (= 1 2)
; p1__26622# was successful: (= 1 1)

2

map #(report %) ['false 'true])
; p1__26612# was not successful: false
; p1__26612# was successful: true

And my questions are,

  • Why in the former case the macro printed true for both values?
  • In my understanding the second is exactly equivalent to the former. But why it gives a different result?

Solution

  • Why in the former case the macro printed true for both values?

    Your report macro is receiving quoted lists as inputs, not expressions that can be evaluated to true/false. Any list is truthy, even if it contains an expression that would evaluate to false. This would give you the expected result:

    (report (= 1 2)) ;; evaluates to false
    

    In my understanding the second is exactly equivalent to the former. But why it gives a different result?

    It's not exactly equivalent because the first example is examining lists and the second is examining quoted booleans. Your second example evaluates 'false as false because that's how if treats it:

    (if 'false 0 1) => 1