Правила синтаксиса схемы - смешивание различных вариантов синтаксиса в `...` - PullRequest
1 голос
/ 21 июня 2020

Допустим, у меня есть макрос (define/custom (name (arg type) ...) body ...), который, помимо прочего, расширяется до (define (name arg ...) body ...). Это просто.

Теперь я хочу разрешить передавать в качестве параметра не только (arg type), но просто arg. Хорошо, поэтому я пишу второе предложение, где (define/custom (name arg ...) body ...) заменяется на (define (name arg ...) body ...). Также просто.

Но при таком решении либо все аргументы имеют тип, либо ни один из них. Как я могу разрешить смешивание двух опций в одном и том же списке синтаксиса (или как там называется ...)? Как сделать так, чтобы например. (define/custom (name arg1 (arg2 type2)) #f) расширяется до (define (name arg1 arg2) #f)? Интуиция состоит в том, чтобы использовать вспомогательный макрос, который расширил бы (helper a) до a и (helper (a b)) до a и заставил бы (define/custom (name arg_or_arg+type ...) body ...) расшириться до (define (name (helper arg_or_arg+type) ...) body ...), но, как вы, вероятно, знали и догадывались, где это прибывает, это не работает, потому что расширение define происходит до расширения helper.

1 Ответ

2 голосов
/ 21 июня 2020

Вы можете сделать это с помощью вспомогательного макроса, который перебирает каждый "arg-or-arg + type" и преобразует их в (arg type) для согласованности.

Во-первых, я рекомендую определить базовую версию макрос, который работает только с последовательной (arg type) версией вещей:

(define-syntax define/custom-core
  (syntax-rules ()
    ((_ (name (arg type) ...) body ...)
     ; among other things
     (define (name arg ...) body ...))))

Затем вы можете определить вспомогательный макрос, который имеет дело с двумя списками входных аргументов: один для согласованных (arg type) вещей, а другой для вещи типа "arg-or-arg +". Пример использования может выглядеть так:

(define/custom-helper (name ((arg type) ...) (arg-or-arg+type ...)) body ...)

По мере прохождения через arg-or-arg+type ... они перемещаются в список (arg type) .... Когда arg-or-arg+type ... пусто, это делается и все элементы (arg type) помещаются в вызов define/custom-core.

(define-syntax define/custom-helper
  (syntax-rules ()
    ((_ (name (arg+type ...) ()) body ...)
     (define/custom-core (name arg+type ...) body ...))
    ((_ (name (arg+type ...) ((arg type) . rest)) body ...)
     (define/custom-helper (name (arg+type ... (arg type)) rest) body ...))
    ((_ (name (arg+type ...) (arg . rest)) body ...)
     (define/custom-helper (name (arg+type ... (arg any)) rest) body ...))))

Это зависит от того, что arg эквивалентно (arg any).

Затем все, что осталось - это обращенный наружу макрос define/custom для вызова вспомогательного макроса. Он может передавать пустой список arg+type и передавать аргументы в место arg-or-arg+type, чтобы помощник имел дело с ним.

(define-syntax define/custom
  (syntax-rules ()
    ((_ (name arg-or-arg+type ...) body ...)
     (define/custom-helper (name () (arg-or-arg+type ...)) body ...))))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...