определение макросов, генерируемых макросами, которые принимают переменное число аргументов - PullRequest
0 голосов
/ 20 декабря 2018

Я пытаюсь написать макрос, генерирующий макрос, где макрос, который он генерирует, принимает переменное число аргументов.

Мне интересно, есть ли способ заставить работать следующий код:

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

Прямо сейчас он говорит "нет pattern variables до ellipsis в template в: ..."

Если я возьму внутреннее define-syntax-rule само по себе, оно работает нормально, поэтомупочему он не работает, когда генерируется другим макросом?

Ответы [ 2 ]

0 голосов
/ 20 декабря 2018

Для этого есть как минимум 3 "Стиля".

1: каждый многоточие в кавычках

Soegaard уже ответил , что вы можете заменить каждый ... в теле с (... ...), так что его интерпретируют как буквальный многоточие, принадлежащее внутреннему макросу, а не как «мета», принадлежащий внешнему макросу:

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

Преимущества: гибкийВы можете свободно смешивать буквальные (... ...) и мета ... эллипсы внутри тела

Недостатки: выглядит странно, если вы не видели (... ...) до

2: цитирование на эллипсисеопределение всего внутреннего макроса

Однако, размещение (... <something>) вокруг чего-либо не ограничивается только ....Если вы поместите туда целый шаблон, любые ... s в этом шаблоне также будут "заключены в кавычки", обработаны как литералы вместо мета, таким же образом:

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

Преимущества: Если у вас есть дажебольшая глубина вложения вам не понадобится ((... ...) (... ...)), как в случае с вариантом 1, вам просто потребуется (... <something-containing (... <something>)>)

Недостатки: жесткие, если вы положите (... <something>) вокруг чего-то, что вы никогда не сможете использоватьмета-эллипсис внутри этого чего-то.Вы не можете свободно смешивать литералы и мета-эллипсы, как в стиле 1 или 3.

3: Создание переменной-шаблона для представления буквального эллипса

Вот еще один способ, который я нахожуменее запутанно, но требует использования define-simple-macro вместо define-syntax-rule, так что вы можете связать новые переменные шаблона, используя #:with.

(require syntax/parse/define)

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

Вы можете использовать с #:with, чтобы связать ooo переменная шаблона к буквальному эллипсу: #: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))))

Преимущества: Гибкость, вы можете свободно смешивать буквальные ooo и мета ... эллипсы внутри тела.Для меня это выглядит менее запутанно, чем (... ...) или ((... ...) (... ...)).

Недостатки: для более глубокого вложения вам может понадобиться несколько #:with -определений, по одному на каждом мета-уровне.

0 голосов
/ 20 декабря 2018

... принадлежит внешнему define-syntax-rule.Чтобы получить многоточие в выводе, вы должны заключить его в кавычки (... ...).

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

Для развлечения: если вам когда-нибудь понадобится написать макрос, который производит макрос, который производит макрос, вы будетенужно ((... ...) (... ...)) для производства многоточия.

...