[racket] beginner question about macros

From: Răzvan Rotaru (razvan.rotaru at gmail.com)
Date: Sun Dec 4 23:42:30 EST 2011

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



Posted on the users mailing list.