; Try to play with what macros might be... try a 3-way if: ; ; (numeric-if numerical-value neg zero pos) ; ; to evaluate exactly one of neg, zero, pos, depending on whether ; numerical-value is negative, zero, or positive; optionally check ; for number-ness of numerical-value? (write-string "################ numeric-if test\n") ; This tests how many times everything gets evaluated (define probe 0) (define neg-action (lambda () (set! probe (+ probe 1)) "negative!")) (define zero-action (lambda () (set! probe (+ probe 10)) "zero!")) (define pos-action (lambda () (set! probe (+ probe 100)) "positive!")) (define test-value (lambda () (set! probe (+ probe 1000)) 0)) (define numeric-if-tmp "foo") ; This version is careful to evaluate tval only once (define (numeric-if-1 tval ifn ifz ifp) `(let ((numeric-if-tmp ,tval)) (display numeric-if-tmp) (newline) (if (number? numeric-if-tmp) (if (negative? numeric-if-tmp) ,ifn (if (positive? numeric-if-tmp) ,ifp ,ifz)) (raise "error: non-numeric test value passed to numeric-if")))) ; This version might evaluate tval two or three times (define (numeric-if-2 tval ifn ifz ifp) `(if (number? ,tval) (if (negative? ,tval) ,ifn (if (positive? ,tval) ,ifp ,ifz)) (raise "error: non-numeric test value passed to numeric-if"))) (display numeric-if-tmp) (newline) (write-string "before: probe is " (number->string probe) #\newline) (define macro-expand (numeric-if-2 '(test-value) '(neg-action) '(zero-action) '(pos-action))) (display macro-expand) (newline) (eval macro-expand) (write-string "after: probe is " (number->string probe) #\newline) (display numeric-if-tmp) (newline) (write-string "################ assertion test\n") ; Also, an (assert foo) macro would be nice: evaluate foo, and if it ; comes out #f, print an error message which includes the unevaluated ; expression of foo and then raise an exception. ; ; (defmacro (assert some-cond) (define (assurt some-cond) `(when (not ,some-cond) (write-string "assertion failure (macro-like): ") (display ',some-cond) (newline))) (define (asserd some-cond) (when (not some-cond) (write-string "assertion failure (function): ") (display some-cond) (newline))) (define x "foo") (asserd (eqv? x "bar")) (display x) (newline) (set! macro-expand (assurt '(eqv? x "bar"))) (display macro-expand) (newline) (eval macro-expand) ; Eventually, we'll say ; (assert (eqv? x "bar")) ; and it'll run through, if x is actually "bar", or it'll raise an exception (write-string "################ th-th-that's all, folks!\n")