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

时间:2016-02-09 18:02:08

标签: macros racket

我有一个扩展了racket语法的宏,并且在某些时候接受了一系列bog标准球拍表达式。这看起来像这样,相关的语法变量是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?可重用性是一个很大的好处,因为这种&#34;类型的身体&#34;可能存在于多个(类似的)宏中。

一些测试代码:

#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 个答案:

答案 0 :(得分:1)

现在重新提出原始问题,我知道(并且可以回答)我想问的问题:如何定义一个只能在某个特定环境中使用的宏(对我来说:在一个方法的主体中) racket class),我如何使用动态绑定变量。在上面的原始代码中:当使用表达式(tweet a)时,我不仅需要a的值,还需要some-formal-parameter的值,该值绑定在代码的上下文中tweet宏被扩展(不是它被定义的地方)。

Chris Jester-Young向我指出了语法参数,它确实似乎解决了动态绑定的问题,而且只能在某些情境中使用&#34;。 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)

关注的三个关键点如下:

  1. 由于tweet宏的定义,只要在syntax-parametrize语句的上下文之外使用它(它改变了tweet的定义),它就会抛出一个适当的错误
  2. 在我们类的公共方法tick的正文中,我们将tweet的定义更改为与(_ value)形式的模式匹配的宏(这是我们提供给的值tweet
  3. 推文宏可以扩展为两者都使用绑定值value some-formal-parameter的值,无论可能是什么。
  4. 我不知道这是否是处理这种情况的正确方法,但似乎很好。