syntax-case-examples


The following are syntax-case versions of the example macros given in syntactic-closures.

The swap! macro can easily be done in syntax-rules, of course, entirely hygienically and without needing to quote or unquote syntax:

 (define-syntax swap! 
   (syntax-rules () 
     ((_ a b) 
      (let ((value a)) 
        (set! a b) 
        (set! b value))))) 

The syntax-case version is slightly more verbose, needing a lambda and quoting of syntax, but the guts are identical. Due purely to high-level sugar, it remains more straightforward than the syntactic closure version, since the macro arguments are bound to names automatically, and no unquoting of syntactic elements is required:

  
 (define-syntax swap! 
   (lambda (stx) 
     (syntax-case stx () 
       ((_ a b) 
        (syntax 
         (let ((value a)) 
           (set! a b) 
           (set! b value))))))) 

For the loop macro, we need to break hygiene, so we use datum->syntax-object to define a syntax object representing the exit identifier. By specifying (syntax loop) as an argument, we ensure that the exit identifier is inserted into the same syntactic environment as the use of the loop keyword, i.e. the syntactic environment of the caller of the macro. We then use with-syntax to inject the exit identifier into the returned syntax object.

[Edit: To emulate the original macro which uses loop as a variable within its definition, we define loop here as a temporary variable. Simply using some other name for the named let would eliminate this issue and provide automatic hygiene. The only reason special action is needed currently is to provide the desired outcome for the two distinct uses of the same name within the macro definition.]

Once again, the macro body doesn't require any unquoting.

 (define-syntax loop 
   (lambda (stx) 
     (syntax-case stx () 
      ((loop expr) 
       (with-syntax ((exit (datum->syntax-object (syntax loop) 'exit)) 
                     (loop (car (generate-temporaries (syntax (loop)))))) 
         (syntax 
          (call/cc 
           (lambda (exit) 
             (let loop () 
               expr 
               (loop)))))))))) 

We do the same thing with the it identifier for the aif macro. To control the precise scope of it within the macro, we use ordinary lexical scope via let, just as you would in an ordinary Scheme procedure.

 (define-syntax aif 
   (lambda (stx) 
     (syntax-case stx () 
       ((aif condition consequent alternative) 
        (with-syntax ((it (datum->syntax-object (syntax aif) 'it))) 
          (syntax 
           (let ((val condition)) 
             (if val 
                 (let ((it val)) consequent) 
                 alternative)))))))) 

category-syntax category-macro