[racket] variables within macros

From: Danny Yoo (dyoo at hashcollision.org)
Date: Wed Jan 16 10:33:18 EST 2013

On Wed, Jan 16, 2013 at 7:24 AM, Tim Brown <tim.brown at cityc.co.uk> wrote:
> Folks,
>
> I would like to write a module that uses a macro to transform "define"s
> and accumulate a value based on those transformations.
>
> In a fairly simple way, I want to do something like the below. However, it
> seems the module-begin is being transformed before the my-defines. How do
> I get counter to be incremented before I need it?

The transformation happens top-down, so you'll see that the body of
your program expands in the following steps (to a first
approximation):


(#%your-module-begin (your-define woo 2))

==>

(#%racket-module-begin (your-define woo 2)
                                    (define defines-counter 0)
                                    (provide defines-counter))

==>

(#%racket-module-begin (racket-define woo 2)
                                    (define defines-counter 0)
                                    (provide defines-counter))


One possible workaround is the the following: add one level of
indirection in installing the value of the defines-counter.  You can
do something like:

    (define-syntax (get-counter stx)
       (datum->syntax stx counter))

and use (get-counter) in place of #,counter in your module-begin.
This way, we delays the lookup of counter until the macro expander
finally reaches that expression, and by that time, it should have hit
all the defines already.


If you need to control the order of expansion more explicitly, you may
need to look into local-expand:

    http://docs.racket-lang.org/reference/stxtrans.html#(def._((quote._~23~25kernel)._local-expand))

----

Modified code below:

  #lang racket/base

  (provide (except-out (all-from-out racket) #%module-begin define)
           (rename-out (module-begin #%module-begin) (my-define define)))

  (require (for-syntax racket/base
                       syntax/parse))
  (define-for-syntax counter 0)

  (define-syntax (my-define stx)
    (syntax-parse
        stx
      [(_ i v) (set! counter (add1 counter)) #`(define i v)]
      [(_ (i args ...) v ...+) (set! counter (add1 counter))
                               #`(define (i args ...) v ...)]))

  (define-syntax (get-counter stx )
    (datum->syntax stx counter))

  (define-syntax (module-begin stx)
    (syntax-parse
        stx
      [(_ expr ...)
       #`(#%module-begin expr ...
                         (define defines-count (get-counter))
                         (provide defines-count))]))

Posted on the users mailing list.