Правила синтаксиса схемы - смешивание различных вариантов синтаксиса в `...`
Допустим, у меня есть макрос (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 ответ
Вы можете сделать это с помощью вспомогательного макроса, который перебирает каждый "тип arg-or-arg+" и преобразует их в (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
list и передайте аргументы в 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 ...))))