;;;; Synactic extensions ;;; So far the only special forms that we used are LAMBDA, IF, DEFINE, QUOTE ;;; and SET! ;;; while these forms are powerful enough SCHEME includes several secondary ;;; special forms that are normally expressed with the help of the primitive ;;; ones ;;; while SCHEME does not specify a standard mechanism for syntactic expansions ;;; actual implementations provide macro mechanism to do the stuff ;;; Quasiquotation ;;; ;;; Macros ;;; macro is a function of one argument (macroexpander) ;;; associated with a keyword ;;; when SCHEME compiles an S-expression car of which is a macro keyword ;;; it replaces it with a value that is returned by the corresponding ;;; macroexpander applied to this S-expression (macro m-square (lambda (body) `(* ,(cadr body) ,(cadr body)))) ;;; so if we say (m-square 4) it will expand into (* 4 4) ;;; but if we say (m-square (sin 1.234)) ;;; it will expand into (* (sin 1.234) (sin 1.234)) ;;; and we are going to evaluate (sin 1.234) twice (macro better-m-square (lambda (body) (if (or (number? (cadr body)) (symbol? (cadr body))) `(* ,(cadr body) ,(cadr body)) `((lambda (temp) (* temp temp)) ,(cadr body))))) ;;; Derived special forms ;;; the simpliest special form we can implement is BEGIN (define (begin-expander body) `((lambda () . ,(cdr body))) (macro my-begin begin-expander) ;;; one of the most useful ones is COND (define (cond-expander body) (define temp (gensym)) (define (loop clauses) (if (pair? clauses) (if (pair? (car clauses)) (if (eq? 'else (caar clauses)) `(begin . ,(cdar clauses)) (if (null? (cdar clauses)) `((lambda (,temp) (if ,temp ,temp ,(loop (cdr clauses)))) ,(caar clauses)) `(if ,(caar clauses) (begin . ,(cdar clauses)) ,(loop (cdr clauses))))) (syntax-error "Wrong clause in COND" body)) #!false)) (loop (cdr body))) (macro my-cond cond-expander) ;;; let us implement a macro BEGIN0 that implements a special form that takes ;;; a sequence of forms, evaluates them and returns the value of the ;;; first one (define (begin0-expander body) (define temp (gensym)) (cond ((null? (cdr body)) (syntax-error "Expression has too few subexpressions" body)) ((null? (cddr body)) (cadr body)) (else `((lambda (,temp) ,@(cddr body) ,temp) ,(cadr body))))) (macro my-begin0 begin0-expander) (define (and-expander form) (cond ((null? (cdr form)) #!true) ((null? (cddr form)) (cadr form)) (else `(if ,(cadr form) ,(and-expander (cdr form)) #!false)))) (macro my-and and-expander) (define (or-expander form) (define temp (gensym)) (cond ((null? (cdr form)) #!false) ((null? (cddr form)) (cadr form)) (else `((lambda (,temp) (if ,temp ,temp ,(or-expander (cdr form)))) ,(cadr form))))) (macro my-or or-expander) (define (when-expander body) (if (> 3 (length body)) (syntax-error "Expression has too few subexpressions" body) `(if ,(cadr body) (begin . ,(cddr body))))) (macro my-when when-expander) (macro my-named-lambda (lambda (form) (cond ((< (length form) 3) (syntax-error "Too few subexpression in expression" form)) ((not (pair? (cadr form))) (syntax-error "Invalid identifier list" form)) (else `(my-rec ,(caadr form) (lambda ,(cdadr form) . ,(cddr form))))))) (macro my-rec (lambda (form) (cond ((< (length form) 3) (syntax-error "Too few subexpression in expression" form)) ((not (symbol? (cadr form))) (syntax-error "Invalid identifier list" (begin (print (cadr form)) form))) (else `(letrec (,(cdr form)) . ,(cddr form))))))