Макрос ракетки, который определяет несколько форм верхнего уровня?

Я определил параметры синтаксиса с идентичными определениями, за исключением их имени, поэтому решил написать макрос, чтобы сделать это проще:

(define-syntax (test-case-parameter stx)
  (syntax-parse stx
    [(_ parameter:id)
     #'(define-syntax-parameter parameter
         (lambda (stx)
           (raise-syntax-error stx "Can only be used inside test-case.")))]))

(test-case-parameter a)
(test-case-parameter b)
(test-case-parameter c)

Однако вместо того, чтобы повторять имя макроса, я хотел бы просто написать:

(test-case-parameter a b c)

Но я не вижу, как это сделать, используя обычный синтаксис эллипсов, потому что мне нужно было бы обернуть все в begin что создаст новую область видимости, и я хочу, чтобы все параметры синтаксиса были такими, как если бы я написал их для каждого верхнего уровня. Как правильно это сделать?

2 ответа

Решение

Ответ заключается в использовании begin, begin странно, потому что поведение на верхнем уровне отличается от поведения в контексте выражения. На верхнем уровне у него есть тот тип поведения сплайсинга, который вы хотели бы использовать для этого макроса, но в контексте выражения он имеет поведение области видимости, на которое вы ссылаетесь.

Таким образом, вы можете определить свой макрос следующим образом:

#lang racket
(require racket/stxparam (for-syntax syntax/parse))

(define-syntax (define-test-case-parameters stx)
  (syntax-parse stx
    [(_ parameter:id ...)
     #'(begin
         (define-syntax-parameter parameter
           (lambda (stx)
             (raise-syntax-error stx "Can only be used inside test-case.")))
         ...)]))

(define-test-case-parameters a b c)

Вы можете увидеть, как begin работы по сращиванию на высшем уровне в Macro Stepper в DrRacket:

сплайсинг-начать-макро-степпер

Создайте новый макрос, который принимает несколько идентификаторов, и пусть он расширяется до последовательности использования вашей версии, которая использует один идентификатор.

#lang racket
(require (for-syntax syntax/parse)
         racket/stxparam)

(define-syntax (test-case-parameter-helper stx)
  (syntax-parse stx
    [(_test-case-parameter-helper parameter:id)
     (syntax/loc stx
       (define-syntax-parameter parameter
         (lambda (stx)
           (raise-syntax-error stx "Can only be used inside test-case."))))]))

(define-syntax (test-case-parameter stx)
  (syntax-parse stx
    [(_test-case-parameter parameter:id ...)
     (syntax/loc stx
       (begin
         (test-case-parameter-helper parameter)
         ...))]))

(test-case-parameter a b c)
Другие вопросы по тегам