[plt-scheme] Newbie question: using a macro to create a top-level variable?

From: Eli Barzilay (eli at barzilay.org)
Date: Sat Aug 22 05:32:29 EDT 2009

On Aug 21, Gregg Williams wrote:
> (define ideas (infoml:make-rack-manual 'ideas))
> I need the variable named "ideas" so I can manipulate the rack from
> the command line. I need the symbol 'ideas (which goes into the rack
> data structure) so that I can, for example, print a list of all
> existing racks.
> The thing is, I would like to be able to write the simpler
> "(infoml:make-rack-manual 'ideas))" and let it create a top-level
> variable with the same name as the symbol given as an argument. I
> can't do that within a simple function definition, but I thought I
> could do it within a macro. Here's what I tried at first (which of
> course didn't work):
> (define-syntax-rule (infoml:make-rack rack-symbol)
>   (define rack-symbol (infoml:make-rack-manual rack-symbol)))
> When I did a macro expand in DrScheme, I could see why it didn't work--
> the expansion was:
> (define (quote rack-symbol) (infoml:make-rack-manual rack-symbol))
> Obviously, it was important to get precisely the right thing after the
> keyword "define". I tried unquoting the symbol; I tried converting the
> symbol into a string--neither worked.

The thing is that you want to quote one place only.  An easy way to do
this is:

  (define-syntax-rule (infoml:make-rack rack-id)
    (define rack-id (infoml:make-rack-manual 'rack-id)))
  (infoml:make-rack ideas) ; no quote

You can do this with the quote:

  (define-syntax-rule (infoml:make-rack 'rack-id)
    (define rack-id (infoml:make-rack-manual 'rack-id)))
  (infoml:make-rack 'ideas)

This looks like it's working, but what's really happening is that the
scheme reader sees:

  (define-syntax-rule (infoml:make-rack (quote rack-id))
    (define rack-id (infoml:make-rack-manual (quote rack-id))))

and `quote' is just a pattern variable that matches anything.  So if
you enter

  (infoml:make-rack (add1 ideas))

it actually expands to

  (define ideas (infoml:make-rack-manual (add1 ideas)))

To make this way work, you can use the more explicit `syntax-rules',
and specify `quote' as a keyword:

  (define-syntax infoml:make-rack
    (syntax-rules (quote)
      [(_ (quote rack-id))
       (define rack-id (infoml:make-rack-manual (quote rack-id)))]))

and doing this should make it clear that this is all redundant since
the `quote' requirement is just an arbitrary piece of syntax that
isn't really doing anything.

          ((lambda (x) (x x)) (lambda (x) (x x)))          Eli Barzilay:
                    http://barzilay.org/                   Maze is Life!

Posted on the users mailing list.