Imagine you wrote if
as a function/procedure rather than a user defined macro/syntax:
;; makes if in terms of cond (define (my-if predicate consequent alternative) (cond (predicate consequent) (else alternative))) ;; example that works (define (atom? x) (my-if (not (pair? x)) #t #f)) ;; example that won't work ;; peano arithemtic (define (add a b) (my-if (zero? a) b (add (- a 1) (+ b 1))))
The problem with my-if
is that as a procedure every argument gets evaluated before the procedure body gets executed. thus in atom?
the parts (not (pair? x))
, #t
and #f
were evaluated before the body of my-if
gets executed.
For the last example means (add (- a 1) (+ b 1))
gets evaluated regardless of what a is, even when a
is zero, so the procedure will never end.
You can make your own if with syntax:
(define-syntax my-if (syntax-rules () ((my-if predicate consequent alternative) (cond (predicate consequent) (else alternative)))))
Now, how you read this is the first part is a template where the predicate consequent and alternative represent unevaluated expressions. It’s replaced with the other just reusing the expressions so that:
(my-if (check-something) (display 10) (display 20))
would be replaced with this:
(cond ((check-something) (display 10)) (else (display 20)))
With the procedure version of my-if
both 10 and 20 would have been printed. This is how and
and or
is implemented as well.