Правила синтаксиса схемы - смешивание различных вариантов синтаксиса в `...`

Допустим, у меня есть макрос (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 ...))))
Другие вопросы по тегам