2
votes

This is the scenario: Given a pattern of the form [sym ...] (e.g. [a b] and [a b c d]) I want to generate (using macros) functions that concatenate the symbols in the pattern, but also supply them as arguments. For example, [a b] transforms to something of the form

(define (ab a b) 
  body)

In this post someone helps me generate the name of the function via a syntax class called signal-list. In the following code I can match the signals pattern variable with a pattern of the form (sig ...), and I can then use it to generate the desired function definition.

(define-syntax (define-something stx)
  (syntax-parse stx
    [(_ (signals:signal-list body ...))
     (syntax-parse #'signals
       [(sig ...)
        #'(define (signals.concatenated-ids sig ...)
               body ...)])]))

An example that matches this macro:

(define-something
  ([a b] 'body))

which expands to (define (ab a b) 'body)

But how do macros work if I want to generate multiple function definitions? For example:

(define-something
  ([a b] 'body)
  ([c d e] 'body))
=>
(begin (define (ab a b) 'body)
       (define (cde c d e) 'body))

I can add an ellipsis in the pattern of the first syntax-parse:

(_ (signals:signal-list body ...) ...)

But then I cannot use the second syntax-parse to match against signals because it needs an ellipsis. Is there a different way to 'de-construct' signals so that I can use its contents as formal parameters to a function, which is compatible with using ellipses?

1
The answer you mentioned already defines multiple functions, so, I'm not sure what you're asking here? Note that that answer works because it uses the same number of ellipses in both the pattern and template. - Greg Hendershott
It does, and I understand why it does it, but with the additional requirement of supplying the combined ids as formal parameters I got quite confused. I should really do more research on syntax classes to properly understand what is going on. I am convinced the answer is quite trivial. The Racket docs on macros are not so friendly to people who don't crunch macros for breakfast. - Sam
It sounds like you're looking to define new pattern variables. syntax-parse is one (rather heavyweight) way to do it. As Chris suggested, with-syntax is an easier way to define local pattern variables. The idiomatic way to define local pattern variabes with syntax-parse is with the #:with pattern directive, eg #:with ((sig ...) ...) #'signals - stchang

1 Answers

2
votes

To directly answer your question, you can pass #'(signals ...) (in place of your existing #'signals) to the inner syntax-parse invocation.


As a proof of concept, I wrote a syntax-case version of your macro (since I don't know syntax-parse yet). You should be able to adapt the same technique to syntax-parse easily:

(define-syntax (define-something outerstx)
  (define (make-name paramstx)
    (datum->syntax outerstx
                   (string->symbol
                    (apply string-append
                           (map symbol->string (syntax->datum paramstx))))))

  (define (make-names innerstx)
    (syntax-case innerstx ()
      (()
       #'())
      (((param ...) rest ...)
       (with-syntax ((name (make-name #'(param ...)))
                     ((next ...) (make-names #'(rest ...))))
         #'(name next ...)))))

  (syntax-case outerstx ()
    ((_ ((param ...) body ...)
        ...)
     (with-syntax (((name ...) (make-names #'((param ...) ...))))
       #'(define-values (name ...)
           (values (lambda (param ...)
                     body ...)
                   ...))))))