首页 文章

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

提问于
浏览
4

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

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

1 回答

  • 4

    在不构造新语法对象时使用 #' (即 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 ()) 不合法,但这不是由于宏中的错误,而是由于宏的使用不正确 .

    使用 syntax/loc 重定向构造的 lambda 表达式的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 .

相关问题