我什么时候应该使用syntax / loc而不是#'(又名语法)?

时间:2012-06-02 13:27:42

标签: racket

syntax/locsyntax(也写成#')可以构建新的语法对象。

我应该何时使用syntax/loc

1 个答案:

答案 0 :(得分:6)

在您不构建新语法对象时使用#'(即syntax),就像刚引用与syntax-casewith-syntax绑定的模式变量一样

#'用于临时语法对象,如(syntax->list #'(id ...))

#'用于表示您知道其中没有语法错误的表单的语法对象,或者其中的语法错误是宏实现的错误,而不是宏的使用。

在构造可能由于宏的错误使用而可能包含语法错误的表达式时使用syntax/loc

让我们考虑一个具体的例子:

表单display-let应该与普通let完全相同,不同之处在于它在评估正文之前显示绑定的值。

这是第一个实现:

(define-syntax (display-let-1 stx)
  (syntax-case stx ()
    [(_ ([id expr] ...) body ...)
     #'((lambda (id ...) 
          (displayln (format "~a is bound to ~a" 'id id)) ...
          body ...)
        expr ...)]))

以下是正确使用宏的示例:

> (display-let-1 ([x 1] [y 2]) (+ x y))
x is bound to 1
y is bound to 2
3

现在让我们看看当宏使用不正确时会发生什么:

> (display-let-1 ())
lambda: bad syntax in: (lambda ())

此用法不正确,因为let的使用必须始终具有非空身体。除了打印错误消息外,DrRacket还将此代码设置为红色:

(lambda (id ...) 
  (displayln (format "~a is bound to ~a" 'id id)) ...
  body ...)

虽然由宏构造的lambda表达式不正确,但(lambda ())不合法,但这不是由于宏中的错误,而是由于错误地使用了宏。

使用lambda重定向构造的syntax/loc表达式的blame,并使用syntax/loc的第一个参数作为红色。

(define-syntax (display-let-2 stx)
  (syntax-case stx ()
    [(display-let ([id expr] ...) body ...)
     #`(#,(syntax/loc stx (lambda (id ...) body ...)) expr ...)]))

> (display-let-2 ())
display-let-2: bad syntax in: (display-let-2 ())

此次在repl中输入的(display-let-2 ())为红色,错误消息提到display-let-2而不是lambda