С syntax-case
и его охранник поддержка:
(define-syntax translate
(lambda (stx)
(syntax-case stx()
[(_ v) (identifier? #'v)
#'(symbol->string 'v)]
[(_ v) (number? (syntax-e #'v))
#'(number->string v)])))
(. Я использовал квадратные скобки для облегчения сравнения с ответом Эли, однако, это не мой обычный стиль ;-))
Но если вы используете syntax-case
, то вы можете точно также сделать преобразование на уровне синтаксиса, а не производить код, который делает это во время выполнения:
(define-syntax translate
(lambda (stx)
(syntax-case stx()
[(_ v) (identifier? #'v)
(datum->syntax stx (symbol->string (syntax->datum #'v)))]
[(_ v) (number? (syntax-e #'v))
(datum->syntax stx (number->string (syntax->datum #'v)))])))
Главное здесь в том, что код макроса теперь обычная схема, например, вы могли бы абстрагировать общие части в качестве помощника:
(define-syntax translate
(lambda (stx)
(define (rewrap convert x)
(datum->syntax stx (convert (syntax->datum x))))
(syntax-case stx()
[(_ v) (identifier? #'v) (rewrap symbol->string #'v)]
[(_ v) (number? (syntax-e #'v)) (rewrap number->string #'v)])))
В том же ключе, если этот макрос так просто, то никакой реальной потребность в syntax-case
, кроме вытаскивания подвыражению:
(define-syntax translate
(lambda (stx)
(syntax-case stx()
[(_ v) (let ([d (syntax->datum #'v)])
(datum->syntax
stx
((cond [(number? d) number->string]
[(symbol? d) symbol->string])
d)))])))
Примечания, кстати, что нет никакой магии в syntax-case
- и в случае этой простой модели, вы могли бы просто вытащить значение себя:
(define-syntax translate
(lambda (stx)
(let ([d (cadr (syntax->datum #'v))])
(datum->syntax
stx
((cond [(number? d) number->string]
[(symbol? d) symbol->string])
d)))))
Существует несколько шаблонного материала, который syntax-case
делает, что эта последнюю версия проигрывает:
Если вы используете макрос неожиданным образом, как (translate)
то эта версия будет выдавать ошибку о cadr
вместо более понятного синтаксиса ошибка
Аналогично, если вы используете (translate 1 2)
, тогда эта версия просто молча игнорирует 2
вместо ошибки.
И если он используется с чем-то, что не является ни идентификатор, ни число (например, (translate (+ 1 2))
), то это будет зависеть от неопределенного значения, cond
возвращается, а не бросать ошибку синтаксиса.
Бьюсь об заклад, если вы предоставили более подробную информацию о том, на каком языке переводчик вы работаете, вы получите гораздо более полезную помощь. Что вы переводите с и на что и почему? –