Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

defining macro-generated macros that take in variable number of arguments

Tags:

racket

I am trying to write a macro-generating macro, where the macro it generates takes a variable number of arguments.

I am wondering if there is a way to make the following code work:

(define-syntax-rule (greet name)
  (define-syntax-rule (name args ...)
    (printf "hello ~a~n" (list args ...))))

Right now it says "no pattern variables before ellipsis in template in: ..."

If I take the inner define-syntax-rule by itself it works fine, so why doesn't it work when it's being generated by another macro?

like image 891
JRR Avatar asked Dec 20 '18 06:12

JRR


People also ask

What are the macros that are designed to support variable length arguments?

To support variable length arguments in macro, we must include ellipses (…) in macro definition. There is also “__VA_ARGS__” preprocessing identifier which takes care of variable length argument substitutions which are provided to macro.

How many arguments we pass in macro definition?

macro (array[x = y, x + 1]) passes two arguments to macro : array[x = y and x + 1] .

How many arguments can a macro Canhave?

For portability, you should not have more than 31 parameters for a macro. The parameter list may end with an ellipsis (…).

What is macro explain macro with arguments?

Macro Arguments (DEFINE-! ENDDEFINE command) The macro definition can include macro arguments, which can be assigned specific values in the macro call. There are two types of arguments: keyword and positional. Keyword arguments are assigned names in the macro definition; in the macro call, they are identified by name.


1 Answers

There are at least 3 "Styles" of doing this.

1: Ellipsis-quoting each ellipsis separately

Soegaard already answered that you can replace every ... in the body with (... ...), so that it gets interpreted as a literal ellipsis belonging to the inner macro instead of as a "meta" ellipsis belonging to the outer macro:

(define-syntax-rule (greet name)
  (define-syntax-rule (name args (... ...))
    (printf "hello ~a~n" (list args (... ...)))))

Advantages: Flexible, you can mix literal (... ...) and meta ... ellipses freely within the body

Disadvantages: Looks confusing if you haven't seen (... ...) before

2: Ellipsis-quoting the whole inner macro definition

However, putting (... <something>) around something is not limited to just .... If you put a whole template there, any ...s within that template will also be "quoted", treated as literal instead of meta, in the same way:

(define-syntax-rule (greet name)
  (...
   (define-syntax-rule (name args ...)
     (printf "hello ~a~n" (list args ...)))))

Advantages: If you have even greater nesting depths you wouldn't need ((... ...) (... ...)) as you would with option 1, you would just need (... <something-containing (... <something>)>)

Disadvantages: Rigid, if you put (... <something>) around something you can't ever use a meta ellipsis inside that something. You can't mix literal and meta ellipses freely like you could with style 1 or 3.

3: Creating a pattern-variable to represent a literal ellipsis

Here's another way, which I find less confusing, but it requires using define-simple-macro instead of define-syntax-rule, so that you can bind new pattern variables using #:with.

(require syntax/parse/define)

(define-simple-macro (<name> <arguments>)
  #:with <pattern-variable> <expression>
  <body-expression>)

You can use with #:with to bind an ooo pattern variable to a literal ellipsis: #:with ooo (quote-syntax ...)

(require syntax/parse/define)

(define-simple-macro (greet name)
  #:with ooo (quote-syntax ...)
  (define-syntax-rule (name args ooo)
    (printf "hello ~a~n" (list args ooo))))

Advantages: Flexible, you can mix literal ooo and meta ... ellipses freely within the body. To me, it looks less confusing than (... ...) or ((... ...) (... ...)).

Disadvantages: For deeper nesting, you might need multiple #:with-definitions, one on each meta-level.

like image 166
Alex Knauth Avatar answered Sep 28 '22 16:09

Alex Knauth