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]))

は、識別子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

しかし実際には、マクロが 1 つ前に展開される'defaultため、最後の行は を返します。fooproxy

これらの行に沿って何かを達成する方法はありますが、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 に答える