是否可以只打印传递给Scheme宏的字符串?

时间:2012-03-02 01:40:55

标签: macros scheme guile r5rs

我正在研究一个guile方案中的语言翻译器,并且需要处理基本情况,你试图转换一个单词。

(define var 5)
(translate var)

这应该返回字符串var而不是数字5 如何使用R5RS Scheme宏(define-syntax样式)?

执行此操作

编辑:
我正在从Scheme转换为Coffeescript。

3 个答案:

答案 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))))