Racket - 将特殊变量注入宏代码

Sco*_*ach 3 macros racket

我想将特殊变量注入到宏中以进行编译时绑定。

因此,例如以下形式:

(define-route (my/route)
  (some-proc @@request)
  (some-other-proc @@request))
Run Code Online (Sandbox Code Playgroud)

应扩展到:

(some-code)
...
(lambda (request)
  ...
  (some-proc request)
  (some-other-proc request))
Run Code Online (Sandbox Code Playgroud)

其中 request 在调用者指定的所有位置绑定到生成代码中的请求。

我不知道如何最好地去做。这是球拍宏提供的更常见的模式,还是我必须手动执行?

如果是这样,我是否应该递归循环主体模式,查找与 '@@request 匹配的任何符号,然后替换它们?我注意到语法->列表不是以这种方式递归的,即

(syntax->list #'(printf "first: ~a\" (get-var (other-proc)))
Run Code Online (Sandbox Code Playgroud)

是 3 个语法对象而不是 4 个,第三个语法对象是 2 个以上。所以我认为我需要在这里手动重复,但也许有更好的方法来做到这一点?

感谢您的帮助。

dyo*_*yoo 5

也许使用syntax-parameterize(及其变体,splicing-syntax-parameterize)应该可以解决问题?当您想要拥有类似关键字的内容并且宏需要根据上下文重新连接关键字的含义时,它是一个标准工具。

它看起来是这样的:

#lang racket/base

(require racket/stxparam
         racket/splicing
         (for-syntax syntax/parse racket/base))

(define-syntax-parameter @@request
  (lambda (stx)
    (raise-syntax-error #f "Use outside of a define-route" stx)))

(define-syntax (define-route stx)
  (syntax-parse stx 
    [(_ (name:id) body:expr ...)
     (syntax/loc stx
       (begin
         (printf "blah blah blah\n")

         (define name
           (lambda (request)
             (splicing-syntax-parameterize ([@@request
                                             (make-rename-transformer #'request)])
               body ...)))))]))

;; example
(define (f r)
  (printf "f sees: ~s\n" r))

(define-route (my/route)
  (f @@request))

(my/route 42)
Run Code Online (Sandbox Code Playgroud)

语法参数化重新连接了@@requesta 的词法上下文中的使用define-route,以便它引用回由request绑定的 that lambda。如果在 a 的上下文之外使用define-route,它将尝试引发合理的错误消息。

(您可以按照最初计划的方式执行此操作,递归地遍历语法对象的结构并挑选出元素@@request。这只是比您需要做的更多工作,除非要求确实不寻常。)