[racket] beginner question about macros

From: J. Ian Johnson (ianj at ccs.neu.edu)
Date: Mon Dec 5 09:39:37 EST 2011

Your textual manipulation of identifiers is unhygienic. You will need to do the following

(with-syntax ([newX (datum->syntax #'x (translate-symbol (syntax-e #'x)))])
  ...use-of-newX...)

This means "take the lexical context of x and mark this new symbol as being in the same context." This allows you to capture names in the calling scope without being given them explicitly.
As for your concern with syntax-case, that's perfectly fine. Hygiene is assured with both syntax-case and syntax-rules.

-Ian

----- Original Message -----
From: "Răzvan Rotaru" <razvan.rotaru at gmail.com>
To: "Carl Eastlund" <cce at ccs.neu.edu>
Cc: users at racket-lang.org
Sent: Sunday, December 4, 2011 11:42:30 PM GMT -05:00 US/Canada Eastern
Subject: Re: [racket] beginner question about macros

On 5 December 2011 04:06, Carl Eastlund <cce at ccs.neu.edu> wrote:
> Răzvan,
>
> Both of these are in some sense advanced macros.  If you're just
> learning how to write macros, I'd suggest slightly simpler forms.
>
> In the first case, write (my-macro (a 1) (b 2) (c 3)) instead.
> Grouping the names and numbers with parentheses means there's less
> work to do when parsing the macro.  Then you can write the whole thing
> with one clause.
>
> (define-syntax my-macro
>  (syntax-rules ()
>    [(_ (name number) ...)
>     (let ([x foo])
>       (name number x)
>       ...)]))
>

Ok, using parens is no problem for me. I tried using syntax rules,
inspired by the example from J. Ian Johnson, but ran into the fact
that generating the code for each pair (name number), which is
recursive requires access to the let-variable. So if I have a
my-macro-aux, which deals with (name number) pairs, then it needs to
get some info from the calling macro my-macro. Here's the code:

(define-syntax gen-pairs
  (syntax-rules ()
    [(_ k v) (printf "~a ~a ~a~n" <x-from-let-here> k v)]
     [(_ k v rest ...) (begin (printf "~a ~a ~a~n" <x-from-let-here> k
v) (gen-options rest ...))]
     [(_ rest ...) (raise-syntax-error #f "Expected even number of
inputs to gen-pairs")]))

(define my-macro
  (syntax-rules ()
    [(_ rest ...) (let ([x foo])
                        (gen-pairs rest ...)]))

I've also managed to come up with a syntax-case version, though at the
moment i'm not 100% sure it's correct. It's basically written by
thinking in lisp macro style, and using syntax-quote instead of quote
(there's an extra foo as first arg, but otherwise the macro is the
same):

(define-syntax (my-macro stx)
  (syntax-case stx ()
    [(_ foo rest ...) #`(let ([x foo])
                                #,@(let ([args (partition-by
(syntax->list #'(rest ...)) 2)])                ;;(partition-by '(1 2
3 4))   =>    '((1 2)(3 4))
                                     ;;TODO - check that args has at
least 2 elements
                                     (for/list ([x args])
                                       #`(printf "~a ~a ~a~n" x #,(car
args) #,(cadr args))))
                                )]))


Is it safe to approach macros like this? Thinking like lisp, but using
#' instead of '  ?

> In the second case, it's not clear what you're trying to accomplish.
> What are new-a, second-b, and another-c supposed to be?  The way you
> wrote it, they appear to just be made up, random names that aren't
> bound and will immediately lead to syntax errors.  I'm sure that's not
> what you meant.  Can you clarify whether these names are supposed to
> be bound inside the macro or somewhere else, and how the macro is
> supposed to come up with their names?
>
> Carl Eastlund


new-a, second-b and another-c already exist in the caller environment.
I'm trying to generate java calls (in kawa) from macros. Something
like:

(create-object MyObject X "1" Y "2")
=>
(MyObject)   ;instantiation
(*:setX "1")   ;set value for X
(*:setY "2")   ;set value for Y

And this should work with any X or Y. In other words I need a textual
transformation from X to setX to be done in the macro, which will of
course fail if setX does not exist (but that's ok).

Razvan

_________________________________________________
  For list-related administrative tasks:
  http://lists.racket-lang.org/listinfo/users



Posted on the users mailing list.