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

soe*_*ard 6 racket

可以通过syntax/loc和构造新的语法对象syntax(也可以用编写#')。

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

soe*_*ard 6

当您不构造新的语法对象时(例如,您仅引用由或绑定的模式变量时),请使用#'(ie syntax)。syntax-casewith-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 ...)]))
Run Code Online (Sandbox Code Playgroud)

这是正确使用宏的示例:

> (display-let-1 ([x 1] [y 2]) (+ x y))
x is bound to 1
y is bound to 2
3
Run Code Online (Sandbox Code Playgroud)

现在让我们看看错误使用宏时会发生什么:

> (display-let-1 ())
lambda: bad syntax in: (lambda ())
Run Code Online (Sandbox Code Playgroud)

这种用法是错误的,因为使用时let必须始终具有非空主体。除了打印错误消息外,DrRacket将此代码着色为红色:

(lambda (id ...) 
  (displayln (format "~a is bound to ~a" 'id id)) ...
  body ...)
Run Code Online (Sandbox Code Playgroud)

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

要重定向非结构化lambda表达式,请syntax/loc使用,然后使用syntax/locas 的第一个参数将位置涂成红色。

(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 ())
Run Code Online (Sandbox Code Playgroud)

这次(display-let-2 ()),在repl中输入的内容周围显示为红色,并提到了错误消息,display-let-2而不是lambda