You are looking at historical revision 24454 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 expressions.
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 expression of the first matching pattern is evaluated to generate the macro-expansion.
But except the renamed symbols in names another one must be available for the macro-writer, compare?, to be able to cope with literal symbols like else and => in the cond macro. The trick is to make er-macro-rules and the other er-macro-... macros unhygienic, polluting their local namespace with the symbol compare?.
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 (er-macro-rules (%if %my-or) ((_) #f) ((_ arg . args) `(,%if ,arg ,arg (,%my-or ,@args)))))
Unhygienic macros can not be implemented with syntax-rules, so we must use er-macro-transformer.
All macros in this module except with-aliases are unhygienic and provide the symbol compare? in the background.
er-macro-rules[syntax] (er-macro-rules (%sym ...) (pat0 xpr0) (pat1 xpr1) ...)
Checks the macro's use against a series of patterns, pat0, pat1 ... and evaluates the corresponding expression xpr0 xpr1 ..., resulting in the macro-expansion.
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 list of the form
(with (%sym ...) xpr . xprs)
where %sym ... are the renamed symbols and the sequence xpr . xprs produces the macro-expansion.
(er-macro-define (my-or . args) (with (%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 (with (%sym ...) xpr . xprs))
where code is the complete macro-code (name . args), i.e. the pattern of a macro call, %sym ... are aliases of sym ... and the sequence of expressions xpr . xprs produces the macro-expansion.
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) (with () n)) ((g n) (with (%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) (with () n)) ((g n) (with (%f) `(,%f ,n))) ) (display (list (f 1) (g 1))) (newline)))
returns (1 1).[syntax] (er-macro-let ((code0 (with (%sym0 ...) . body0)) ...) . body)
where code0, %sym0 and body0 are as in macro-define. This is a local version of er-macro-define, allowing a list of (code with-xpr) lists to be processed in body in parallel.
er-macro-letrec[syntax] (er-macro-letrec ((code0 (with (%sym0 ...) . body0)) ...) . body)
where code0, %sym0 and body0 are as in macro-define. This is a local version of er-macro-define, allowing a list of (code with-xpr) lists to be processed 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. In that case, op is the rename operator.
(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.
- except with-aliases all macros are unhygienic
- changed syntax of er-macro-rules and resulting corrections
- added with-aliases, renamed explicit-renaming er-macro-rules, added er-prefix to other symbols
- initial import