#racket
#racket
Вопрос:
В настоящее время у меня есть куча объединяемых синтаксических классов, которые я использую для генерации кода.
Они выглядят следующим образом:
(define-splicing-syntax-class vec-exp
(pattern (~seq x y)
#:with result #'(vec x y)))
Цель состоит в том, чтобы иметь возможность сопоставлять последовательность x y
в любом месте и заменять ее на (vec x y)
.
Единственный способ, который я вижу на данный момент, — это создать атрибут с именем result
и использовать его:
> (syntax-parse #'(position 4.2 5.7)
[(<name> <pos>:vec-exp)
(attribute <pos>.result)])
#'(vec 4.2 5.7)
Есть ли способ изменить мой код, чтобы я мог получить тот же результат, написав следующее?
> (syntax-parse #'(position 4.2 5.7)
[(<name> <pos>:vec-exp)
(attribute <pos>)])
#'(4.2 5.7) ;; not what I want
Ответ №1:
Черт возьми, ты можешь это сделать. Не уверен, приемлемо ли это для вас или нет.
(require syntax/parse
(for-syntax syntax/parse))
(define-splicing-syntax-class vec-exp
(pattern (~seq x y) #:with result #'(vec x y)))
(define-syntax ~res
(pattern-expander
(syntax-parser
[(_ pat cls)
#'(~and (~var PAT cls) (~bind [pat (attribute PAT.result)]))])))
И затем:
> (syntax-parse #'(position 4.2 5.7)
[(<name> (~res <pos> vec-exp))
(attribute <pos>)])
#'(vec 4.2 5.7)
Ответ №2:
Я так не думаю. Шаблон (<name> <pos>:vec-exp)
означает «Входные данные должны быть списком; привяжите его элементы к переменным шаблона <name>
и <pos>
«. Эти переменные шаблона предоставляют доступ к тому, что было сопоставлено.Атрибуты, возвращаемые синтаксическим классом, являются тем, что было сгенерировано. syntax-parse
Система очень требовательна к разделению этих двух понятий, поэтому я не думаю, что она позволит вам заменить одно другим.
Вы пытаетесь сделать свой макрос более читаемым или менее подверженным ошибкам? Если да, может быть, расскажите нам немного больше. Возможно, есть способ сделать это.