diff --git a/collects/scribblings/guide/pattern-macros.scrbl b/collects/scribblings/guide/pattern-macros.scrbl index 10be33a49f..9c4e8a09f6 100644 --- a/collects/scribblings/guide/pattern-macros.scrbl +++ b/collects/scribblings/guide/pattern-macros.scrbl @@ -251,7 +251,8 @@ error is reported: @interaction[#:eval swap-eval (+ swap 3)] -An @deftech{identifier macro} works in any expression. For example, we +An @deftech{identifier macro} is a pattern-matching macro that +works in any expression. For example, we can define @racket[clock] as an identifier macro that expands to @racket[(get-clock)], so @racket[(+ clock 3)] would expand to @racket[(+ (get-clock) 3)]. An identifier macro also cooperates with diff --git a/collects/scribblings/guide/proc-macros.scrbl b/collects/scribblings/guide/proc-macros.scrbl index c3290c0abf..f267489897 100644 --- a/collects/scribblings/guide/proc-macros.scrbl +++ b/collects/scribblings/guide/proc-macros.scrbl @@ -18,22 +18,6 @@ The compile-time value associated with a transformer binding can be anything; if it is a procedure of one argument, then the binding is used as a macro, and the procedure is the @deftech{macro transformer}. -The @racket[syntax-rules] and @racket[syntax-id-rules] forms are -macros that expand to procedure forms. For example, if you evaluate a -@racket[syntax-rules] form directly (instead of placing on the -right-hand of a @racket[define-syntax] form), the result is a -procedure: - -@interaction[ -(syntax-rules () [(nothing) something]) -] - -Instead of using @racket[syntax-rules], you can write your own macro -transformer procedure directly using @racket[lambda]. The argument to -the procedure is a value that represents the source form, and the -result of the procedure must be a value that represents the -replacement form. - @local-table-of-contents[] @; ---------------------------------------- @@ -136,6 +120,66 @@ with @racket[syntax-e] eventually produces the syntax objects that were given to @racket[datum->syntax]. +@; ---------------------------------------- + +@section[#:tag "macro-transformers"]{Macro Transformer Procedures} + +Any procedure of one argument can be a @tech{macro transformer}. As +it turns out, the @racket[syntax-rules] form is a macro that expands +to a procedure form. For example, if you evaluate a +@racket[syntax-rules] form directly (instead of placing on the +right-hand of a @racket[define-syntax] form), the result is a +procedure: + +@interaction[ +(syntax-rules () [(nothing) something]) +] + +Instead of using @racket[syntax-rules], you can write your own macro +transformer procedure directly using @racket[lambda]. The argument to +the procedure is a @tech{syntax object} that represents the source form, and the +result of the procedure must be a @tech{syntax object} that represents the +replacement form: + +@interaction[ +#:eval check-eval +(define-syntax self-as-string + (lambda (stx) + (datum->syntax stx + (format "~s" (syntax->datum stx))))) + +(self-as-string (+ 1 2)) +] + +The source form passed to a macro transformer represents an +expression in which its identifier is used in an application position +(i.e., after a parenthesis that starts an expression), or it +represents the identifier by itself if it is used as an expression +position and not in an application position.@margin-note*{The procedure produced by +@racket[syntax-rules] raises a syntax error if its argument +corresponds to a use of the identifier by itself, which is why +@racket[syntax-rules] does not implement an @tech{identifier macro}.} + +@interaction[ +#:eval check-eval +(self-as-string (+ 1 2)) +self-as-string +] + +The @racket[define-syntax] form supports the same shortcut +syntax for functions as @racket[define], so that the following @racket[self-as-string] +definition is equivalent to the one that uses @racket[lambda] +explicitly: + +@interaction[ +#:eval check-eval +(define-syntax (self-as-string stx) + (datum->syntax stx + (format "~s" (syntax->datum stx)))) + +(self-as-string (+ 1 2)) +] + @; ---------------------------------------- @section[#:tag "syntax-case"]{Mixing Patterns and Expressions: @racket[syntax-case]} @@ -175,12 +219,11 @@ We could write the @racket[swap] macro using @racket[syntax-case] instead of @racket[define-syntax-rule] or @racket[syntax-rules]: @racketblock[ -(define-syntax swap - (lambda (stx) - (syntax-case stx () - [(swap x y) #'(let ([tmp x]) - (set! x y) - (set! y tmp))]))) +(define-syntax (swap stx) + (syntax-case stx () + [(swap x y) #'(let ([tmp x]) + (set! x y) + (set! y tmp))])) ] One advantage of using @racket[syntax-case] is that we can provide @@ -192,21 +235,20 @@ because @racket[2] is not an identifier. We can refine our check the sub-forms: @racketblock[ -(define-syntax swap - (lambda (stx) - (syntax-case stx () - [(swap x y) - (if (and (identifier? #'x) - (identifier? #'y)) - #'(let ([tmp x]) - (set! x y) - (set! y tmp)) - (raise-syntax-error #f - "not an identifier" - stx - (if (identifier? #'x) - #'y - #'x)))]))) +(define-syntax (swap stx) + (syntax-case stx () + [(swap x y) + (if (and (identifier? #'x) + (identifier? #'y)) + #'(let ([tmp x]) + (set! x y) + (set! y tmp)) + (raise-syntax-error #f + "not an identifier" + stx + (if (identifier? #'x) + #'y + #'x)))])) ] With this definition, @racket[(swap x 2)] provides a syntax error @@ -241,9 +283,6 @@ set of names based on a sequence @racket[id ...]: body) ....])) ] -@margin-note{This example uses @racket[(define-syntax (_id _arg) _body ...+)], - which is equivalent to @racket[(define-syntax _id (lambda (_arg) _body ...+))].} - In place of the @racket[....]s above, we need to bind @racket[get ...] and @racket[put ...] to lists of generated identifiers. We cannot use @racket[let] to bind @racket[get] and @racket[put],