[racket] Macro defining functions question

From: Marco Maggi (marco.maggi-ipsu at poste.it)
Date: Thu May 15 14:21:09 EDT 2014

Kevin Forchione wrote:
> This one leaves me scratching my head. Why doesn’t this work? When you
> run the  macro the functions aren’t  defined outside of the  extent of
> the begin.

> (define-syntax (foo stx)
>   (syntax-case stx ()
>     [(foo)
>      #'(begin
>          (define (bar x) x)
>          (define (baz x) x))]))

> After inning the macro (bar 3) produces an bar undefined error.

After the your definition of the syntax FOO, you can think of:

   (foo) ;this is the syntax use

as expanding to:

   (begin
     (define (G0 G2) G2)
     (define (G3 G4) G4)) ;this is the output form

that is: all the identifiers  in binding position and reference position
introduced in the  syntax-use's output-form have been  renamed to unique
gensyms; there  are no  bindings with  name BAR and  BAZ in  the lexical
context of the syntax use.

  Instead, if you do:

   (define-syntax (foo stx)
     (syntax-case stx ()
       [(foo)
        (datum->syntax #'foo
                       '(begin
                          (define (bar x) x)
                          (define (baz x) x)))]))

   (foo)
   (bar 1)
   (baz 2)

everything works because DATUM->SYNTAX transforms all the symbols in the
symbolic expression into identifiers belonging to the lexical context of
the syntax use.  Such definition is equivalent to:

   (define-syntax (foo stx)
     (syntax-case stx ()
       [(foo ?stuff)
        #'?stuff]))

   (foo (begin
          (define (bar x) x)
          (define (baz x) x)))
   (bar 1)
   (baz 2)

  Usually, to  introduce unhygienic bindings  in the lexical  context of
the syntax use, one does:

   (define-syntax (foo stx)
     (syntax-case stx ()
       [(foo)
        (with-syntax
            ((BAR (datum->syntax #'foo 'bar))
             (BAZ (datum->syntax #'foo 'baz)))
          #'(begin
              (define (BAR x) x)
              (define (BAZ x) x)))]))

   (foo)
   (bar 1)
   (baz 2)

so that only BAR and BAZ are  marked as belonging to the lexical context
of the syntax use.  Such definition is equivalent to:

   (define-syntax (foo stx)
     (syntax-case stx ()
       [(foo ?bar ?baz)
        #'(begin
            (define (?bar x) x)
            (define (?baz x) x))]))

   (foo bar baz)
   (bar 1)
   (baz 2)

which is the "correct" way of doing things because: first it creates the
identifiers BAR and BAZ in the lexical context of the syntax use; second
it  composes the  output form  with such  identifiers, without  breaking
hygiene.

HTH
-- 
Marco Maggi


Posted on the users mailing list.