STKLOS supports hygienic macros such as the ones defined in R5RS
as well as low level macros.
Low level macros are defined with define-macro
whereas R5RS
macros
are defined with define-syntax
1. Hygienic macros use the
implementation of "Macro by Example" (Eugene Kohlbecker, R4RS
) by Dorai
Sitaram. This implementation generates low level STKLOS macros. This
implementation of hygienic macros is not expensive.
Its major drawback is that these macros are not referentially
transparent (see section `Macros' in R4RS
). Lexically scoped macros
(i.e., let-syntax
and letrec-syntax
) are not supported. In any case,
the problem of referential transparency gains poignancy only when
let-syntax
and letrec-syntax
are used. So you will not be courting
large-scale disaster unless you're using system-function names as local
variables with unintuitive bindings that the macro can't use. However,
if you must have the full R5RS
macro functionality, you can load do
(require "full-syntax")to have access to the more featureful (but also more expensive) versions of
syntax-rules
. Requiring full-syntax
load the version 2.1
of an implementation of hygienic macros by Robert Hieb and R. Kent Dybvig.
TODO: DEFINE THE LOW LEVEL EXPANDER MECHANISM
define-macro [<name> <formals] <body> | STKLOS Syntax |
define-macro <name> [lambda <formals> <body>] | STKLOS Syntax |
define-macro can be used to define low-level macro (i.e. non
hygienic macros. This for is similar to the defmacro of Common Lisp.
(define-macro (incr x) `(set! ,x (+ ,x 1))) (let ((a 1)) (incr a) a) => 2 (define-macro (when test . body) `(if ,test ,@(if (null? (cdr body)) body `((begin ,@body))))) (macro-expand '(when a b)) => (if a b) (macro-expand '(when a b c d)) => (if a (begin b c d)) (define-macro (my-and . exprs) (cond ((null? exprs) #t) ((= (length exprs) 1) (car exprs)) (else `(if ,(car exprs) (my-and ,@(cdr exprs)) #f)))) (macro-expand '(my-and a b c)) => (if a (my-and b c) #f) |
define-syntax <identifier> <transformer-spec> | R5RS |
<Define-syntax> extends the top-level syntactic environment by binding
the <identifier> to the specified transformer.
Note: (define-syntax let* (syntax-rules () ((let* () body1 body2 ...) (let () body1 body2 ...)) ((let* ((name1 val1) (name2 val2) ...) body1 body2 ...) (let ((name1 val1)) (let* (( name2 val2) ...) body1 body2 ...)))) |
syntax-rules <literals> <syntax-rule> ... | R5RS |
<literals> is a list of identifiers, and each <syntax-rule> should be of
the form
(pattern template) An instance of Each pattern begins with the name for the macro. This name is not involved in the matching and is not considered a pattern variable or literal identifier. Note: For a complete description of the Scheme pattern language, refer to R5RS . |
let-syntax <bindings> <body> | R5RS |
<Bindings> should have the form
((<keyword> <transformer spec>) ...) Each The Note: (let-syntax ((when (syntax-rules () ((when test stmt1 stmt2 ...) (if test (begin stmt1 stmt2 ...)))))) (let ((if #t)) (when if (set! if 'now)) if)) => now (let ((x 'outer)) (let-syntax ((m (syntax-rules () ((m) x)))) (let ((x 'inner)) (m)))) => outer |
letrec-syntax <bindings> <body> | R5RS |
Syntax of letrec-syntax is the same as for let-syntax .
The (letrec-syntax ((my-or (syntax-rules () ((my-or) #f) ((my-or e) e) ((my-or e1 e2 ...) (let ((temp e1)) (if temp temp (my-or e2 ...))))))) (let ((x #f) (y 7) (temp 8) (let odd?) (if even?)) (my-or x (let temp) (if y) y))) => 7 |
macro-expand form | STKLOS Procedure |
Returns the macro expansion of form if it is a macro call,
otherwise form is returned unchanged.
(define-macro (incr x) `(set! ,x (+ ,x 1))) (macro-expand '(incr foo)) => (set! foo (+ foo 1)) (macro-expand '(car bar)) => (car bar) |