You are looking at historical revision 24331 of this page. It may differ significantly from its current revision.
As an application of the match macro we'll define a macro, explicit-renaming, that will simplify the implementation of low-level macros considerably. Note, that the transformer of such a macro is a routine of three parameters, usually called form, rename, compare?, and that within that routine form has to be destructured by hand, and the symbols have to be renamed by hand as well. In our enhancement, we want both to be done automatically. Moreover, we want our macro to be of the same syntax as syntax-rules, i.e. it should look like this
(explicit-renaming names (pat xpr) (pat1 xpr1) ...)
where names should be a list of symbols, pat, pat1, ... represent admissible macro calls and xpr, xpr1 ... corresponding transformers. Moreover, explicit-renaming should expand into a (lambda (form rename compare?) ...) as does syntax-rules. Of course, names should contain a representation of those symbols, which are to be renamed. Our convention is, to prefix each symbol to be renamed with one character, % most of the time, so that in fact all renamings will be done in one large let at the beginning of the macro expansion. To be more precise, if names is (%sym ...), then we'll have a let of the form (let ((%sym (rename (sym-cdr '%sym))) ...) in the expansion, where sym-cdr is a local routine, which strips the prefix. The patterns will be destructured by match and the transformers are all functions of one argument, compare?, which isn't used in most cases (like the identifiers in syntax-rules).
As a non-trivial example consider the following low-level implementation of or. Note the similarity to the high-level one.
(define-syntax my-or ; ok (explicit-renaming (%if %my-or) ((_) (lambda (compare?) #f)) ((_ arg . args) (lambda (compare?) `(,%if ,arg ,arg (,%my-or ,@args))))))
A high-level implementation of explicit-renaming would work, but it would expose the local routine, sym-cdr, and delay the stripping of prefixes to run-time, although it can be done at compile-time. So we prefer a low-level implementation.
explicit-renaming[syntax] (explicit-renaming names (pat xpr) (pat1 xpr1) ...)
Checks the macro's use against a series of patterns, pat, pat1 ... and returns a syntax-transformer, i.e. a three argument lambda expression with body of the matching xpr, xpr1, ...
With explicit renaming under our belt, it's easy to implement three macros, macro-define, macro-let and macro-letrec, which facilitate the implementation of low-level macros even more: We simply match one pattern, the macro code, against a literal lambda-expression with arguments compare? %sym .... This time, my-or would look like this
(macro-define (my-or . args) (lambda (compare? %if %my-or) (if (null? args) #f (let ((tmp (car args))) `(,%if ,tmp ,tmp (,%my-or ,@(cdr args)))))))
macro-define[syntax] (macro-define code proc)
where code is the complete macro-code (name . args), i.e. the pattern of a macro call, and proc is a macro-transformer, now a literal lambda-expression with parameters compare? %sym .... Returns a low-level define-syntax expression of the form (define-syntax name (lambda (form rename compare?) ...)) by means of explicit-renaming.
macro-let and macro-letrec are local versions of macro-define, where the local macros are evaluated in parallel or recursively. For example
(let ((f (lambda (n) (+ n 10)))) (macro-let ( ((f n) (lambda (compare?) n)) ((g n) (lambda (compare? %f) `(,%f ,n))) ) (display (list (f 1) (g 1))) (newline)))
will result in (1 11) while
(let ((f (lambda (n) (+ n 10)))) (macro-letrec ( ((f n) (lambda (compare?) n)) ((g n) (lambda (compare? %f) `(,%f ,n))) ) (display (list (f 1) (g 1))) (newline)))
returns (1 1).[syntax] (macro-let ((code proc) ...) . body)
where code and proc are as in macro-define. This is a local version of macro-define, allowing a list of (code proc) lists to be processed in body in parallel.
macro-letrec[syntax] (macro-letrec ((code proc) ...) . body)
where code and proc are as in macro-define. Local version of macro-define, allowing a list of (code proc) lists to be processed in body recursively.
Copyright (c) 2011, Juergen Lorenz All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. Neither the name of the author nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- initial import