我正在尝试define-let
在球拍中编写一个宏,它“保存” a 的标题(let ((var value) ...) ...)
,即只是(var value) ...
部分,并允许稍后重新使用它。
下面的代码按预期工作:
#lang racket
;; define-let allows saving the header part of a let, and re-use it later
(define-syntax (define-let stx1)
(syntax-case stx1 ()
[(_ name [var value] ...)
#`(define-syntax (name stx2)
(syntax-case stx2 ()
[(_ . body)
#`(let ([#,(datum->syntax stx2 'var) value] ...)
. body)]))]))
;; Save the header (let ([x "works]) ...) in the macro foo
(define-let foo [x "works"])
;; Use the header, should have the same semantics as:
;; (let ([x "BAD"])
;; (let ([x "works])
;; (displayln x))
(let ([x "BAD"])
(foo (displayln x))) ;; Displays "works".
问题是宏破坏了卫生:如下例所示,y
在 a 中声明的define-let
由宏产生的变量 应该是一个新的、不受约束的符号,因为卫生,但它设法从宏中泄漏, 并且在(displayln y)
.
;; In the following macro, hygiene should make y unavailable
(define-syntax (hygiene-test stx)
(syntax-case stx ()
[(_ name val)
#'(define-let name [y val])]))
;; Therefore, the y in the above macro shouldn't bind the y in (displayln y).
(hygiene-test bar "wrong")
(let ((y "okay"))
(bar (displayln y))) ;; But it displays "wrong".
我如何编写define-let
宏,使其表现得像第一个示例中一样,但在标识符由宏生成时也保持卫生,"okay"
在第二个示例中给出?