Macros 如何控制方案宏观展开的顺序?

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])) 将标识符代理设置为隐藏的代理。这是一个无用的示例,但它说明了用法 我发现自己处于这样

我正在使用Racket宏扩展
语法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…#默认值))
是的,当然你是对的。我猜诈骗者通常更喜欢
语法分析
,因为它有更具表现力的模式语言和更好的错误报告功能。