Macros 定义可访问周围变量的嵌套racket宏
我有一个宏,它扩展了racket语法,并在某个点上接受一系列bog标准racket表达式。这看起来像这样,相关的语法变量是Macros 定义可访问周围变量的嵌套racket宏,macros,racket,Macros,Racket,我有一个宏,它扩展了racket语法,并在某个点上接受一系列bog标准racket表达式。这看起来像这样,相关的语法变量是body: (syntax-parse stx [(_ some-id:id body:expr ...+) 此宏使用生成的方法生成racket类,如下所示: #'(<class stuff> (define/public (some-id some-formal-parameter) body ...) 但这不允许我使用一些形
body
:
(syntax-parse stx
[(_ some-id:id
body:expr ...+)
此宏使用生成的方法生成racket类,如下所示:
#'(<class stuff>
(define/public (some-id some-formal-parameter)
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)
现在我知道(并且可以回答)我想问的问题:如何定义只能在特定上下文中使用的宏(对我来说:在racket类的方法体中),以及如何使用动态绑定变量。在上面的原始代码中:当使用表达式
(tweet a)
时,我不仅需要a
的值,还需要一些形式参数的值,这些参数在tweet宏展开的代码上下文中绑定(未定义)
ChrisJester Young善意地向我指出语法参数,它似乎确实解决了动态绑定问题,并且“只能在某些上下文中使用”。Eli Barzilay、Ryan Culpeper和Matthew Flatt的一篇文章帮助我理解了语法参数
关于我发布的原始示例代码,这是我提出的解决方案:
#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
宏的定义,每当它在语法参数化
语句的上下文之外使用时(该语句更改tweet
的定义),它都会抛出相应的错误
在类的公共方法的主体中,我们将tweet
的定义更改为一个宏,该宏与(\uvalue)
形式的模式相匹配(这是我们提供给tweet
的值)
tweet宏可以扩展为既使用绑定值值
,又使用某个形式参数
的值,不管是什么
我不知道这是否是处理这种情况的正确方法,但它似乎很好。我不完全理解您的问题,但据我所知,语法参数似乎是实现它的方法。如果你能把你之前和之后的期望都公布出来,我可以试着编一些东西。:-)是的,很抱歉。“用宏思考”很难理解。有那么多要学,那么多要知道,那么多你必须知道。我正在读一篇关于语法参数的文章,看起来这可以解决这个问题。我不知道它是否能很好地解决这个问题,但我会尝试一些东西并报告:)很好的解决方案!但是,您可能注意到,您不能在define something
的主体中引用一些形式参数,因为它们在不同的词汇范围内。也许这没关系,但如果您确实希望能够做到这一点,那么解决方案将是某些形式参数的另一个语法参数。这是因为现在在定义某物
的主体中有两件事情是可用的。对于我遇到的特定问题,定义某物
的主体不能使用一些形式参数
,这确实不是一个问题。事实上,这是一个身体不应该意识到的参数,因此它不在词汇范围内的事实实际上是很好的。谢谢你的评论。这是对我的解决方案的一个很好的验证,当其他人偶然发现这个问题时,他们可能会发现这个见解很有用:)
#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)