使用syntax-case 及其保护支持:
(define-syntax translate
(lambda (stx)
(syntax-case stx ()
[(_ v) (identifier? #'v)
#'(symbol->string 'v)]
[(_ v) (number? (syntax-e #'v))
#'(number->string v)])))
(我使用方括号方便与 Eli 的回答进行比较,但是,这不是我通常的风格。;-))
但如果您使用的是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 返回的未指定值,而不是引发语法错误。