Ina*_*thi 6 macros scheme define-syntax racket
使用define-syntax或define-syntax-rule在Racket中定义捕获宏的最简单方法是什么?
作为一个具体的例子,这里aif是CL风格的宏系统中的微不足道的.
(defmacro aif (test if-true &optional if-false)
`(let ((it ,test))
(if it ,if-true ,if-false)))
Run Code Online (Sandbox Code Playgroud)
这个想法是,it将被绑定到的结果test在if-true和if-false条款.天真的音译(减去可选的替代方案)是
(define-syntax-rule (aif test if-true if-false)
(let ((it test))
(if it if-true if-false)))
Run Code Online (Sandbox Code Playgroud)
在没有投诉的情况下进行评估,但如果您尝试it在子句中使用则会出错:
> (aif "Something" (displayln it) (displayln "Nope")))
reference to undefined identifier: it
Run Code Online (Sandbox Code Playgroud)
该anaphora蛋实现aif为
(define-syntax aif
(ir-macro-transformer
(lambda (form inject compare?)
(let ((it (inject 'it)))
(let ((test (cadr form))
(consequent (caddr form))
(alternative (cdddr form)))
(if (null? alternative)
`(let ((,it ,test))
(if ,it ,consequent))
`(let ((,it ,test))
(if ,it ,consequent ,(car alternative)))))))))
Run Code Online (Sandbox Code Playgroud)
但是,Racket似乎没有ir-macro-transformer定义或记录.
Gre*_*ott 10
Racket宏旨在避免默认捕获.当你使用define-syntax-rule它时会尊重词汇范围.
当你想故意"打破卫生"时,传统上你需要使用syntax-case和(小心)使用datum->syntax.
但在Racket中,执行"照应"宏的最简单,最安全的方法是使用语法参数和简单define-syntax-rule.
例如:
(require racket/stxparam)
(define-syntax-parameter it
(lambda (stx)
(raise-syntax-error (syntax-e stx) "can only be used inside aif")))
(define-syntax-rule (aif condition true-expr false-expr)
(let ([tmp condition])
(if tmp
(syntax-parameterize ([it (make-rename-transformer #'tmp)])
true-expr)
false-expr)))
Run Code Online (Sandbox Code Playgroud)
我在这里写了关于语法参数的文章,你也应该阅读Eli Barzilay的Dirty Looking Hygiene博客文章和用语法参数保持清洁(PDF).