6

一个新的语法对象可以由syntax/locsyntax(也写成#')来构造。

我应该什么时候使用syntax/loc

4

1 回答 1

6

当你不构造一个新的语法对象时使用#'(ie syntax),就像你只是引用一个用syntax-caseor绑定的模式变量一样with-syntax

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

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

当您构造由于宏使用syntax/loc不正确而可能包含语法错误的表达式时使用。

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

表单display-let应该像 normal 一样工作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并使用syntax/locas place 的第一个参数来着色为红色。

(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 ())

这一次,(display-let-2 ())在 repl 中输入的内容是红色的,并且提到的错误消息display-let-2不是lambda.

于 2012-06-02T13:27:42.703 回答