Macros 如何控制方案宏观展开的顺序?
我正在使用Racket宏扩展Macros 如何控制方案宏观展开的顺序?,macros,scheme,racket,define-syntax,syntax-rules,Macros,Scheme,Racket,Define Syntax,Syntax Rules,我正在使用Racket宏扩展语法id规则,其他一些方案实现在标识符语法的名称下提供了该扩展。这些允许您指定宏扩展,即使定义的标识符不在头位置,宏扩展也会发生。例如: (define hidden #f) (define-syntax proxy (syntax-id-rules (set!) [(set! proxy v) (set! hidden v)] [proxy hidden])) 将标识符代理设置为隐藏的代理。这是一个无用的示例,但它说明了用法 我发现自己处于这样
语法id规则
,其他一些方案实现在标识符语法
的名称下提供了该扩展。这些允许您指定宏扩展,即使定义的标识符不在头位置,宏扩展也会发生。例如:
(define hidden #f)
(define-syntax proxy
(syntax-id-rules (set!)
[(set! proxy v) (set! hidden v)]
[proxy hidden]))
将标识符代理设置为隐藏的代理。这是一个无用的示例,但它说明了用法
我发现自己处于这样一种情况:我需要一个全局普通宏,我们称之为foo
,在某些情况下,我希望在使用标识符宏(如proxy
)时覆盖它。也就是说,我希望能够做这样的事情:
(define-syntax foo
(syntax-rules ()
[(foo arg ...) 'default]))
(define hidden #f)
(define-syntax proxy
(syntax-id-rules (foo set!)
[(foo proxy arg ...) 'special]
[(set! proxy v) (set! hidden v)]
[proxy hidden]))
(foo proxy) ; should return 'special
但事实上,最后一行返回的是默认值
,因为foo
宏在代理
宏之前展开
有什么想法可以让我沿着这些思路实现一些东西,但是用代理
标识符宏覆盖foo
的默认宏定义?我并不特别致力于上述体系结构
补充:这不是用于任何真实世界的用法,而是形式语义学理论观点的一部分演示。在我看来,您需要找到一种替代策略。如果你能提供更多关于你想使用它的情况的细节,也许我们可以找到一个解决方案
无论如何,这就是为什么你的策略不起作用。当你写作时
(define-syntax proxy ...)
将语法转换器与标识符代理关联。当扩展器看到(proxy…
、(set!proxy…
)或proxy
时,它将调用该转换器
为了控制(foo proxy arg…
扩展到的内容,您需要在与foo
关联的语法转换器中指定它
现在,根据情况,可能会有一些小把戏
例如,可以想象将程序包装成一种新形式,将(foo proxy arg…
重写为(proxy'was-a-foo-original arg…
),然后让proxy的语法转换器处理其余部分
简单的解决方案是将(foo proxy arg…
的处理移到foo
的转换器中,但是您特别要求一个foo
没有更改的解决方案。@soegaard对此进行了完美的解释。如果不修改宏扩展器,则无法直接执行所需操作
为了扩展@soegaard的答案,这里有一种方法可以模拟您的要求。它基本上执行“双重分派”宏扩展。正如苏加德所指出的,根据你的目标,可能有一种更惯用的方式来实现你想要的
#lang racket
(require (for-syntax syntax/parse))
(begin-for-syntax
(define (special-condition? id)
(and (identifier? id)
(regexp-match #rx"^p" ; starts with "p"
(symbol->string (syntax->datum id))))))
(define-syntax foo
(syntax-parser
[(_ special-case arg ...)
#:when (special-condition? #'special-case)
#'(special-case 'hidden-special-case-tag arg ...)]
; else
[(_ arg ...) #''default]))
(define hidden #f)
(define-syntax proxy
(syntax-id-rules (quote set!)
[(proxy (quote hidden-special-case-tag) arg ...) 'special]
[(set! proxy v) (set! hidden v)]
[(proxy arg ...) 'other]
[proxy hidden]))
(foo non-proxy) ; => 'default
(foo proxy) ; => 'special
(proxy) ; => 'other
proxy ; => #f
(set! proxy #t)
proxy ; => #t
添加了关于我的“用例”的问题注释。我不能轻易地将proxy
的处理放入foo
,因为可能有许多proxy
在不同级别上定义,但foo
的默认实现应该只有一个一应俱全,其中proxy
所需的参数与之类似;感谢您展示了实现这一点的框架代码。就我的目的而言,这可能已经足够好了,而且听起来我不会做得更好。本质上,我需要的是类似语法id规则
或生成集-transformer
,但我们可以提供额外的表单,如foo
,它们得到与设置相同的特殊处理代码>获取。语法分析器
在这里似乎根本不需要;使用Racket的语法case
上的可选保护表达式可以达到同样的效果:(定义语法(foo stx)(语法case stx()[(u)特殊情况arg…(特殊条件?#'特殊情况)#'(特殊情况'隐藏特殊情况标记arg…][(u arg…#默认值))
是的,当然你是对的。我猜诈骗者通常更喜欢语法分析
,因为它有更具表现力的模式语言和更好的错误报告功能。