2

我正在使用 Racket 宏扩展syntax-id-rules,它是其他一些方案实现在名称下提供的identifier-syntax。这些使您可以指定即使定义的标识符不在头部位置也会发生的宏扩展。例如:

(define hidden #f)
(define-syntax proxy
  (syntax-id-rules (set!)
    [(set! proxy v) (set! hidden v)]
    [proxy hidden]))

将标识符设置proxyhidden. 这是一个无用的示例,但它说明了用法。

我发现自己处于想要一个全局普通宏的情况,我们称之为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

但实际上最后一行返回'default,因为foo宏在它之前被扩展proxy

任何想法我可以如何实现这些方面的东西,但proxy标识符宏覆盖默认宏定义foo?我并没有专门致力于上述架构。

补充:这不适用于任何现实世界的使用,而是形式语义理论点演示的一部分。

4

2 回答 2

3

@soegaard 完美地解释了它。如果不修改宏扩展器,您将无法直接执行您想要的操作。

为了扩展@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
于 2015-08-14T17:55:16.817 回答
3

在我看来,您需要找到替代策略。如果您提供有关您想要使用它的情况的更多详细信息,也许我们可以找到解决方案。

无论如何,这就是为什么您的策略不起作用的原因。当你写

(define-syntax proxy ...)

您将语法转换器与标识符相关联proxy(proxy ...)扩展器在看到、(set! proxy ...)或时调用该转换器proxy

为了控制(foo proxy arg ...)扩展的内容,您需要在与foo.

现在根据情况可能会有一些技巧可以玩。

例如,可以想象将您的程序包装为一种新形式,该形式会重写,然后让语法转换器(foo proxy arg ...)处理其余部分。(proxy 'was-a-foo-originally arg ...)proxy

简单的解决方案是将 的处理(foo proxy arg ...)移到变压器中foo,但您特别要求foo不更改的解决方案。

于 2015-08-14T16:26:57.157 回答