首页 文章

定义可以访问周围变量的嵌套球拍宏

提问于
浏览
1

我有一个扩展球拍语法的宏,并在某些时候接受一系列沼泽标准球拍表达式 . 看起来像这样,相关的语法变量是 body

(syntax-parse stx
  [(_ some-id:id
      body:expr ...+)

这个宏使用生成的方法生成一个racket类,如下所示:

#'(<class stuff>
   (define/public (some-id some-formal-parameter)
     body ...)

正如我所说 body 是普通的球拍代码,除了一个可以在体内专门使用的表达式,例如:

(define-syntax-rule (tweet identifier value)
  (send this publish-tweet (quote identifier) value))

但这不允许我使用 some-formal-parameter ,因为它没有定义 . 是否有一些正确的方法可以定义可以在主体中专门使用的东西,并且仍然可以在扩展后绑定到上下文中的变量?也许通过splicing syntax class?可重用性是一个很大的好处,因为"type of body"可能存在于多个(相似的)宏中 .

一些测试代码:

#lang racket
(require (for-syntax syntax/parse))

(define-syntax (define-something stx)
  (syntax-parse stx
    [(_ some-id:id
        body:expr ...+)
     #'(define some-id
         (new
          (class object%
            (super-new)
            (define/public (displ arg)
              (displayln arg))
            (define/public (tick some-formal-parameter) 
              body ...))))]))

(define-syntax-rule (tweet value)
  (send this displ value))


(define-something derp
  (define a 'not-derp)
  (tweet a))

(send derp tick 'derp)

1 回答

  • 1

    现在重新提出原始问题,我知道(并且可以回答)我想问的问题:如何定义一个只能在特定上下文中使用的宏(对我来说:在一个球拍类的方法体内) ,以及如何使用动态绑定变量 . 在上面的原始代码中:当使用表达式 (tweet a) 时,我不仅需要 a 的值,而且还需要 some-formal-parameter 的值,该值在扩展推文宏的代码的上下文中绑定(而不是在其定义的位置) .

    Chris Jester-Young向我指出了语法参数,它确实似乎解决了动态绑定和"can only be used in certain contexts"的问题 . Eli Barzilay,Ryan Culpepper和Matthew Flatt的paper帮助我理解了语法参数 .

    关于我发布的原始示例代码,这是我提出的解决方案:

    #lang racket
    
    (require
      racket/stxparam
      (for-syntax syntax/parse))
    
    (define-syntax-parameter tweet
      (lambda (stx)
        (raise-syntax-error 'tweet "use of an actor keyword outside of the body of an actor" stx)))
    
    (define-syntax (define-something stx)
      (syntax-parse stx
        [(_ some-id:id
            body:expr ...+)
         #'(define some-id
             (new
              (class object%
                (super-new)
    
                (define/public (tick some-formal-parameter)
                  (syntax-parameterize
                   ([tweet
                     (syntax-rules ()
                       [(_ value)
                        (begin (displayln some-formal-parameter)
                               (displayln value))])])
                   body ...)
                  ))))]))
    
    (define-something derp
      (define a 'not-derp)
      (tweet a))
    
    (send derp tick 'derp)
    

    关注的三个关键点如下 .

    • 由于 tweet 宏的定义,只要在 syntax-parametrize 语句的上下文之外使用它(它改变了 tweet 的定义),它就会抛出适当的错误 .

    • 在我们类的公共方法 tick 的主体中,我们将 tweet 的定义更改为与 (_ value) 形式的模式匹配的宏(这是我们提供给 tweet 的值)

    • 推文宏可以扩展为两者都使用绑定值 valuesome-formal-parameter 的值,无论可能是什么 .

    我不知道这是否是处理这种情况的正确方法,但似乎很好 .

相关问题