Macros ====== User-defined syntactic forms are also called macros. Let's review macros in C/C++. They are essentially textual substitutions. #define SQUARE(x) x*x This has a problem: 4 * SQUARE(2 + 3) gets expanded to 4 * 2 + 3 * 2 + 3, completely messing up the intended meaning. To fix SQUARE: #define SQUARE(x) ((x)*(x)) Doesn't come up in Scheme, since all expressions are fully-parenthesized. One can go as far as (I saw this at one company I worked for): #define BEGIN { #define END } Standard macros in Scheme don't allow manipulation below the level of lists of tokens. But some extensions do. Consider now a macro to swap the values of two variables: #define SWAP(v1,v2) int t = v1; v1 = v2; v2 = t; This has a problem if t is one of the variables we want to swap: SWAP(t,v): int t = t; t = v; v = t; In Scheme: (define-syntax swap (syntax-rules () ((swap v1 v2) ; names in code matched to v1 and v2 refer to the caller's names (let ((t v1)) ; other names in result template (let, t, set!) refer to names where (set! v1 v2) ; macro is defined (set! v2 t))))) We get much of the usual effect of procedures, with the ability to pass code that doesn't lose its meaning: meaning of non-parameters comes from environment where swap is defined meaning of parameter code (if evaluated) comes from caller's environment These kinds of macros are called "hygienic". Here is an annotated expansion of (swap t v): (swap-let ((swap-t caller-t)) (swap-set! caller-t caller-v) (swap-set! caller-v swap-t)) If we haven't redefined let and set! where swap was made or called, we can just think of it as: (let ((swap-t caller-t)) (set! caller-t caller-v) (set! caller-v swap-t)) And if we think of it as being expanded where swap is called, it's equivalent to: (let ((swap-t t)) (set! t v) (set! v swap-t)) Applicative vs Normal order =========================== Code is a tree, and is evaluated by a mixture of top-down/outside-in (Normal order) and bottom-up/inside-out (Applicative order) processing. Call-by-value is bottom-up: the procedure executes only after the arguments have been evaluated. Syntactic-forms are top-down: they control the processing of their arguments. For example: (define-syntax s (syntax-rules () ((s (x y)) y))) (s (not #t)) transforms to code #t when run evaluates to #t (s (s (not #t))) transforms to code (not #t) when run evaluates to #f '(s (s (not #t))) shorthand for (quote (s (s (not #t)))) quote is a syntactic form, prevents evaluation of arguments when run evaluates to list (s (s (not #t)))