8.1. Keyword Bindings


8.1. Keyword Bindings

This section describes forms that establish bindings between keywords and transformers. Keyword bindings may be established at top level, using define-syntax, or locally, using let-syntax, letrec-syntax, or internal define-syntax. Existing keyword bindings may be rebound temporarily with fluid-let-syntax.

(define-syntax keyword exp)

syntax

returns: unspecified

exp must evaluate to a transformer.

The following example defines let* as a syntactic extension, specifying the transformer with syntax-rules (see Section 8.2).

 (define-syntax let*   (syntax-rules ()     (( () e1 e2 ...) (let () e1 e2 ...))     (( ((i1 v1) (i2 v2) ...) e1 e2 ...)      (let ((i1 v1))        (let* ((i2 v2) ...) e1 e2 ...))))) 

define-syntax forms appearing at top level behave similarly to top-level variable definitions, and define-syntax forms appearing at the front of a lambda or other body behave similarly to internal variable definitions. That is, a binding established by a top-level define-syntax form is visible globally, whereas one established by an internal define-syntax form is visible only within the body in which the define-syntax form appears.

All bindings established by a set of internal definitions, whether keyword or variable definitions, are visible within the definitions themselves. For example, the expression

 (let ()   (define even?     (lambda (x)       (or (= x 0) (odd? (- x 1)))))   (define-syntax odd?     (syntax-rules ()       (( x) (not (even? x))))) (even? 10)) 

is valid and should return #t. It must be possible for the expander to determine the set of syntax and variable definitions that appears at the front of a body without referring to any of the locally defined identifiers. It is not legal, therefore, for an internal definition to affect the status of a (potential) internal definition in the same sequence of forms. For example,

 (let ()   (define-syntax bind-to-zero     (syntax-rules ()       (( id) (define id 0)))) (bind-to-zero x) x) 

is not valid, since it would require the expander to expand (bind-to-zero x) in order to recognize it as a syntax definition. Rewritten as follows it returns 0.

 (let ()   (define-syntax bind-to-zero     (syntax-rules ()       (( id) (define id 0)))) (let ()   (bind-to-zero x) x)) 

A top-level syntactic definition must be established before its first use in order for that use to be recognized.

(let-syntax ((keyword exp) ...) form1 form2 ...)

syntax

(letrec-syntax ((keyword exp) ...) form1 form2 ...)

syntax

returns: see explanation

Each exp must evaluate to a transformer. For both let-syntax and letrec-syntax, each keyword is bound within the forms form1 form2 . For letrec-syntax the binding scope also includes each exp.

A let-syntax or letrec-syntax form may expand into one or more expressions anywhere expressions are permitted, in which case the resulting expressions are treated as if enclosed in a begin expression. This allows a let-syntax or letrec-syntax form to expand into a definition or sequence of definitions anywhere definitions are permitted, in which case the definitions are treated as if they appeared in place of the let-syntax or letrec-syntax form. (This differs from the Revised5 Report treatment of these forms; see page 183.)

The following example highlights how let-syntax and letrec-syntax differ.

 (let ((f (lambda (x) (+ x 1))))   (let-syntax ((f (syntax-rules ()                     (( x) x)))                (g (syntax-rules ()                     (( x) (f x)))))     (list (f 1) (g 1))))  (1 2) (let ((f (lambda (x) (+ x 1))))   (letrec-syntax ((f (syntax-rules ()                        (( x) x)))                   (g (syntax-rules ()                        (( x) (f x)))))     (list (f 1) (g 1))))  (1 1) 

The two expressions are identical except that the let-syntax form in the first expression is a letrec-syntax form in the second. In the first expression, the f occurring in g refers to the let-bound variable f, whereas in the second it refers to the keyword f whose binding is established by the letrec-syntax form.

(fluid-let-syntax ((keyword exp) ...) form1 form2 ...)

syntax

returns: see explanation

Each exp must evaluate to a transformer. fluid-let-syntax is similar to let-syntax, except that instead of introducing new bindings for the keywords keyword , fluid-let-syntax temporarily alters the existing bindings for the keywords during the expansion of its body. That is, during the expansion of form1 form2 , the visible lexical (or top-level) binding for each keyword is temporarily replaced by a new association between the keyword and the corresponding transformer. This affects any references to the keyword that resolve to the same lexical (or top-level) binding whether the references occur in the text of the body or are introduced during its expansion. In contrast, let-syntax captures only those references that occur within the text of its body.

The following example shows how fluid-let-syntax differs from let-syntax.

 (let ((f (lambda (x) (+ x 1))))   (let-syntax ((g (syntax-rules ()                     (( x) (f x)))))     (let-syntax ((f (syntax-rules ()                       (( x) x))))       (g 1))))  2 (let ((f (lambda (x) (+ x 1))))   (let-syntax ((g (syntax-rules ()                     (( x) (f x)))))     (fluid-let-syntax ((f (syntax-rules ()                             (( x) x))))       (g 1))))  1 

The two expressions are identical except that the inner let-syntax form in the first expression is a fluid-let-syntax form in the second. In the first expression, the f occurring in the expansion of (g 1) refers to the let-bound variable f, whereas in the second it refers to the keyword f by virtue of the uid syntax binding for f.




The Scheme Programming Language
The Scheme Programming Language
ISBN: 026251298X
EAN: 2147483647
Year: 2003
Pages: 98

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net