(define (verbose arg)
(display arg) ; display
(newline) ; display newline
arg)) ; evaluate to arg
(if-fun (verbose (> 3 4))
(verbose 'true)
(verbose 'false))
; ==> false
This prints
#f
true
false
The macro version:
(if-mac (verbose (> 3 4))
(verbose 'true)
(verbose 'false))
; ==> false
It prints
#f
false
You see the difference? With a procedure every argument is evaluated and bound to the variables, then the body is evaluated.
In the macro version the code gets transformed, then evaluated. Thus the consequent expression was never executed since the predicate was #f
.
If you try making a recursive function:
(define (factorial n)
(if-fun (<= n 2)
n
(* n (factorial (- n 1)))))
(factorial 2)
Even when it hits the base case, since all 3 arguments are evaluated it will do (factorial 1), then (factorial 0), (factorial -1) ..... to negative infinity. It will never ever return a value but, sice it's not tail recursive, it will run out of memory.
(define (factorial n)
(if-mac (<= n 2)
n
(* n (factorial (- n 1)))))
(factorial 2)
When the procedure is evaluated the macro can be expanded so it turns into:
(define (factorial n)
(if (<= n 2)
n
(* n (factorial (- n 1)))))
And it would be as if you didn't use your macro at all. If you had a macro that printed something when it got expanded it would print once for every use in a procedure, before you use it.
It's like this because Scheme and Racket has eager evaluation. Eg. #!lazy
racket, which is a lazy version of #!racket
, if
and other special forms are made as procedures since evaluation is by need. There are no need for macros in a lazy language.