Original Answer
I think this is what you are looking for:
(defmacro is [expr value]
`(if (= ~expr ~value)
true
(println "Expected " ~value "In" (str (quote ~expr))
"But Evaluated to" ~expr)))
what (quote ~expr)
does is bring the s-expression represented by expr
into your "template", but prevents it from being evaluated, then applying str
to the unevaluated s-expression makes it into a string for concatenation with the other strings of the error message. So, :
user=> (is (+ 2 2) 5)
Expected 5 In (+ 2 2) But Evaluated to 4
produces the desired behavior.
Rather than using 'yes
to report success, you can simply use true
as the report for the success of the test, giving:
user=> (is (+ 2 2) 4)
true
and avoiding the problem of 'yes
being returned as a qualified symbol. If you need a symbol for some reason, then you could make a keyword:
(defmacro is [expr value]
`(if (= ~expr ~value)
:yes
(println "Expected " ~value "In" (str (quote ~expr))
"But Evaluated to" ~expr)))
user=> (is (+ 2 2) 4)
:yes
Answer to Question Asked in Comments
You asked in comments:
I am sorry I should have been clearer in my question. What would be the difference between a symbol and keyword in this case?
Consider your original definition (with the correction to make the error return the way you wanted):
(defmacro is [expr value]
`(if (= ~expr ~value)
'yes
(println "Expected " ~value "In" (str (quote ~expr))
"But Evaluated to" ~expr)))
I imagine that you want the 'yes
thinking that you could use to test against 'yes
in other contexts (one often sees these types of tests in introductory lisp texts). But 'yes
is used in your macro definition, it returns a qualified symbol when the test is passes:
user=> (is (+ 2 2) 4)
user/yes
Now, this is not what you would want. Imagine that you said this:
user=> (= 'yes (is (+ 2 2) 4))
false
To get a true
answer, you would have to say this (using a syntax quote):
user=> (= `yes (is (+ 2 2) 4))
true
If you defined your macro to return :yes
, then you get the checkable return without having to syntax quote the object you are using to do the checking:
user=> (= :yes (is (+ 2 2) 4))
true
But this is all superfluous because you are really interested in whether (+ 2 2)
returns 4
, i.e. whether your assertion is true
or false
rather than whether 'yes
equals `yes
or 'yes
; you can just have it return true
and avoid this checking step (in the real world).
In any case, to understand what qualified symbols are, you need to read the docs on the clojure reader and this SO answer explaining the ins and outs of symbols in clojure.