You are looking at historical revision 24384 of this page. It may differ significantly from its current revision.
As an application of the match macro we'll define a macro, er-macro-rules, 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
(er-macro-rules names (pat xpr) (pat1 xpr1) ...)
where names should be a list of symbols, pat, pat1, ... represent admissible macro calls and xpr, xpr1 ... corresponding transformers, functions of one argument compare?.
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 (er-macro-rules (%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.
er-macro-rules[syntax] (er-macro-rules names (pat xpr) (pat1 xpr1) ...)
Checks the macro's use against a series of patterns, pat, pat1 ... and executes the corresponding syntax-transformer xpr xpr1 ..., which is a function of one argument, compare?, whose duty is to check if a symbol in the macro code is an alias of another symbol.
explicit-renaming[syntax] (explicit-renaming names (pat xpr) (pat1 xpr1) ...)
an alias to er-macro-rules, deprecated.
With er-macro-rules under our belt, it's easy to implement three macros, er-macro-define, er-macro-let and er-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
(er-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)))))))
er-macro-define[syntax] (er-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?) ...)).
er-macro-let and er-macro-letrec are local versions of er-macro-define, where the local macros are evaluated in parallel or recursively. For example
(let ((f (lambda (n) (+ n 10)))) (er-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)))) (er-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] (er-macro-let ((code proc) ...) . body)
where code and proc are as in macro-define. This is a local version of er-macro-define, allowing a list of (code proc) lists to be processed in body in parallel.
er-macro-letrec[syntax] (er-macro-letrec ((code proc) ...) . body)
where code and proc are as in er-macro-define. Local version of er-macro-define, allowing a list of (code proc) lists to be processed in body recursively.
with-aliases[syntax] (with-aliases (op %sym ...) . body)
binds %sym ... to (op sym) ... and executes body in this scope. Mostly used within raw low-level macros, if destructuring is not a problem.
(import er-macros) (import-for-syntax (only matchable match) (only er-macros with-aliases er-macro-rules))
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.
- added with-aliases, renamed explicit-renaming er-macro-rules, added er-prefix to other symbols
- initial import