我正在研究一个guile方案中的语言翻译器,并且需要处理基本情况,你试图转换一个单词。
(define var 5)
(translate var)
这应该返回字符串var
而不是数字5
如何使用R5RS Scheme宏(define-syntax
样式)?
编辑:
我正在从Scheme转换为Coffeescript。
答案 0 :(得分:5)
(define-syntax translate
(syntax-rules ()
[(_ v) 'v]))
如果你想要一个字符串:
(define-syntax translate
(syntax-rules ()
[(_ v) (symbol->string 'v)]))
希望Guile的编译器足够聪明,可以折叠生成的表达式,使其基本上成为一个常量字符串。
答案 1 :(得分:4)
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
返回的未指定值而不是抛出语法错误
答案 2 :(得分:0)
其他答案已经足够有用,但我想我只是指出可以用一种非常有用的方式概括这种技术:用于打印表达式的宏及其调试结果:
(define-syntax log-expr
(syntax-rules ()
((_ expr)
(let ((result expr))
(write (quote expr))
(display " evaluates to ")
(write result)
(newline)
result))))