一个新的语法对象可以由syntax/loc和syntax(也写成 #' )构造 .
#'
我什么时候应该使用 syntax/loc ?
syntax/loc
在不构造新语法对象时使用 #' (即 syntax ),就像刚引用与 syntax-case 或 with-syntax 绑定的模式变量一样 .
syntax
syntax-case
with-syntax
使用 #' 作为临时语法对象,如 (syntax->list #'(id ...)) .
(syntax->list #'(id ...))
将 #' 用于表示您知道其中没有语法错误的表单的语法对象,或者其中的语法错误是宏实现的错误,而不是宏的使用 .
当您构造可能由于宏的错误使用而可能包含语法错误的表达式时,请使用 syntax/loc .
让我们考虑一个具体的例子:
表单 display-let 应该与普通 let 完全相同,只是它在评估正文之前显示绑定的值 .
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
(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 .
(display-let-2 ())
display-let-2
1 回答
在不构造新语法对象时使用
#'
(即syntax
),就像刚引用与syntax-case
或with-syntax
绑定的模式变量一样 .使用
#'
作为临时语法对象,如(syntax->list #'(id ...))
.将
#'
用于表示您知道其中没有语法错误的表单的语法对象,或者其中的语法错误是宏实现的错误,而不是宏的使用 .当您构造可能由于宏的错误使用而可能包含语法错误的表达式时,请使用
syntax/loc
.让我们考虑一个具体的例子:
表单
display-let
应该与普通let
完全相同,只是它在评估正文之前显示绑定的值 .这是第一个实现:
以下是正确使用宏的示例:
现在让我们看看当宏使用不正确时会发生什么:
这种用法不正确,因为使用
let
必须始终具有非空体 . 除了打印错误消息外,DrRacket还将此代码设置为红色:虽然由宏构造的
lambda
表达式是不正确的,但(lambda ())
不合法,但这不是由于宏中的错误,而是由于宏的使用不正确 .使用
syntax/loc
重定向构造的lambda
表达式的blame并使用syntax/loc
的第一个参数作为红色的位置 .这次在repl中输入的
(display-let-2 ())
是红色的,并且错误消息提到display-let-2
而不是lambda
.